From 7130fe7dda0c7137a40dbf31b3c40a7f0bd36346 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Fri, 12 Dec 2025 20:08:53 +0000 Subject: [PATCH] add tests for 'diW' motion, and fix a bug in the implementation (contiguous spaces were not deleted properly) --- fcore/cursor.sml | 50 ++++++++++++++++++++++++ fcore/normal-mode/make-normal-delete.sml | 40 ++++++++----------- todo.md | 3 +- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 2376225..ce20cc4 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -569,6 +569,56 @@ struct fun lastContiguousPunct (lineGap, cursorIdx) = LastContiguousPunct.foldNext (lineGap, cursorIdx, ()) + structure FirstContiguousNonSpace = + MakeIfCharFolderPrev + (struct + type env = unit + + fun loop (strPos, shd, absIdx, stl) = + if strPos < 0 then + case stl of + shd :: stl => loop (String.size shd - 1, shd, absIdx, stl) + | [] => 0 + else + let + val chr = String.sub (shd, strPos) + in + if Char.isSpace chr then absIdx + 1 + else loop (strPos - 1, shd, absIdx - 1, stl) + end + + fun fStart (strPos, shd, _, absIdx, stl, _, _) = + loop (strPos, shd, absIdx, stl) + end) + + fun firstContiguousNonSpace (lineGap, cursorIdx) = + FirstContiguousNonSpace.foldPrev (lineGap, cursorIdx, ()) + + structure LastContiguousNonSpace = + MakeIfCharFolderNext + (struct + type env = unit + + fun loop (strPos, shd, absIdx, stl) = + if strPos = String.size shd then + case stl of + shd :: stl => loop (0, shd, absIdx, stl) + | [] => Int.max (0, absIdx - 1) + else + let + val chr = String.sub (shd, strPos) + in + if Char.isSpace chr then absIdx - 1 + else loop (strPos + 1, shd, absIdx + 1, stl) + end + + fun fStart (strPos, shd, _, absIdx, stl, _, _) = + loop (strPos, shd, absIdx, stl) + end) + + fun lastContiguousNonSpace (lineGap, cursorIdx) = + LastContiguousNonSpace.foldNext (lineGap, cursorIdx, ()) + (* Prerequisite: lineGap is moved to cursorIdx *) fun isCursorAtStartOfLine (lineGap: LineGap.t, cursorIdx) = let diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 145954d..2b8cfc0 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -25,10 +25,7 @@ struct val buffer = LineGap.goToIdx (low, buffer) val low = - if Cursor.isOnNewlineAfterChr (buffer, low) then - low - 1 - else - low + if Cursor.isOnNewlineAfterChr (buffer, low) then low - 1 else low in finishAfterDeletingBuffer (app, low, buffer, time, initialMsg) end @@ -915,11 +912,6 @@ struct helpDeleteToMatch (app, newCursorIdx, cursorIdx, time) end - (* check if we are trying to delete from an empty buffer - * or a buffer which consists of only one character which is \n *) - fun canDeleteInsideOrAround (buffer, low, length) = - not (length = 1 andalso LineGap.substring (low, 1, buffer) = "\n") - fun deleteInsideWord (app: app_type, time) = let val {buffer, cursorIdx, dfa, ...} = app @@ -959,26 +951,26 @@ struct let val {buffer, cursorIdx, dfa, ...} = app val buffer = LineGap.goToIdx (cursorIdx, buffer) - - val low = Cursor.prevWORDStrict (buffer, cursorIdx, 1) - val high = Cursor.endOfWORDStrict (buffer, cursorIdx, 1) + 1 - - val buffer = LineGap.goToIdx (high, buffer) - val length = high - low + val chr = LineGap.sub (cursorIdx, buffer) in - if canDeleteInsideOrAround (buffer, low, length) then + if chr = #"\n" then + NormalFinish.clearMode app + else if Char.isSpace chr then let - val initialMsg = Fn.initMsgs (low, length, buffer) - val buffer = LineGap.delete (low, length, buffer) - val (buffer, searchList) = SearchList.build (buffer, dfa) - - val buffer = LineGap.goToIdx (low, buffer) + val low = Cursor.firstContiguousSpace (buffer, cursorIdx) + val high = Cursor.lastContiguousSpace (buffer, cursorIdx) + 1 + val length = high - low in - NormalFinish.buildTextAndClear - (app, buffer, low, searchList, initialMsg, time) + deleteAndFinish (app, low, length, buffer, time) end else - app + let + val low = Cursor.firstContiguousNonSpace (buffer, cursorIdx) + val high = Cursor.lastContiguousNonSpace (buffer, cursorIdx) + 1 + val length = high - low + in + deleteAndFinish (app, low, length, buffer, time) + end end fun finishAfterDeleteInside (app: app_type, origLow, high, time) = diff --git a/todo.md b/todo.md index 09e9212..5bfe13f 100644 --- a/todo.md +++ b/todo.md @@ -1,9 +1,8 @@ # To-do list - Add tests for: - - delete inside WORD - Implement delete-around-word/WORD and test it -- Reimplement `%` motion and `d%` motion. +- Reimple `%` motion and `d%` motion. - They 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`