pass higher order function to word motions, for less code duplication

This commit is contained in:
2024-10-25 21:27:58 +01:00
parent 39e867bd35
commit 7a62ad3afc
2 changed files with 51 additions and 149 deletions

View File

@@ -443,9 +443,7 @@ struct
else else
case String.sub (str, strPos) of case String.sub (str, strPos) of
#"\n" => #"\n" =>
if if hasPassedLine then
hasPassedLine
then
(* reached end of line twice, (* reached end of line twice,
* but line has fewer chars than preferredColumn * but line has fewer chars than preferredColumn
* note: if in double \n\n linebreak, * note: if in double \n\n linebreak,
@@ -939,31 +937,6 @@ struct
helpNextWord (strPos + 1, str, absIdx + 1, strTl, lineTl) helpNextWord (strPos + 1, str, absIdx + 1, strTl, lineTl)
end end
fun nextWord (lineGap: LineGap.t, cursorIdx) =
let
val {rightStrings, rightLines, idx = bufferIdx, ...} = lineGap
in
case (rightStrings, rightLines) of
(shd :: stl, lhd :: ltl) =>
let
(* convert absolute cursorIdx to idx relative to hd string *)
val strIdx = cursorIdx - bufferIdx
in
if strIdx < String.size shd then
(* strIdx is in this string *)
helpNextWord (strIdx, shd, cursorIdx, stl, ltl)
else
(* strIdx is in tl *)
(case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) =>
let val strIdx = strIdx - String.size shd
in helpNextWord (strIdx, shd, cursorIdx, stl, ltl)
end
| (_, _) => cursorIdx)
end
| (_, _) => cursorIdx
end
fun helpNextWORD (strPos, str, absIdx, strTl, lineTl) = fun helpNextWORD (strPos, str, absIdx, strTl, lineTl) =
if strPos = String.size str then if strPos = String.size str then
case (strTl, lineTl) of case (strTl, lineTl) of
@@ -986,9 +959,7 @@ struct
helpNextWORD (strPos + 1, str, absIdx + 1, strTl, lineTl) helpNextWORD (strPos + 1, str, absIdx + 1, strTl, lineTl)
end end
(* equivalent of vi's W, fun toNextWord (lineGap: LineGap.t, cursorIdx, fNext) =
* which goes to next WORD rather than word *)
fun nextWORD (lineGap: LineGap.t, cursorIdx) =
let let
val {rightStrings, rightLines, idx = bufferIdx, ...} = lineGap val {rightStrings, rightLines, idx = bufferIdx, ...} = lineGap
in in
@@ -1000,19 +971,27 @@ struct
in in
if strIdx < String.size shd then if strIdx < String.size shd then
(* strIdx is in this string *) (* strIdx is in this string *)
helpNextWORD (strIdx, shd, cursorIdx, stl, ltl) fNext (strIdx, shd, cursorIdx, stl, ltl)
else else
(* strIdx is in tl *) (* strIdx is in tl *)
(case (stl, ltl) of (case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) => (stlhd :: stltl, ltlhd :: ltltl) =>
let val strIdx = strIdx - String.size shd let val strIdx = strIdx - String.size shd
in helpNextWORD (strIdx, shd, cursorIdx, stl, ltl) in fNext (strIdx, shd, cursorIdx, stl, ltl)
end end
| (_, _) => cursorIdx) | (_, _) => cursorIdx)
end end
| (_, _) => cursorIdx | (_, _) => cursorIdx
end end
(* equivalent 'f vi's 'w' command *)
fun nextWord (lineGap, cursorIdx) =
toNextWord (lineGap, cursorIdx, helpNextWord)
(* equivalent 'f vi's 'W' command *)
fun nextWORD (lineGap, cursorIdx) =
toNextWord (lineGap, cursorIdx, helpNextWORD)
fun helpPrevWord (strPos, str, absIdx, strTl, lineTl) = fun helpPrevWord (strPos, str, absIdx, strTl, lineTl) =
if strPos < 0 then if strPos < 0 then
case (strTl, lineTl) of case (strTl, lineTl) of
@@ -1026,16 +1005,12 @@ struct
let let
val chr = String.sub (str, strPos) val chr = String.sub (str, strPos)
in in
if if Char.isAlphaNum chr orelse chr = #"_" then
Char.isAlphaNum chr orelse chr = #"_"
then
if isPrevChrSpace (strPos, str, strTl) if isPrevChrSpace (strPos, str, strTl)
orelse isPrevChrNonBlank (strPos, str, strTl) orelse isPrevChrNonBlank (strPos, str, strTl)
then absIdx then absIdx
else helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl) else helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl)
else if else if Char.isSpace chr then
Char.isSpace chr
then
helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl) helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl)
else else
(* is NON_BLANK *) (* is NON_BLANK *)
@@ -1047,55 +1022,6 @@ struct
helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl) helpPrevWord (strPos - 1, str, absIdx - 1, strTl, lineTl)
end end
fun startPrevWord (shd, strIdx, absIdx, stl, ltl) =
(* we want to start iterating from previous character
* and ignore the character the cursor is at
* so check previous character *)
if strIdx > 0 then
helpPrevWord (strIdx - 1, shd, absIdx - 1, stl, ltl)
else
case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) =>
let val prevIdx = String.size stlhd - 1
in helpPrevWord (prevIdx, stlhd, absIdx - 1, stltl, ltltl)
end
| (_, _) =>
(* tl is empty; just return idx 0 *)
0
(* equivalent of vi's `b` command *)
fun prevWord (lineGap: LineGap.t, cursorIdx) =
let
val
{rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} =
lineGap
in
case (rightStrings, rightLines) of
(shd :: stl, lhd :: ltl) =>
let
(* convert absolute cursorIdx to idx relative to hd string *)
val strIdx = cursorIdx - bufferIdx
in
if strIdx < String.size shd then
(* strIdx is in this string *)
startPrevWord (shd, strIdx, cursorIdx, leftStrings, leftLines)
else
(* strIdx is in tl *)
(case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) =>
let
val strIdx = strIdx - String.size shd
val leftStrings = shd :: leftStrings
val leftLines = lhd :: leftLines
in
startPrevWord
(stlhd, strIdx, cursorIdx, leftStrings, leftLines)
end
| (_, _) => cursorIdx)
end
| (_, _) => cursorIdx
end
fun helpPrevWORD (strPos, str, absIdx, strTl, lineTl) = fun helpPrevWORD (strPos, str, absIdx, strTl, lineTl) =
if strPos < 0 then if strPos < 0 then
case (strTl, lineTl) of case (strTl, lineTl) of
@@ -1120,24 +1046,23 @@ struct
(strPos - 1, str, absIdx - 1, strTl, lineTl) (strPos - 1, str, absIdx - 1, strTl, lineTl)
end end
fun startPrevWORD (shd, strIdx, absIdx, stl, ltl) = fun startPrevWord (shd, strIdx, absIdx, stl, ltl, fPrev) =
(* we want to start iterating from previous character (* we want to start iterating from previous character
* and ignore the character the cursor is at * and ignore the character the cursor is at
* so check previous character *) * so check previous character *)
if strIdx > 0 then if strIdx > 0 then
helpPrevWORD (strIdx - 1, shd, absIdx - 1, stl, ltl) fPrev (strIdx - 1, shd, absIdx - 1, stl, ltl)
else else
case (stl, ltl) of case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) => (stlhd :: stltl, ltlhd :: ltltl) =>
let val prevIdx = String.size stlhd - 1 let val prevIdx = String.size stlhd - 1
in helpPrevWORD (prevIdx, stlhd, absIdx - 1, stltl, ltltl) in fPrev (prevIdx, stlhd, absIdx - 1, stltl, ltltl)
end end
| (_, _) => | (_, _) =>
(* tl is empty; just return idx 0 *) (* tl is empty; just return idx 0 *)
0 0
(* equivalent of vi's `B` command *) fun toPrevWord (lineGap: LineGap.t, cursorIdx, fPrev) =
fun prevWORD (lineGap: LineGap.t, cursorIdx) =
let let
val val
{rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} = {rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} =
@@ -1151,7 +1076,8 @@ struct
in in
if strIdx < String.size shd then if strIdx < String.size shd then
(* strIdx is in this string *) (* strIdx is in this string *)
startPrevWORD (shd, strIdx, cursorIdx, leftStrings, leftLines) startPrevWord
(shd, strIdx, cursorIdx, leftStrings, leftLines, fPrev)
else else
(* strIdx is in tl *) (* strIdx is in tl *)
(case (stl, ltl) of (case (stl, ltl) of
@@ -1161,14 +1087,22 @@ struct
val leftStrings = shd :: leftStrings val leftStrings = shd :: leftStrings
val leftLines = lhd :: leftLines val leftLines = lhd :: leftLines
in in
startPrevWORD startPrevWord
(stlhd, strIdx, cursorIdx, leftStrings, leftLines) (stlhd, strIdx, cursorIdx, leftStrings, leftLines, fPrev)
end end
| (_, _) => cursorIdx) | (_, _) => cursorIdx)
end end
| (_, _) => cursorIdx | (_, _) => cursorIdx
end end
(* equivalent of vi's 'b' command *)
fun prevWord (lineGap, cursorIdx) =
toPrevWord (lineGap, cursorIdx, helpPrevWord)
(* equivalent of vi's 'B' command *)
fun prevWORD (lineGap, cursorIdx) =
toPrevWord (lineGap, cursorIdx, helpPrevWORD)
fun helpEndOfWord (strPos, str, absIdx, stl, ltl) = fun helpEndOfWord (strPos, str, absIdx, stl, ltl) =
if strPos = String.size str then if strPos = String.size str then
case (stl, ltl) of case (stl, ltl) of
@@ -1178,16 +1112,12 @@ struct
let let
val chr = String.sub (str, strPos) val chr = String.sub (str, strPos)
in in
if if Char.isAlphaNum chr orelse chr = #"_" then
Char.isAlphaNum chr orelse chr = #"_"
then
if isNextChrSpace (strPos, str, stl) if isNextChrSpace (strPos, str, stl)
orelse isNextChrNonBlank (strPos, str, stl) orelse isNextChrNonBlank (strPos, str, stl)
then absIdx then absIdx
else helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl) else helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl)
else if else if Char.isSpace chr then
Char.isSpace chr
then
helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl) helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl)
else else
(* is NON_BLANK *) (* is NON_BLANK *)
@@ -1199,45 +1129,6 @@ struct
helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl) helpEndOfWord (strPos + 1, str, absIdx + 1, stl, ltl)
end end
fun startEndOfWord (shd, strIdx, absIdx, stl, ltl) =
(* we want to start iterating from next char after strIdx *)
if strIdx - 1 < String.size shd then
helpEndOfWord (strIdx + 1, shd, absIdx + 1, stl, ltl)
else
case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) =>
helpEndOfWord (0, stlhd, absIdx + 1, stltl, ltltl)
| (_, _) =>
(* tl is empty; just return absIdx *)
absIdx
(* equivalent of vi's `e` command *)
fun endOfWord (lineGap: LineGap.t, cursorIdx) =
let
val
{rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} =
lineGap
in
case (rightStrings, rightLines) of
(shd :: stl, lhd :: ltl) =>
let
val strIdx = cursorIdx - bufferIdx
in
if strIdx < String.size shd then
(* strIdx is in this string *)
startEndOfWord (shd, strIdx, cursorIdx, rightStrings, rightLines)
else
(* strIdx is in tl *)
(case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) =>
let val strIdx = strIdx - String.size shd
in startEndOfWord (stlhd, strIdx, cursorIdx, stltl, ltltl)
end
| (_, _) => cursorIdx)
end
| (_, _) => cursorIdx
end
fun helpEndOfWORD (strPos, str, absIdx, stl, ltl) = fun helpEndOfWORD (strPos, str, absIdx, stl, ltl) =
if strPos = String.size str then if strPos = String.size str then
case (stl, ltl) of case (stl, ltl) of
@@ -1256,20 +1147,19 @@ struct
helpEndOfWORD (strPos + 1, str, absIdx + 1, stl, ltl) helpEndOfWORD (strPos + 1, str, absIdx + 1, stl, ltl)
end end
fun startEndOfWORD (shd, strIdx, absIdx, stl, ltl) = fun startEndOfWord (shd, strIdx, absIdx, stl, ltl, fEnd) =
(* we want to start iterating from next char after strIdx *) (* we want to start iterating from next char after strIdx *)
if strIdx - 1 < String.size shd then if strIdx - 1 < String.size shd then
helpEndOfWORD (strIdx + 1, shd, absIdx + 1, stl, ltl) fEnd (strIdx + 1, shd, absIdx + 1, stl, ltl)
else else
case (stl, ltl) of case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) => (stlhd :: stltl, ltlhd :: ltltl) =>
helpEndOfWORD (0, stlhd, absIdx + 1, stltl, ltltl) fEnd (0, stlhd, absIdx + 1, stltl, ltltl)
| (_, _) => | (_, _) =>
(* tl is empty; just return absIdx *) (* tl is empty; just return absIdx *)
absIdx absIdx
(* equivalent of vi's `E` command *) fun toEndOfWord (lineGap: LineGap.t, cursorIdx, fEnd) =
fun endOfWORD (lineGap: LineGap.t, cursorIdx) =
let let
val val
{rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} = {rightStrings, rightLines, leftStrings, leftLines, idx = bufferIdx, ...} =
@@ -1282,16 +1172,28 @@ struct
in in
if strIdx < String.size shd then if strIdx < String.size shd then
(* strIdx is in this string *) (* strIdx is in this string *)
startEndOfWORD (shd, strIdx, cursorIdx, rightStrings, rightLines) startEndOfWord
(shd, strIdx, cursorIdx, rightStrings, rightLines, fEnd)
else else
(* strIdx is in tl *) (* strIdx is in tl *)
(case (stl, ltl) of (case (stl, ltl) of
(stlhd :: stltl, ltlhd :: ltltl) => (stlhd :: stltl, ltlhd :: ltltl) =>
let val strIdx = strIdx - String.size shd let
in startEndOfWORD (stlhd, strIdx, cursorIdx, stltl, ltltl) val strIdx = strIdx - String.size shd
in
startEndOfWord
(stlhd, strIdx, cursorIdx, stltl, ltltl, fEnd)
end end
| (_, _) => cursorIdx) | (_, _) => cursorIdx)
end end
| (_, _) => cursorIdx | (_, _) => cursorIdx
end end
(* equivalent of vi's `e` command *)
fun endOfWord (lineGap, cursorIdx) =
toEndOfWord (lineGap, cursorIdx, helpEndOfWord)
(* equivalent of vi's `E` command *)
fun endOfWORD (lineGap, cursorIdx) =
toEndOfWord (lineGap, cursorIdx, helpEndOfWORD)
end end

BIN
shf

Binary file not shown.