reimplement vi's '$' motion as a DFA, also eliminating a bug that involves double deleteion in the process
This commit is contained in:
@@ -509,7 +509,7 @@ struct
|
|||||||
* We also rely on helpRemoveChr to handle backwards-movement logic:
|
* We also rely on helpRemoveChr to handle backwards-movement logic:
|
||||||
* If cursorIdx is at \n after deletion, then stop.
|
* If cursorIdx is at \n after deletion, then stop.
|
||||||
* Else, move back one chr. *)
|
* Else, move back one chr. *)
|
||||||
val lastChr = Cursor.viDlr (buffer, cursorIdx)
|
val lastChr = Cursor.viDlr (buffer, cursorIdx, 1)
|
||||||
val length = lastChr - cursorIdx
|
val length = lastChr - cursorIdx
|
||||||
val buffer = LineGap.delete (cursorIdx, length, buffer)
|
val buffer = LineGap.delete (cursorIdx, length, buffer)
|
||||||
|
|
||||||
@@ -522,39 +522,23 @@ struct
|
|||||||
end
|
end
|
||||||
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) =
|
fun deleteLine (app: app_type, count) =
|
||||||
let
|
let
|
||||||
val {buffer, cursorIdx, ...} = app
|
val {buffer, cursorIdx, searchList, searchString, ...} = app
|
||||||
val cursorIdx = Cursor.vi0 (buffer, cursorIdx)
|
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
|
in
|
||||||
helpDeleteLine (app, buffer, cursorIdx, cursorIdx, count)
|
Finish.buildTextAndClear (app, buffer, cursorIdx, searchList)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun helpDeleteLineBack (app, buffer, low, high, count) =
|
fun helpDeleteLineBack (app, buffer, low, high, count) =
|
||||||
@@ -587,7 +571,7 @@ struct
|
|||||||
let
|
let
|
||||||
val {buffer, cursorIdx, ...} = app
|
val {buffer, cursorIdx, ...} = app
|
||||||
val low = Cursor.vi0 (buffer, cursorIdx)
|
val low = Cursor.vi0 (buffer, cursorIdx)
|
||||||
val high = Cursor.viDlr (buffer, cursorIdx) + 1
|
val high = Cursor.viDlr (buffer, cursorIdx, 1) + 1
|
||||||
in
|
in
|
||||||
helpDeleteLineBack (app, buffer, low, high, count)
|
helpDeleteLineBack (app, buffer, low, high, count)
|
||||||
end
|
end
|
||||||
|
|||||||
56
fcore/cursor-dfa/vi-dlr-dfa.sml
Normal file
56
fcore/cursor-dfa/vi-dlr-dfa.sml
Normal file
@@ -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
|
||||||
@@ -47,67 +47,8 @@ struct
|
|||||||
|
|
||||||
fun vi0 (lineGap, cursorIdx) = Vi0.foldPrev (lineGap, cursorIdx, ())
|
fun vi0 (lineGap, cursorIdx) = Vi0.foldPrev (lineGap, cursorIdx, ())
|
||||||
|
|
||||||
fun helpViDlr (strPos, str, absIdx, strTl, lineTl) =
|
val viDlr = ViDlrDfa.next
|
||||||
if strPos = String.size str then
|
val viDlrForDelete = ViDlrDfa.nextForDelete
|
||||||
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
|
|
||||||
|
|
||||||
fun helpViL (strIdx, hd, cursorIdx, tl) =
|
fun helpViL (strIdx, hd, cursorIdx, tl) =
|
||||||
if String.sub (hd, strIdx) = #"\n" then
|
if String.sub (hd, strIdx) = #"\n" then
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ structure MoveViK = MakeMove (struct val fMove = Cursor.viK end)
|
|||||||
structure MoveViL = MakeMove (struct val fMove = Cursor.viL end)
|
structure MoveViL = MakeMove (struct val fMove = Cursor.viL end)
|
||||||
|
|
||||||
structure MoveToStartOfLine = MakeMove (struct val fMove = Cursor.vi0 end)
|
structure MoveToStartOfLine = MakeMove (struct val fMove = Cursor.vi0 end)
|
||||||
structure MoveToEndOfLine = MakeMove (struct val fMove = Cursor.viDlr end)
|
|
||||||
|
|
||||||
signature DFA_MOVE =
|
signature DFA_MOVE =
|
||||||
sig
|
sig
|
||||||
@@ -82,3 +81,5 @@ structure MoveToEndOfPrevWord =
|
|||||||
MakeDfaMove (struct val fMove = Cursor.endOfPrevWord end)
|
MakeDfaMove (struct val fMove = Cursor.endOfPrevWord end)
|
||||||
structure MoveToEndOfPrevWORD =
|
structure MoveToEndOfPrevWORD =
|
||||||
MakeDfaMove (struct val fMove = Cursor.endOfPrevWORD end)
|
MakeDfaMove (struct val fMove = Cursor.endOfPrevWORD end)
|
||||||
|
|
||||||
|
structure MoveToEndOfLine = MakeDfaMove (struct val fMove = Cursor.viDlr end)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ in
|
|||||||
fcore/cursor-dfa/make-dfa-loop.sml
|
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-word-dfa.sml
|
fcore/cursor-dfa/vi-word-dfa.sml
|
||||||
|
fcore/cursor-dfa/vi-dlr-dfa.sml
|
||||||
end
|
end
|
||||||
fcore/cursor.sml
|
fcore/cursor.sml
|
||||||
fcore/text-window.sml
|
fcore/text-window.sml
|
||||||
|
|||||||
1
shf.mlb
1
shf.mlb
@@ -25,6 +25,7 @@ in
|
|||||||
fcore/cursor-dfa/make-dfa-loop.sml
|
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-word-dfa.sml
|
fcore/cursor-dfa/vi-word-dfa.sml
|
||||||
|
fcore/cursor-dfa/vi-dlr-dfa.sml
|
||||||
end
|
end
|
||||||
fcore/cursor.sml
|
fcore/cursor.sml
|
||||||
fcore/text-window.sml
|
fcore/text-window.sml
|
||||||
|
|||||||
Reference in New Issue
Block a user