add function to move to specific line number (or the node containing a specific line number if node contains multiple line breaks)

This commit is contained in:
2024-10-05 23:01:19 +01:00
parent 36edbb6dee
commit d4ef45630d

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 goToLine: int * t -> t
(* for testing *) (* for testing *)
val verifyIndex: t -> unit val verifyIndex: t -> unit
@@ -2008,6 +2009,182 @@ 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
(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 *)
(case (rightStrings, rightLines) of
(rStrHd :: rStrTl, rLnHd :: rLnTl) =>
if isInLimit (lStrHd, rStrHd, lLnHd, rLnHd) then
(* join into a single node before moving *)
let
val newRstrHd = lStrHd ^ rStrHd
val newRlnHd =
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
helpGoToLineLeft
( idx - String.size lStrHd
, line - Vector.length lLnHd
, searchLine
, lStrTl
, lLnTl
, newRstrHd :: rStrTl
, newRlnHd :: rLnTl
)
end
else
(* move without joining *)
helpGoToLineLeft
( idx - String.size lStrHd
, line - Vector.length lLnHd
, searchLine
, lStrTl
, lLnTl
, lStrHd :: rightStrings
, lLnHd :: rightLines
)
| (_, _) =>
(* right side is empty, so just move left without joining *)
helpGoToLineLeft
( idx - String.size lStrHd
, line - Vector.length lLnHd
, searchLine
, lStrTl
, lLnTl
, [lStrHd]
, [lLnHd]
))
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 helpGoToLineRight
(idx, line, searchLine, leftStrings, leftLines, rightStrings, rightLines) =
case (rightStrings, rightLines) of
(rStrHd :: rStrTl, rLnHd :: rLnTl) =>
if searchLine > line + Vector.length rLnHd then
(* have to move rightwards *)
(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
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
(* 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 goToLine (searchLine, buffer: t) =
let
val {idx, line, leftStrings, leftLines, rightStrings, rightLines} = buffer
in
if searchLine < idx then
helpGoToLineLeft
( idx
, line
, searchLine
, leftStrings
, leftLines
, rightStrings
, rightLines
)
else if searchLine > idx then
helpGoToLineRight
( idx
, line
, searchLine
, leftStrings
, leftLines
, rightStrings
, rightLines
)
else
buffer
end
(* TEST CODE *) (* TEST CODE *)
local local
fun lineBreaksToString vec = fun lineBreaksToString vec =