abstract reusable function from goToLine so it can be used in goToIdx, and implement goToIdx
This commit is contained in:
256
src/line_gap.sml
256
src/line_gap.sml
@@ -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 =
|
||||||
|
|||||||
Reference in New Issue
Block a user