reimplement vi0 and helper functions so that they are likely faster (vi0 bring cursor to start of current line; before, this was done by checking each character in the string backwards, but now it is done by looking at the line metadata, which is faster for us by some constant factor)

This commit is contained in:
2024-11-26 21:57:02 +00:00
parent db64917416
commit 57f012d655

View File

@@ -1,15 +1,41 @@
structure Cursor = structure Cursor =
struct struct
fun helpVi0 (strPos, str, absIdx, strTl, lineTl) = (* returns absolute index of previous line break in string *)
if strPos < 0 then fun helpVi0 (absIdx, stl, ltl) =
case (strTl, lineTl) of case (stl, ltl) of
(shd :: stl, lhd :: ltl) => (shd :: stl, lhd :: ltl) =>
helpVi0 (String.size shd - 1, shd, absIdx, stl, ltl) if Vector.length lhd > 0 then
| (_, _) => 0 let
val startAbsIdx = absIdx - String.size shd
val lineIdx = Vector.sub (lhd, Vector.length lhd - 1)
in
(* found lineIdx.
* Need to make sure we follow cursor-on-linebreak rule:
* If line break is preceded by non-line break char,
* then increment by 1.
* *)
startAbsIdx + lineIdx + 1
end
else else
case String.sub (str, strPos) of helpVi0 (absIdx - String.size shd, stl, ltl)
#"\n" => absIdx + 1 | (_, _) => 0
| _ => helpVi0 (strPos - 1, str, absIdx - 1, strTl, lineTl)
fun startVi0 (strPos, shd, lhd, absIdx, stl, ltl) =
if String.sub (shd, strPos) = #"\n" then
absIdx
else
if Vector.length lhd > 0 then
if Vector.sub (lhd, 0) < strPos then
let
val linePos = BinSearch.equalOrLess (strPos - 1, lhd)
val lineIdx = Vector.sub (lhd, linePos)
in
absIdx - strPos + lineIdx + 1
end
else
helpVi0 (absIdx - strPos, stl, ltl)
else
helpVi0 (absIdx - strPos, stl, ltl)
fun vi0 (lineGap: LineGap.t, cursorIdx) = fun vi0 (lineGap: LineGap.t, cursorIdx) =
let let
@@ -25,14 +51,8 @@ struct
in in
if strIdx < String.size strHd then if strIdx < String.size strHd then
(* strIdx is in this string *) (* strIdx is in this string *)
if String.sub (strHd, strIdx) = #"\n" then startVi0
(* don't need to do anything if we are already at newline; (strIdx, strHd, lnHd, cursorIdx, leftStrings, leftLines)
* just return current cursorIdx *)
cursorIdx
else
(* not at newline so start iterating *)
helpVi0
(strIdx - 1, strHd, cursorIdx - 1, leftStrings, leftLines)
else else
(* strIdx must be in the strTl *) (* strIdx must be in the strTl *)
(case (strTl, lnTl) of (case (strTl, lnTl) of
@@ -40,15 +60,11 @@ struct
let let
val strIdx = strIdx - String.size strHd val strIdx = strIdx - String.size strHd
in in
if String.sub (nestStrHd, strIdx) = #"\n" then startVi0
(* already at linebreak so return same cursorIdx *) ( strIdx
cursorIdx
else
(* not in linebreak *)
helpVi0
( strIdx - 1
, nestStrHd , nestStrHd
, cursorIdx - 1 , nestLnHd
, cursorIdx
, strHd :: leftStrings , strHd :: leftStrings
, lnHd :: leftLines , lnHd :: leftLines
) )
@@ -541,8 +557,8 @@ struct
(* graphical-chr -> \n -> \n (* graphical-chr -> \n -> \n
* so go to beginning of line, * so go to beginning of line,
* starting from graphical-chr *) * starting from graphical-chr *)
helpVi0 startVi0
(strIdx - 2, shd, cursorIdx - 2, leftStrings, leftLines) (strIdx - 2, shd, lhd, cursorIdx - 2, leftStrings, leftLines)
else else
(* strIdx - 2 is in leftStrings *) (* strIdx - 2 is in leftStrings *)
case (leftStrings, leftLines) of case (leftStrings, leftLines) of
@@ -555,8 +571,8 @@ struct
(* graphical-chr -> \n -> \n (* graphical-chr -> \n -> \n
* so go to beginning of line, * so go to beginning of line,
* starting from graphical-chr *) * starting from graphical-chr *)
helpVi0 startVi0
(String.size lshd - 1, lshd, cursorIdx - 2, lstl, lltl) (String.size lshd - 1, lshd, llhd, cursorIdx - 2, lstl, lltl)
| (_, _) => | (_, _) =>
(* nothing to the left, so we are at start of buffer *) (* nothing to the left, so we are at start of buffer *)
0 0
@@ -564,7 +580,8 @@ struct
(* ? -> graphical-chr -> \n (* ? -> graphical-chr -> \n
* Don't expect this case to happen * Don't expect this case to happen
* but if it does, go to start of line. *) * but if it does, go to start of line. *)
helpVi0 (strIdx - 1, shd, cursorIdx - 1, leftStrings, leftLines) startVi0
(strIdx - 1, shd, lhd, cursorIdx - 1, leftStrings, leftLines)
else else
(* strIdx - 1 is in leftStrings *) (* strIdx - 1 is in leftStrings *)
case (leftStrings, leftLines) of case (leftStrings, leftLines) of
@@ -578,8 +595,8 @@ struct
cursorIdx - 1 cursorIdx - 1
else else
(* graphical-chr -> \n -> \n *) (* graphical-chr -> \n -> \n *)
helpVi0 startVi0
(String.size lshd - 2, lshd, cursorIdx - 2, lstl, lltl) (String.size lshd - 2, lshd, llhd, cursorIdx - 2, lstl, lltl)
else else
(* cursorIdx - 2 is in lstl *) (* cursorIdx - 2 is in lstl *)
(case (lstl, lltl) of (case (lstl, lltl) of
@@ -589,12 +606,13 @@ struct
cursorIdx - 1 cursorIdx - 1
else else
(* graphical-chr -> \n -> \n *) (* graphical-chr -> \n -> \n *)
helpVi0 startVi0
(String.size stlhd - 1, stlhd, cursorIdx - 2, lstl, lltl) (String.size stlhd - 1, stlhd, ltlhd, cursorIdx - 2, lstl, lltl)
| (_, _) => 0) | (_, _) => 0)
else else
(* ? -> graphical-chr -> \n *) (* ? -> graphical-chr -> \n *)
helpVi0 (String.size lshd - 1, lshd, cursorIdx - 1, leftStrings, leftLines) startVi0
(String.size lshd - 1, lshd, llhd, cursorIdx - 1, leftStrings, leftLines)
| (_, _) => | (_, _) =>
(* leftStrings is empty so go to start of buffer *) (* leftStrings is empty so go to start of buffer *)
0 0
@@ -1636,8 +1654,9 @@ struct
(case (leftStrings, leftLines) of (case (leftStrings, leftLines) of
(lshd :: lstl, llhd :: lltl) => (lshd :: lstl, llhd :: lltl) =>
let let
val result = helpVi0 val result =
(String.size lshd - 1, lshd, bufferIdx - 1, lstl, lltl) startVi0
(String.size lshd - 1, lshd, llhd, bufferIdx - 1, lstl, lltl)
in in
if result = bufferIdx then if result = bufferIdx then
bufferIdx - 1 bufferIdx - 1