From dbf05ec8dc812ff32e684a40837926e8d4ced3f0 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Wed, 17 Sep 2025 10:45:37 +0100 Subject: [PATCH] refactor Cursor.viH to use DFA --- fcore/cursor-dfa/vi-l-dfa.sml | 62 ++++++++++++++++++-- fcore/cursor.sml | 72 +----------------------- fcore/move.sml | 2 +- fcore/normal-mode/make-normal-delete.sml | 2 +- fcore/normal-mode/normal-mode.sml | 4 +- 5 files changed, 63 insertions(+), 79 deletions(-) diff --git a/fcore/cursor-dfa/vi-l-dfa.sml b/fcore/cursor-dfa/vi-l-dfa.sml index 4cba737..0bb86e0 100644 --- a/fcore/cursor-dfa/vi-l-dfa.sml +++ b/fcore/cursor-dfa/vi-l-dfa.sml @@ -4,19 +4,30 @@ struct val notNewlineState: Word8.word = 0w1 val oneNewlineState: Word8.word = 0w2 val twoNewlineState: Word8.word = 0w3 + val notNewlineAfterNewlineState: Word8.word = 0w4 fun makeStart i = if Char.chr i = #"\n" then oneNewlineState else notNewlineState fun makeOneNewline i = - if Char.chr i = #"\n" then twoNewlineState else notNewlineState + if Char.chr i = #"\n" then twoNewlineState else notNewlineAfterNewlineState + + fun makeTwoNeline i = + if Char.chr i = #"\n" then oneNewlineState else notNewlineAfterNewlineState val startTable = Vector.tabulate (255, makeStart) val notNewlineTable = startTable val oneNewlineTable = Vector.tabulate (255, makeOneNewline) val twoNewLineTable = startTable + val notNewlineAfterNewlineTable = notNewlineTable - val tables = #[startTable, notNewlineTable, oneNewlineTable, twoNewLineTable] + val tables = + #[ startTable + , notNewlineTable + , oneNewlineTable + , twoNewLineTable + , notNewlineAfterNewlineTable + ] fun next (currentState, chr) = let val table = Vector.sub (tables, Word8.toInt currentState) @@ -38,12 +49,17 @@ struct val chr = String.sub (str, idx) val newState = next (currentState, chr) in - if newState = twoNewlineState then + if + newState = twoNewlineState + then if counter - 1 = ~1 then absIdx - 1 else loop (idx + 1, absIdx + 1, str, tl, startState, counter - 1) - else if newState = notNewlineState then + else if + newState = notNewlineState + orelse newState = notNewlineAfterNewlineState + then if counter - 1 = ~1 then absIdx else @@ -55,5 +71,43 @@ struct val fStart = loop end) + structure ViH = + MakePrevDfaLoop + (struct + val startState = startState + + fun loop (idx, absIdx, str, tl, currentState, counter) = + if idx < 0 then + case tl of + str :: tl => + loop + (String.size str - 1, absIdx, str, tl, currentState, counter) + | [] => absIdx + else + let + val chr = String.sub (str, idx) + val newState = next (currentState, chr) + in + if newState = twoNewlineState then + if counter - 1 = ~1 then absIdx + else loop (idx - 1, absIdx - 1, str, tl, newState, counter - 1) + else if newState = notNewlineState then + if counter - 1 = ~1 then + absIdx + else + loop (idx - 1, absIdx - 1, str, tl, startState, counter - 1) + else if newState = notNewlineAfterNewlineState then + if counter - 1 <= 0 then + absIdx + else + loop (idx - 1, absIdx - 1, str, tl, startState, counter - 1) + else + loop (idx - 1, absIdx - 1, str, tl, newState, counter) + end + + val fStart = loop + end) + val next = ViL.next + val prev = ViH.prev end diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 7c1e329..fd5ec19 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -57,77 +57,7 @@ struct val viDlrForDelete = ViDlrDfa.nextForDelete val viL = ViLDfa.next - - structure ViH = - MakeIfCharFolderPrev - (struct - type env = unit - - fun helpViH (strIdx, hd, cursorIdx, leftStrings) = - if strIdx > 0 then - (* bounds check: can access prev char in hd *) - if String.sub (hd, strIdx - 1) = #"\n" then - (* prev char is line break *) - if strIdx - 1 > 0 then - (* bounds check: can access two chars back in hd *) - if String.sub (hd, strIdx - 2) = #"\n" then - (* line break followed by line break - * so it is fine to decrement by 1 *) - cursorIdx - 1 - else - (* non-line break followed by line break - * so we have to decrement by two, - * skipping over line break *) - cursorIdx - 2 - else - (* need to check two chars back in leftStrings *) - (case leftStrings of - lhd :: ltl => - if String.sub (lhd, String.size lhd - 1) = #"\n" then - (* double line break *) - cursorIdx - 1 - else - (* non-line break precedes line break *) - cursorIdx - 2 - | [] => cursorIdx - 1) - else - (* prev char is not line break so we can decrement by 1 *) - cursorIdx - 1 - else - (* prev char is in leftStrings *) - (case leftStrings of - lhd :: ltl => - if String.sub (lhd, String.size lhd - 1) = #"\n" then - (* one line break *) - if String.size lhd > 1 then - (* bounds check: prev-prev chr is in lhd *) - if String.sub (lhd, String.size lhd - 2) = #"\n" then - (* double line break *) - cursorIdx - 1 - else - (* non-line break precedes line break *) - cursorIdx - 2 - else - (* prev-prev chr is in ltl *) - (case ltl of - ltlhd :: _ => - if String.sub (ltlhd, String.size ltlhd - 1) = #"\n" then - (* double line break *) - cursorIdx - 1 - else - (* non-line break precedes line break *) - cursorIdx - 2 - | [] => cursorIdx - 1) - else - (* no line break *) - cursorIdx - 1 - | [] => 0) - - fun fStart (strIdx, hd, _, cursorIdx, leftStrings, _, _) = - helpViH (strIdx, hd, cursorIdx, leftStrings) - end) - - fun viH (lineGap, cursorIdx) = ViH.foldPrev (lineGap, cursorIdx, ()) + val viH = ViLDfa.prev fun helpGetCursorColumn (distanceFromLine, strList, lineList) = case (strList, lineList) of diff --git a/fcore/move.sml b/fcore/move.sml index 140a93d..a6164e4 100644 --- a/fcore/move.sml +++ b/fcore/move.sml @@ -42,7 +42,6 @@ struct end end -structure MoveViH = MakeMove (struct val fMove = Cursor.viH end) structure MoveViJ = MakeMove (struct val fMove = Cursor.viJ end) structure MoveViK = MakeMove (struct val fMove = Cursor.viK end) @@ -76,6 +75,7 @@ struct end end +structure MoveViH = MakeDfaMove (struct val fMove = Cursor.viH end) structure MoveViL = MakeDfaMove (struct val fMove = Cursor.viL end) structure MoveToNextWord = MakeDfaMove (struct val fMove = Cursor.nextWord end) diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 110b223..b4a2e1f 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -337,7 +337,7 @@ struct else let val buffer = LineGap.goToIdx (low, buffer) - val low = Cursor.viH (buffer, low) + val low = Cursor.viH (buffer, low, 1) val buffer = LineGap.goToIdx (low, buffer) val low = Cursor.vi0 (buffer, low) val newCount = if low = 0 then 0 else count - 1 diff --git a/fcore/normal-mode/normal-mode.sml b/fcore/normal-mode/normal-mode.sml index 145071b..3f4635f 100644 --- a/fcore/normal-mode/normal-mode.sml +++ b/fcore/normal-mode/normal-mode.sml @@ -250,7 +250,7 @@ struct fun parseDeleteTerminal (str, count, app, chrCmd, time) = case chrCmd of (* terminal commands: require no input after *) - #"h" => NormalDelete.delete (app, count, Cursor.viH, time) + #"h" => NormalDelete.deleteByDfa (app, count, Cursor.viH, time) | #"l" => NormalDelete.deleteByDfa (app, count, Cursor.viL, time) (* vi's 'j' and 'k' commands move up or down a column * but 'dj' or 'dk' delete whole lines @@ -346,7 +346,7 @@ struct fun parseDeleteTerminal (str, count, app, chrCmd, time) = case chrCmd of (* terminal commands: require no input after *) - #"h" => NormalYankDelete.delete (app, count, Cursor.viH, time) + #"h" => NormalYankDelete.deleteByDfa (app, count, Cursor.viH, time) | #"l" => NormalYankDelete.deleteByDfa (app, count, Cursor.viL, time) (* vi's 'j' and 'k' commands move up or down a column * but 'dj' or 'dk' delete whole lines