From 717ec2048b6a6b1ebd64169f2d655c8ce96e36ad Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Wed, 18 Mar 2026 20:04:25 -0600 Subject: [PATCH] Backwards motions and deletions --- src/cg/06-textEditor.cg | 48 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/cg/06-textEditor.cg b/src/cg/06-textEditor.cg index 95efb93..0220583 100644 --- a/src/cg/06-textEditor.cg +++ b/src/cg/06-textEditor.cg @@ -53,10 +53,46 @@ textEditor = name \ pos = skipWhile (ch \ charKind ch == kind) lines row col; skipWhile (ch \ ch == " ") lines pos.row pos.col; + skipBack = pred line row col lines \ + col < 0 + | True \ (row > 0 + | True \ ( + prevLine = nth (row - 1) lines ~ unwrapOr ""; + skipBack pred prevLine (row - 1) (len prevLine - 1) lines) + | False \ { row = 0, col = 0 - 1 }) + | False \ (pred (nth col line ~ unwrapOr "") + | True \ skipBack pred line row (col - 1) lines + | False \ { row = row, col = col }); + + prevWordStart = lines row col \ + # step back 1 + c = col - 1; + r = row; + r2 = c < 0 + | True \ r - 1 + | False \ r; + c2 = c < 0 + | True \ (max 0 (len (nth (r - 1) lines ~ unwrapOr "") - 1)) + | False \ c; + # no prev line + r2 < 0 + | True \ { row = 0, col = 0 } + | False \ ( + line = nth r2 lines ~ unwrapOr ""; + # skip spaces backward + pos = skipBack (ch \ ch == " ") line r2 c2 lines; + # skip same kind backward + kind = charKind (nth pos.col (nth pos.row lines ~ unwrapOr "") ~ unwrapOr " "); + pos2 = skipBack (ch \ charKind ch == kind) (nth pos.row lines ~ unwrapOr "") pos.row (pos.col - 1) lines; + # go 1 ahead + { row = pos2.row, col = pos2.col + 1 } + ); + resolveMotion = motion state \ from = { row = state.cursorRow, col = state.cursorCol }; to = motion | Word \ nextWordStart state.lines from.row from.col + | BackWord \ prevWordStart state.lines from.row from.col | WholeLine \ from; { from = from, to = to }; @@ -66,11 +102,10 @@ textEditor = name \ deleteRange = state from to \ line = nth from.row state.lines ~ unwrapOr ""; - toCol = to.row > from.row - | True \ len line - | False \ to.col; - newLine = (slice line 0 from.col) & (slice line toCol (len line)); - state.{ lines = updateAt from.row (_ \ newLine) state.lines, cursorCol = from.col }; + startCol = min from.col to.col; + endCol = max from.col to.col; + newLine = (slice line 0 startCol) & (slice line endCol (len line)); + state.{ lines = updateAt from.row (_ \ newLine) state.lines, cursorCol = startCol }; applyOperator = operator motion state \ target = resolveMotion motion state; @@ -277,6 +312,9 @@ textEditor = name \ | Key { key = "d" } \ (state.pending | Some Delete \ applyOperator Delete WholeLine state | _ \ { state = state.{ pending = Some Delete }, emit = [] }) + | Key { key = "b" } \ (state.pending + | None \ withScroll { state = moveCursor (resolveMotion BackWord state) state, emit = [] } + | Some Delete \ withScroll (applyOperator Delete BackWord state)) | Key { key = "w" } \ (state.pending | None \ withScroll { state = moveCursor (resolveMotion Word state) state, emit = [] } | Some Delete \ withScroll (applyOperator Delete Word state))