diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 84fdafe..b2be255 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -209,14 +209,47 @@ struct val toPrevChr = ToPrevChr.foldPrev + structure NextPairChr = + MakeIfCharFolderNext + (struct + type env = unit + + fun isPairChr chr = + chr = #"(" orelse chr = #")" orelse + chr = #"[" orelse chr = #"]" orelse + chr = #"{" orelse chr = #"}" orelse + chr = #"<" orelse chr = #">" + + fun loop (strPos, str, absIdx, stl) = + if strPos = String.size str then + case stl of + str :: stl => loop (0, str, absIdx, stl) + | [] => ~1 + else + let + val chr = String.sub (str, strPos) + in + if isPairChr chr then + absIdx + else + loop (strPos + 1, str, absIdx + 1, stl) + end + + fun fStart (strPos, str, _, absIdx, stl, _, _) = + loop (strPos, str, absIdx, stl) + end) + + fun nextPairChr (lineGap, cursorIdx) = + NextPairChr.foldNext (lineGap, cursorIdx, ()) + fun helpMatchPairNext - (strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) = + (strPos, str, absIdx, stl, openChr, openNum, closeChr, closeNum) = if strPos = String.size str then case stl of hd :: tl => helpMatchPairNext - (0, hd, absIdx, tl, origIdx, openChr, openNum, closeChr, closeNum) - | [] => origIdx + (0, hd, absIdx, tl, openChr, openNum, closeChr, closeNum) + | [] => ~1 else let val chr = String.sub (str, strPos) @@ -231,7 +264,6 @@ struct , str , absIdx + 1 , stl - , origIdx , openChr , openNum , closeChr @@ -240,7 +272,7 @@ struct end fun helpMatchPairPrev - (strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) = + (strPos, str, absIdx, stl, openChr, openNum, closeChr, closeNum) = if strPos < 0 then case stl of hd :: tl => @@ -249,13 +281,12 @@ struct , hd , absIdx , tl - , origIdx , openChr , openNum , closeChr , closeNum ) - | [] => origIdx + | [] => ~1 else let val chr = String.sub (str, strPos) @@ -270,7 +301,6 @@ struct , str , absIdx - 1 , stl - , origIdx , openChr , openNum , closeChr @@ -286,7 +316,6 @@ struct , shd , cursorIdx + 1 , rightStrings - , cursorIdx , #"(" , 1 , #")" @@ -298,7 +327,6 @@ struct , shd , cursorIdx - 1 , leftStrings - , cursorIdx , #"(" , 0 , #")" @@ -310,7 +338,6 @@ struct , shd , cursorIdx + 1 , rightStrings - , cursorIdx , #"[" , 1 , #"]" @@ -322,7 +349,6 @@ struct , shd , cursorIdx - 1 , leftStrings - , cursorIdx , #"[" , 0 , #"]" @@ -334,7 +360,6 @@ struct , shd , cursorIdx + 1 , rightStrings - , cursorIdx , #"{" , 1 , #"}" @@ -346,7 +371,6 @@ struct , shd , cursorIdx - 1 , leftStrings - , cursorIdx , #"{" , 0 , #"}" @@ -358,7 +382,6 @@ struct , shd , cursorIdx + 1 , rightStrings - , cursorIdx , #"<" , 1 , #">" @@ -370,13 +393,12 @@ struct , shd , cursorIdx - 1 , leftStrings - , cursorIdx , #"<" , 0 , #">" , 1 ) - | _ => cursorIdx + | _ => ~1 fun matchPair (lineGap: LineGap.t, cursorIdx) = let diff --git a/fcore/normal-mode/normal-move.sml b/fcore/normal-mode/normal-move.sml index b6d01de..4610c75 100644 --- a/fcore/normal-mode/normal-move.sml +++ b/fcore/normal-mode/normal-move.sml @@ -398,46 +398,57 @@ struct (* move LineGap and buffer to start of line *) val buffer = LineGap.goToIdx (cursorIdx, buffer) - val cursorIdx = Cursor.matchPair (buffer, cursorIdx) + val cursorIdx = Cursor.nextPairChr (buffer, cursorIdx) in - let - val buffer = LineGap.goToIdx (cursorIdx, buffer) - val visualScrollColumn = - TextScroll.getScrollColumn - (buffer, cursorIdx, windowWidth, prevScrollColumn) + if cursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val cursorIdx = Cursor.matchPair (buffer, cursorIdx) + in + if cursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val visualScrollColumn = + TextScroll.getScrollColumn + (buffer, cursorIdx, windowWidth, prevScrollColumn) - val cursorLine = LineGap.idxToLineNumber (cursorIdx, buffer) - val startLine = - TextScroll.getStartLine - (prevLineNumber, cursorLine, windowHeight, #lineLength buffer) + val cursorLine = LineGap.idxToLineNumber (cursorIdx, buffer) + val startLine = + TextScroll.getStartLine + (prevLineNumber, cursorLine, windowHeight, #lineLength buffer) - val buffer = LineGap.goToLine (startLine, buffer) + val buffer = LineGap.goToLine (startLine, buffer) - val drawMsg = NormalModeTextBuilder.build - ( startLine - , cursorIdx - , buffer - , windowWidth - , windowHeight - , searchList - , visualScrollColumn - ) - val drawMsg = Vector.concat drawMsg - val drawMsg = DrawMsg.DRAW_TEXT drawMsg - val drawMsg = [MailboxType.DRAW drawMsg] - in - NormalModeWith.bufferAndCursorIdx - ( app - , buffer - , cursorIdx - , NORMAL_MODE "" - , startLine - , searchList - , drawMsg - , bufferModifyTime - , visualScrollColumn - ) - end + val drawMsg = NormalModeTextBuilder.build + ( startLine + , cursorIdx + , buffer + , windowWidth + , windowHeight + , searchList + , visualScrollColumn + ) + val drawMsg = Vector.concat drawMsg + val drawMsg = DrawMsg.DRAW_TEXT drawMsg + val drawMsg = [MailboxType.DRAW drawMsg] + in + NormalModeWith.bufferAndCursorIdx + ( app + , buffer + , cursorIdx + , NORMAL_MODE "" + , startLine + , searchList + , drawMsg + , bufferModifyTime + , visualScrollColumn + ) + end + end end fun firstNonSpaceChr (app: app_type) = diff --git a/temp.txt b/temp.txt index 0056b4a..082d5e0 100644 --- a/temp.txt +++ b/temp.txt @@ -1,3 +1 @@ -hello -world -again +he()o world diff --git a/test/normal-move.sml b/test/normal-move.sml index 7dfdf23..1d203b7 100644 --- a/test/normal-move.sml +++ b/test/normal-move.sml @@ -1752,21 +1752,39 @@ struct (* assert *) Expect.isTrue (getChr app = #"<") end) - (* testing that % on a non-pair character is a no-op *) - , test "does not move when cursor is on a non-pair-character" (fn _ => - let - (* arrange *) - val app = TestUtils.init "hello, world\n" - val app = AppWith.idx (app, 5) - val oldIdx = #cursorIdx app + , test + "does not move when cursor is on a non-pair-character, \ + \and there is no pair-character where the cursor is at or after the cursor" + (fn _ => + let + (* arrange *) + val app = TestUtils.init "he()o, world\n" + val app = AppWith.idx (app, 5) + val oldIdx = #cursorIdx app - (* act *) - val app = TestUtils.update (app, CHAR_EVENT #"%") - val newIdx = #cursorIdx app - in - (* assert *) - Expect.isTrue (newIdx = oldIdx) - end) + (* act *) + val app = TestUtils.update (app, CHAR_EVENT #"%") + val newIdx = #cursorIdx app + in + (* assert *) + Expect.isTrue (newIdx = oldIdx) + end) + , test + "moves cursor when the cursor is not on a \ + \pair-character, but there is a pair-character \ + \after the cursor" + (fn _ => + let + (* arrange *) + val app = TestUtils.init "he()o world\n" + val app = AppWith.idx (app, 0) + + (* act *) + val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"%") + in + (* assert *) + Expect.isTrue (cursorIdx = 3) + end) ] (* movements which use multiple chars *) diff --git a/todo.md b/todo.md index ea8f526..09eb874 100644 --- a/todo.md +++ b/todo.md @@ -1,8 +1,8 @@ # To-do list - Add tests for: -- Reimplement `%` motion and `d%` motion. - - They should both search for the next character in any pair, the same way in Vim +- Reimplement `d%` motion. + - It should both search for the next character in any pair, the same way in Vim - Add tests for reimplemented movements and motions - Reimplement `di` and `da` - They should search for the next char in the specific pair, the same way in Vim