From 528aea59a1eb5508565aec66626c3c0eea9e118b Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Mon, 4 Aug 2025 05:37:08 +0100 Subject: [PATCH] reimplement vi's '$' motion as a DFA, also eliminating a bug that involves double deleteion in the process --- fcore/app-update.sml | 48 +++++++++---------------- fcore/cursor-dfa/vi-dlr-dfa.sml | 56 +++++++++++++++++++++++++++++ fcore/cursor.sml | 63 ++------------------------------- fcore/move.sml | 3 +- shf-tests.mlb | 1 + shf.mlb | 1 + 6 files changed, 78 insertions(+), 94 deletions(-) create mode 100644 fcore/cursor-dfa/vi-dlr-dfa.sml diff --git a/fcore/app-update.sml b/fcore/app-update.sml index cb74e36..bfe3444 100644 --- a/fcore/app-update.sml +++ b/fcore/app-update.sml @@ -509,7 +509,7 @@ struct * We also rely on helpRemoveChr to handle backwards-movement logic: * If cursorIdx is at \n after deletion, then stop. * Else, move back one chr. *) - val lastChr = Cursor.viDlr (buffer, cursorIdx) + val lastChr = Cursor.viDlr (buffer, cursorIdx, 1) val length = lastChr - cursorIdx val buffer = LineGap.delete (cursorIdx, length, buffer) @@ -522,39 +522,23 @@ struct end end - fun helpDeleteLine (app: app_type, buffer, cursorIdx, otherIdx, count) = - if count = 0 then - let - val otherIdx = Cursor.clipIdx (buffer, otherIdx) - val length = otherIdx - cursorIdx - val buffer = LineGap.delete (cursorIdx, length, buffer) - - val {searchList, searchString, ...} = app - val (buffer, searchList) = deleteSearchList - (cursorIdx, length, searchString, searchList, buffer) - - val buffer = LineGap.goToIdx (cursorIdx, buffer) - val cursorIdx = Cursor.clipIdx (buffer, cursorIdx) - in - Finish.buildTextAndClear (app, buffer, cursorIdx, searchList) - end - else - let - (* get otherIdx, where cursor will want to go after motion. *) - val buffer = LineGap.goToIdx (otherIdx, buffer) - val newOtherIdx = Cursor.viDlr (buffer, otherIdx) - val newOtherIdx = Cursor.viL (buffer, newOtherIdx) - val newCount = if newOtherIdx = otherIdx then 0 else count - 1 - in - helpDeleteLine (app, buffer, cursorIdx, newOtherIdx, newCount) - end - fun deleteLine (app: app_type, count) = let - val {buffer, cursorIdx, ...} = app - val cursorIdx = Cursor.vi0 (buffer, cursorIdx) + val {buffer, cursorIdx, searchList, searchString, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + + val startIdx = Cursor.vi0 (buffer, cursorIdx) + val finishIdx = Cursor.viDlrForDelete (buffer, cursorIdx, count) + + val length = finishIdx - startIdx + val buffer = LineGap.delete (startIdx, length, buffer) + + val (buffer, searchList) = deleteSearchList + (startIdx, length, searchString, searchList, buffer) + + val buffer = LineGap.goToIdx (startIdx, buffer) in - helpDeleteLine (app, buffer, cursorIdx, cursorIdx, count) + Finish.buildTextAndClear (app, buffer, cursorIdx, searchList) end fun helpDeleteLineBack (app, buffer, low, high, count) = @@ -587,7 +571,7 @@ struct let val {buffer, cursorIdx, ...} = app val low = Cursor.vi0 (buffer, cursorIdx) - val high = Cursor.viDlr (buffer, cursorIdx) + 1 + val high = Cursor.viDlr (buffer, cursorIdx, 1) + 1 in helpDeleteLineBack (app, buffer, low, high, count) end diff --git a/fcore/cursor-dfa/vi-dlr-dfa.sml b/fcore/cursor-dfa/vi-dlr-dfa.sml new file mode 100644 index 0000000..f963ef6 --- /dev/null +++ b/fcore/cursor-dfa/vi-dlr-dfa.sml @@ -0,0 +1,56 @@ +structure ViDlrDfa = +struct + val startState: Word8.word = 0w0 + val newlineState: Word8.word = 0w1 + val notNewlineState = 0w2 + + fun makeStart i = + if Char.chr i = #"\n" then newlineState else notNewlineState + + val startTable = Vector.tabulate (255, makeStart) + val newlineTable = startTable + val notNewlineTable = startTable + + val tables = #[startTable, newlineTable, notNewlineTable] + + fun isFinal currentState = currentState = newlineState + + structure ViDlr = + MakeNextDfaLoop + (struct + val startState = startState + + structure Folder = + MakeCharFolderNext + (struct + val startState = startState + val tables = tables + + fun finish x = x - 1 + val isFinal = isFinal + end) + + val fStart = Folder.foldNext + end) + + structure ViDlrForDelete = + MakeNextDfaLoop + (struct + val startState = startState + + structure Folder = + MakeCharFolderNext + (struct + val startState = startState + val tables = tables + + fun finish x = x + 1 + val isFinal = isFinal + end) + + val fStart = Folder.foldNext + end) + + val next = ViDlr.next + val nextForDelete = ViDlrForDelete.next +end diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 27bcaa2..3b13156 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -47,67 +47,8 @@ struct fun vi0 (lineGap, cursorIdx) = Vi0.foldPrev (lineGap, cursorIdx, ()) - fun helpViDlr (strPos, str, absIdx, strTl, lineTl) = - if strPos = String.size str then - case (strTl, lineTl) of - (shd :: stl, lhd :: ltl) => helpViDlr (0, shd, absIdx, stl, ltl) - | (_, _) => absIdx - 1 - else - case String.sub (str, strPos) of - #"\n" => absIdx - 1 - | _ => helpViDlr (strPos + 1, str, absIdx + 1, strTl, lineTl) - - fun viDlr (lineGap: LineGap.t, cursorIdx) = - let - val - {rightStrings, idx = bufferIdx, rightLines, leftStrings, leftLines, ...} = - lineGap - in - case (rightStrings, rightLines) of - (strHd :: strTl, lnHd :: lnTl) => - let - (* convert absolute cursorIdx to idx relative to hd string *) - val strIdx = cursorIdx - bufferIdx - in - if strIdx < String.size strHd then - if String.sub (strHd, strIdx) <> #"\n" then - (* not in double linebreak *) - helpViDlr (strIdx + 1, strHd, cursorIdx + 1, strTl, lnTl) - else (* check if we are in double linebreak *) if strIdx - 1 >= 0 then - if String.sub (strHd, strIdx - 1) = #"\n" then - (* we are in double linebreak, so do nothing *) - cursorIdx - else - (* not in double linebreak, so iterate *) - helpViDlr (strIdx + 1, strHd, cursorIdx + 1, strTl, lnTl) - else - (* check if double linebreak in strTl *) - (case strTl of - nestStrHd :: _ => - if String.sub (nestStrHd, 0) = #"\n" then - cursorIdx - else - helpViDlr (strIdx + 1, strHd, cursorIdx + 1, strTl, lnTl) - | [] => cursorIdx) - else - (* strIdx must be in the strTl *) - (case (strTl, lnTl) of - (nestStrHd :: nestStrTl, nestLnHd :: nestLnTl) => - let - val strIdx = strIdx - String.size strHd - in - helpViDlr - ( strIdx + 1 - , nestStrHd - , cursorIdx + 1 - , nestStrTl - , nestLnTl - ) - end - | (_, _) => cursorIdx) - end - | (_, _) => (* nowhere to go, so return cursorIdx *) cursorIdx - end + val viDlr = ViDlrDfa.next + val viDlrForDelete = ViDlrDfa.nextForDelete fun helpViL (strIdx, hd, cursorIdx, tl) = if String.sub (hd, strIdx) = #"\n" then diff --git a/fcore/move.sml b/fcore/move.sml index 9113459..95db467 100644 --- a/fcore/move.sml +++ b/fcore/move.sml @@ -43,7 +43,6 @@ structure MoveViK = MakeMove (struct val fMove = Cursor.viK end) structure MoveViL = MakeMove (struct val fMove = Cursor.viL end) structure MoveToStartOfLine = MakeMove (struct val fMove = Cursor.vi0 end) -structure MoveToEndOfLine = MakeMove (struct val fMove = Cursor.viDlr end) signature DFA_MOVE = sig @@ -82,3 +81,5 @@ structure MoveToEndOfPrevWord = MakeDfaMove (struct val fMove = Cursor.endOfPrevWord end) structure MoveToEndOfPrevWORD = MakeDfaMove (struct val fMove = Cursor.endOfPrevWORD end) + +structure MoveToEndOfLine = MakeDfaMove (struct val fMove = Cursor.viDlr end) diff --git a/shf-tests.mlb b/shf-tests.mlb index 3c51cd4..dea6bd9 100644 --- a/shf-tests.mlb +++ b/shf-tests.mlb @@ -25,6 +25,7 @@ in fcore/cursor-dfa/make-dfa-loop.sml fcore/cursor-dfa/vi-WORD-dfa.sml fcore/cursor-dfa/vi-word-dfa.sml + fcore/cursor-dfa/vi-dlr-dfa.sml end fcore/cursor.sml fcore/text-window.sml diff --git a/shf.mlb b/shf.mlb index baa2a3e..8450677 100644 --- a/shf.mlb +++ b/shf.mlb @@ -25,6 +25,7 @@ in fcore/cursor-dfa/make-dfa-loop.sml fcore/cursor-dfa/vi-WORD-dfa.sml fcore/cursor-dfa/vi-word-dfa.sml + fcore/cursor-dfa/vi-dlr-dfa.sml end fcore/cursor.sml fcore/text-window.sml