From 57f012d655197f8aa09ec46fecab653a18c8ce1e Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Tue, 26 Nov 2024 21:57:02 +0000 Subject: [PATCH] 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) --- fcore/cursor.sml | 101 ++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 071ddc3..663e167 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -1,15 +1,41 @@ structure Cursor = struct - fun helpVi0 (strPos, str, absIdx, strTl, lineTl) = - if strPos < 0 then - case (strTl, lineTl) of - (shd :: stl, lhd :: ltl) => - helpVi0 (String.size shd - 1, shd, absIdx, stl, ltl) - | (_, _) => 0 + (* returns absolute index of previous line break in string *) + fun helpVi0 (absIdx, stl, ltl) = + case (stl, ltl) of + (shd :: stl, lhd :: ltl) => + if Vector.length lhd > 0 then + 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 + helpVi0 (absIdx - String.size shd, stl, ltl) + | (_, _) => 0 + + fun startVi0 (strPos, shd, lhd, absIdx, stl, ltl) = + if String.sub (shd, strPos) = #"\n" then + absIdx else - case String.sub (str, strPos) of - #"\n" => absIdx + 1 - | _ => helpVi0 (strPos - 1, str, absIdx - 1, strTl, lineTl) + 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) = let @@ -25,14 +51,8 @@ struct in if strIdx < String.size strHd then (* strIdx is in this string *) - if String.sub (strHd, strIdx) = #"\n" then - (* don't need to do anything if we are already at newline; - * just return current cursorIdx *) - cursorIdx - else - (* not at newline so start iterating *) - helpVi0 - (strIdx - 1, strHd, cursorIdx - 1, leftStrings, leftLines) + startVi0 + (strIdx, strHd, lnHd, cursorIdx, leftStrings, leftLines) else (* strIdx must be in the strTl *) (case (strTl, lnTl) of @@ -40,18 +60,14 @@ struct let val strIdx = strIdx - String.size strHd in - if String.sub (nestStrHd, strIdx) = #"\n" then - (* already at linebreak so return same cursorIdx *) - cursorIdx - else - (* not in linebreak *) - helpVi0 - ( strIdx - 1 - , nestStrHd - , cursorIdx - 1 - , strHd :: leftStrings - , lnHd :: leftLines - ) + startVi0 + ( strIdx + , nestStrHd + , nestLnHd + , cursorIdx + , strHd :: leftStrings + , lnHd :: leftLines + ) end | (_, _) => cursorIdx) end @@ -541,8 +557,8 @@ struct (* graphical-chr -> \n -> \n * so go to beginning of line, * starting from graphical-chr *) - helpVi0 - (strIdx - 2, shd, cursorIdx - 2, leftStrings, leftLines) + startVi0 + (strIdx - 2, shd, lhd, cursorIdx - 2, leftStrings, leftLines) else (* strIdx - 2 is in leftStrings *) case (leftStrings, leftLines) of @@ -555,8 +571,8 @@ struct (* graphical-chr -> \n -> \n * so go to beginning of line, * starting from graphical-chr *) - helpVi0 - (String.size lshd - 1, lshd, cursorIdx - 2, lstl, lltl) + startVi0 + (String.size lshd - 1, lshd, llhd, cursorIdx - 2, lstl, lltl) | (_, _) => (* nothing to the left, so we are at start of buffer *) 0 @@ -564,7 +580,8 @@ struct (* ? -> graphical-chr -> \n * Don't expect this case to happen * 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 (* strIdx - 1 is in leftStrings *) case (leftStrings, leftLines) of @@ -578,8 +595,8 @@ struct cursorIdx - 1 else (* graphical-chr -> \n -> \n *) - helpVi0 - (String.size lshd - 2, lshd, cursorIdx - 2, lstl, lltl) + startVi0 + (String.size lshd - 2, lshd, llhd, cursorIdx - 2, lstl, lltl) else (* cursorIdx - 2 is in lstl *) (case (lstl, lltl) of @@ -589,12 +606,13 @@ struct cursorIdx - 1 else (* graphical-chr -> \n -> \n *) - helpVi0 - (String.size stlhd - 1, stlhd, cursorIdx - 2, lstl, lltl) + startVi0 + (String.size stlhd - 1, stlhd, ltlhd, cursorIdx - 2, lstl, lltl) | (_, _) => 0) else (* ? -> 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 *) 0 @@ -1636,8 +1654,9 @@ struct (case (leftStrings, leftLines) of (lshd :: lstl, llhd :: lltl) => let - val result = helpVi0 - (String.size lshd - 1, lshd, bufferIdx - 1, lstl, lltl) + val result = + startVi0 + (String.size lshd - 1, lshd, llhd, bufferIdx - 1, lstl, lltl) in if result = bufferIdx then bufferIdx - 1