abstract reusable function from goToLine so it can be used in goToIdx, and implement goToIdx

This commit is contained in:
2024-10-10 22:56:24 +01:00
parent d4ef45630d
commit d2e5c23c61

View File

@@ -20,6 +20,7 @@ sig
val append: string * t -> t val append: string * t -> t
val goToStart: t -> t val goToStart: t -> t
val goToIdx: int * t -> t
val goToLine: int * t -> t val goToLine: int * t -> t
(* for testing *) (* for testing *)
@@ -2009,13 +2010,27 @@ struct
({idx, line, leftStrings, leftLines, rightStrings, rightLines}: t) = ({idx, line, leftStrings, leftLines, rightStrings, rightLines}: t) =
helpGoToStart (idx, line, leftStrings, leftLines, rightStrings, rightLines) helpGoToStart (idx, line, leftStrings, leftLines, rightStrings, rightLines)
fun helpGoToLineLeft (* function to abstract leftwards movement.
(idx, line, searchLine, leftStrings, leftLines, rightStrings, rightLines) = * if the left hd and the right hd can be joined in one node
case (leftStrings, leftLines) of * during movement, while staying in limit, then join and move.
(lStrHd :: lStrTl, lLnHd :: lLnTl) => * Else, move without joining.
if searchLine < line - Vector.length lLnHd then * The code to do this is a bit boiler-plate heavy
(* move leftwards, joining if possible *) * so it has been abstracted to a reusable function.
(case (rightStrings, rightLines) of *
* The last parameter, fGoLeft, is the function to return to
* after the leftwards movement.
*
* The third paremeter, searchTo, is the line number or UTF-8
* index to search. Since moveLeft is meant to abstract over
* the search number, this parameter is just passed to fGoLeft.
* *)
fun moveLeft
( idx, line, searchTo
, leftStrings, leftLines, rightStrings, rightLines
, lStrHd, lStrTl, lLnHd, lLnTl
, fGoLeft
) =
case (rightStrings, rightLines) of
(rStrHd :: rStrTl, rLnHd :: rLnTl) => (rStrHd :: rStrTl, rLnHd :: rLnTl) =>
if isInLimit (lStrHd, rStrHd, lLnHd, rLnHd) then if isInLimit (lStrHd, rStrHd, lLnHd, rLnHd) then
(* join into a single node before moving *) (* join into a single node before moving *)
@@ -2032,10 +2047,10 @@ struct
+ String.size lStrHd + String.size lStrHd
) )
in in
helpGoToLineLeft fGoLeft
( idx - String.size lStrHd ( idx - String.size lStrHd
, line - Vector.length lLnHd , line - Vector.length lLnHd
, searchLine , searchTo
, lStrTl , lStrTl
, lLnTl , lLnTl
, newRstrHd :: rStrTl , newRstrHd :: rStrTl
@@ -2044,10 +2059,10 @@ struct
end end
else else
(* move without joining *) (* move without joining *)
helpGoToLineLeft fGoLeft
( idx - String.size lStrHd ( idx - String.size lStrHd
, line - Vector.length lLnHd , line - Vector.length lLnHd
, searchLine , searchTo
, lStrTl , lStrTl
, lLnTl , lLnTl
, lStrHd :: rightStrings , lStrHd :: rightStrings
@@ -2055,15 +2070,85 @@ struct
) )
| (_, _) => | (_, _) =>
(* right side is empty, so just move left without joining *) (* right side is empty, so just move left without joining *)
helpGoToLineLeft fGoLeft
( idx - String.size lStrHd ( idx - String.size lStrHd
, line - Vector.length lLnHd , line - Vector.length lLnHd
, searchLine , searchTo
, lStrTl , lStrTl
, lLnTl , lLnTl
, [lStrHd] , [lStrHd]
, [lLnHd] , [lLnHd]
)) )
(* same as moveLeft function, except it move rightwards instead *)
fun moveRight
( idx, line, searchTo
, leftStrings, leftLines, rightStrings, rightLines
, rStrHd, rStrTl, rLnHd, rLnTl
, fGoRight
) =
case (leftStrings, leftLines) of
(lStrHd :: lStrTl, lLnHd :: lLnTl) =>
if isInLimit (lStrHd, rStrHd, lLnHd, rLnHd) then
(* can join while staying in limit, so join and move right *)
let
val newLstrHd = lStrHd ^ rStrHd
val newLlnHd =
Vector.tabulate
( Vector.length lLnHd + Vector.length rLnHd
, fn lnIdx =>
if lnIdx < Vector.length lLnHd then
Vector.sub (lLnHd, lnIdx)
else
Vector.sub (rLnHd, lnIdx - Vector.length lLnHd)
+ String.size lStrHd
)
in
fGoRight
( idx + String.size rStrHd
, line + Vector.length rLnHd
, searchTo
, newLstrHd :: lStrTl
, newLlnHd :: lLnTl
, rStrTl
, rLnTl
)
end
else
(* cannot join while staying in limit, so just move right *)
fGoRight
( idx + String.size rStrHd
, line + Vector.length rLnHd
, searchTo
, rStrHd :: leftStrings
, rLnHd :: leftLines
, rStrTl
, rLnTl
)
| (_, _) =>
(* left side is empty, so just move rightwards without joining *)
fGoRight
( String.size rStrHd
, Vector.length rLnHd
, searchTo
, [rStrHd]
, [rLnHd]
, rStrTl
, rLnTl
)
fun helpGoToLineLeft
(idx, line, searchLine, leftStrings, leftLines, rightStrings, rightLines) =
case (leftStrings, leftLines) of
(lStrHd :: lStrTl, lLnHd :: lLnTl) =>
if searchLine < line - Vector.length lLnHd then
(* move leftwards, joining if possible *)
moveLeft
( idx, line, searchLine
, leftStrings, leftLines, rightStrings, rightLines
, lStrHd, lStrTl, lLnHd, lLnTl
, helpGoToLineLeft
)
else else
(* line is at left head, so place it to the right and return *) (* line is at left head, so place it to the right and return *)
{ idx = idx - String.size lStrHd { idx = idx - String.size lStrHd
@@ -2089,55 +2174,12 @@ struct
(rStrHd :: rStrTl, rLnHd :: rLnTl) => (rStrHd :: rStrTl, rLnHd :: rLnTl) =>
if searchLine > line + Vector.length rLnHd then if searchLine > line + Vector.length rLnHd then
(* have to move rightwards *) (* have to move rightwards *)
(case (leftStrings, leftLines) of moveRight
(lStrHd :: lStrTl, lLnHd :: lLnTl) => ( idx, line, searchLine
if isInLimit (lStrHd, rStrHd, lLnHd, rLnHd) then , leftStrings, leftLines, rightStrings, rightLines
(* can join while staying in limit, so join and move right *) , rStrHd, rStrTl, rLnHd, rLnTl
let , helpGoToLineRight
val newLstrHd = lStrHd ^ rStrHd
val newLlnHd =
Vector.tabulate
( Vector.length lLnHd + Vector.length rLnHd
, fn lnIdx =>
if lnIdx < Vector.length lLnHd then
Vector.sub (lLnHd, lnIdx)
else
Vector.sub (rLnHd, lnIdx - Vector.length lLnHd)
+ String.size lStrHd
) )
in
helpGoToLineRight
( idx + String.size rStrHd
, line + Vector.length rLnHd
, searchLine
, newLstrHd :: lStrTl
, newLlnHd :: lLnTl
, rStrTl
, rLnTl
)
end
else
(* cannot join while staying in limit, so just move right *)
helpGoToLineRight
( idx + String.size rStrHd
, line + Vector.length rLnHd
, searchLine
, rStrHd :: leftStrings
, rLnHd :: leftLines
, rStrTl
, rLnTl
)
| (_, _) =>
(* left side is empty, so just move rightwards without joining *)
helpGoToLineRight
( String.size rStrHd
, Vector.length rLnHd
, searchLine
, [rStrHd]
, [rLnHd]
, rStrTl
, rLnTl
))
else else
(* searchLine is in rStrHd/rLnHd, so return *) (* searchLine is in rStrHd/rLnHd, so return *)
{ idx = idx { idx = idx
@@ -2185,6 +2227,96 @@ struct
buffer buffer
end end
fun helpGoToIdxLeft
(idx, line, searchIdx, leftStrings, leftLines, rightStrings, rightLines) =
case (leftStrings, leftLines) of
(lStrHd :: lStrTl, lLnHd :: lLnTl) =>
if searchIdx < idx - String.size lStrHd then
(* move leftwards, joining if possible *)
moveLeft
( idx, line, searchIdx
, leftStrings, leftLines, rightStrings, rightLines
, lStrHd, lStrTl, lLnHd, lLnTl
, helpGoToIdxLeft
)
else
(* line is at left head, so place it to the right and return *)
{ idx = idx - String.size lStrHd
, line = line - Vector.length lLnHd
, leftStrings = lStrTl
, leftLines = lLnTl
, rightStrings = lStrHd :: rightStrings
, rightLines = lLnHd :: rightLines
}
| (_, _) =>
(* left side is empty, so just return *)
{ idx = idx
, line = line
, leftStrings = []
, leftLines = []
, rightStrings = rightStrings
, rightLines = rightLines
}
fun helpGoToIdxRight
(idx, line, searchIdx, leftStrings, leftLines, rightStrings, rightLines) =
case (rightStrings, rightLines) of
(rStrHd :: rStrTl, rLnHd :: rLnTl) =>
if searchIdx > idx + String.size rStrHd then
(* have to move rightwards *)
moveRight
( idx, line, searchIdx
, leftStrings, leftLines, rightStrings, rightLines
, rStrHd, rStrTl, rLnHd, rLnTl
, helpGoToIdxRight
)
else
(* searchLine is in rStrHd/rLnHd, so return *)
{ idx = idx
, line = line
, leftStrings = leftStrings
, leftLines = leftLines
, rightStrings = rightStrings
, rightLines = rightLines
}
| (_, _) =>
(* right side is empty, so just return *)
{ idx = idx
, line = line
, leftStrings = leftStrings
, leftLines = leftLines
, rightStrings = []
, rightLines = []
}
fun goToIdx (searchIdx, buffer: t) =
let
val {idx, line, leftStrings, leftLines, rightStrings, rightLines} = buffer
in
if searchIdx < idx then
helpGoToIdxLeft
( idx
, line
, searchIdx
, leftStrings
, leftLines
, rightStrings
, rightLines
)
else if searchIdx > idx then
helpGoToIdxRight
( idx
, line
, searchIdx
, leftStrings
, leftLines
, rightStrings
, rightLines
)
else
buffer
end
(* TEST CODE *) (* TEST CODE *)
local local
fun lineBreaksToString vec = fun lineBreaksToString vec =