refactor Cursor.viH to use DFA

This commit is contained in:
2025-09-17 10:45:37 +01:00
parent 9ddb5f68d7
commit dbf05ec8dc
5 changed files with 63 additions and 79 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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