From 7d1272180bd7d49459431de9a5ebd18219720244 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sun, 19 Oct 2025 14:30:26 +0100 Subject: [PATCH] remove 'Cursor.tillPrevChr', replacing usages of that function with 'Cursor.toPrevChr' --- fcore/cursor.sml | 252 ++--------------------- fcore/normal-mode/make-normal-delete.sml | 37 +++- fcore/normal-mode/normal-mode.sml | 32 +-- fcore/normal-mode/normal-move.sml | 28 +++ fcore/normal-mode/normal-yank.sml | 55 +++-- 5 files changed, 130 insertions(+), 274 deletions(-) diff --git a/fcore/cursor.sml b/fcore/cursor.sml index 2757166..6764693 100644 --- a/fcore/cursor.sml +++ b/fcore/cursor.sml @@ -196,114 +196,6 @@ struct fun firstNonSpaceChr (lineGap, cursorIdx) = FirstNonSpaceChr.foldPrev (lineGap, cursorIdx, ()) - fun helpToNextChr (strPos, str, absIdx, stl, ltl, origIdx, findChr) = - if strPos = String.size str then - case (stl, ltl) of - (shd :: stl, lhd :: ltl) => - helpToNextChr (0, shd, absIdx, stl, ltl, origIdx, findChr) - | (_, _) => origIdx - else if String.sub (str, strPos) = findChr then - absIdx - else - helpToNextChr (strPos + 1, str, absIdx + 1, stl, ltl, origIdx, findChr) - - fun startToNextChr (shd, strIdx, absIdx, stl, ltl, findChr) = - (* we want to start iterating from next char after strIdx *) - if strIdx - 1 < String.size shd then - helpToNextChr (strIdx + 1, shd, absIdx + 1, stl, ltl, absIdx, findChr) - else - case (stl, ltl) of - (stlhd :: stltl, ltlhd :: ltltl) => - helpToNextChr (0, stlhd, absIdx + 1, stltl, ltltl, absIdx, findChr) - | (_, _) => (* tl is empty; just return absIdx *) absIdx - - fun helpTillNextChr - (strPos, str, absIdx, stl, ltl, origIdx, findChr, lastNonLine, lastLine) = - if strPos = String.size str then - case (stl, ltl) of - (shd :: stl, lhd :: ltl) => - helpTillNextChr - (0, shd, absIdx, stl, ltl, origIdx, findChr, lastNonLine, lastLine) - | (_, _) => origIdx - else - let - val chr = String.sub (str, strPos) - in - if chr = findChr then - if lastLine = lastNonLine + 1 then - (* graphical-chr -> \n - * so return graphical-chr *) - lastNonLine - else - Int.max (lastLine, lastNonLine) - else - let - val lastLine = if chr = #"\n" then absIdx else lastLine - val lastNonLine = if chr = #"\n" then lastNonLine else absIdx - in - helpTillNextChr - ( strPos + 1 - , str - , absIdx + 1 - , stl - , ltl - , origIdx - , findChr - , lastNonLine - , lastLine - ) - end - end - - fun startTillNextChr (shd, strIdx, absIdx, stl, ltl, findChr) = - (* we want to start iterating from next char after strIdx *) - if strIdx + 1 < String.size shd then - helpTillNextChr - (strIdx + 1, shd, absIdx + 1, stl, ltl, absIdx, findChr, absIdx, absIdx) - else - case (stl, ltl) of - (stlhd :: stltl, ltlhd :: ltltl) => - helpTillNextChr - ( 0 - , stlhd - , absIdx + 1 - , stltl - , ltltl - , absIdx - , findChr - , absIdx - , absIdx - ) - | (_, _) => (* tl is empty; just return absIdx *) absIdx - - fun nextChr (lineGap: LineGap.t, cursorIdx, chr, fStart) = - 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 *) - fStart (shd, strIdx, cursorIdx, stl, ltl, chr) - else - (* strIdx is in tl *) - (case (stl, ltl) of - (stlhd :: stltl, ltlhd :: ltltl) => - let val strIdx = strIdx - String.size shd - in fStart (stlhd, strIdx, cursorIdx, stltl, ltltl, chr) - end - | (_, _) => cursorIdx) - end - | (_, _) => cursorIdx - end - - fun tillNextChr (lineGap, cursorIdx, chr) = - nextChr (lineGap, cursorIdx, chr, startTillNextChr) - structure ToNextChr = MakeIfCharFolderNext (struct @@ -356,148 +248,38 @@ struct structure ToPrevChr = MakeIfCharFolderPrev (struct - type env = char + type env = {findChr: char, count: int} - fun helpToPrevChr (strPos, str, absIdx, stl, origIdx, findChr) = + fun helpToPrevChr + (strPos, str, absIdx, stl, lastFoundIdx, findChr, count) = if strPos < 0 then case stl of shd :: stl => helpToPrevChr - (String.size shd - 1, shd, absIdx, stl, origIdx, findChr) - | [] => origIdx - else if String.sub (str, strPos) = findChr then - absIdx - else - helpToPrevChr (strPos - 1, str, absIdx - 1, stl, origIdx, findChr) - - fun fStart (strIdx, shd, _, absIdx, stl, _, findChr) = - (* we want to start iterating from Prev char after strIdx *) - if strIdx > 0 then - helpToPrevChr (strIdx - 1, shd, absIdx - 1, stl, absIdx, findChr) - else - case stl of - stlhd :: stltl => - helpToPrevChr - ( String.size stlhd - 1 - , stlhd - , absIdx - 1 - , stltl - , absIdx - , findChr - ) - | [] => (* tl is empty; return 0 for lineGap start *) 0 - end) - - val toPrevChr = ToPrevChr.foldPrev - - structure TillPrevChr = - MakeIfCharFolderPrev - (struct - type env = char - - fun helpTillPrevChr - ( strPos - , str - , absIdx - , stl - , origIdx - , findChr - , lastNonLine - , lastLine - , lastValid - ) = - if strPos < 0 then - case stl of - shd :: stl => - helpTillPrevChr ( String.size shd - 1 , shd , absIdx , stl - , origIdx + , lastFoundIdx , findChr - , lastNonLine - , lastLine - , lastValid + , count ) - | [] => origIdx + | [] => lastFoundIdx + else if String.sub (str, strPos) = findChr then + if count - 1 = 0 then + absIdx + else + helpToPrevChr + (strPos - 1, str, absIdx - 1, stl, absIdx, findChr, count - 1) else - let - val chr = String.sub (str, strPos) - in - if chr = findChr then - if lastLine = lastNonLine then lastNonLine - else if absIdx + 1 = lastLine then lastValid + 1 - else Int.min (lastLine, lastNonLine) - else - let - val lastLine = if chr = #"\n" then absIdx else lastLine - val lastNonLine = if chr = #"\n" then lastNonLine else absIdx + helpToPrevChr + (strPos - 1, str, absIdx - 1, stl, lastFoundIdx, findChr, count) - (* There is a slightly tricky edge case - * which is the reason the lastValid variable. - * Say we have a string "a\n\n\nbcd" - * and we type "Ta" with the cursor at the end. - * We want the cursor to go to the second line break - * because (graphical-chr -> \n) should not be selectable. - * However, with only lastLine and lastNonLine variables, - * we only have information about the most recent \n - * and the most recent graphical-chr. - * This means we don't have information about the case - * where a graphical-chr is followed by multiple '\n's. - * The lastValid variable keeps track of this information - * so we can use it to provide the expected behaviour. - * *) - val lastValid = - if lastLine = lastNonLine + 1 then lastLine + 1 - else Int.min (lastLine, lastNonLine) - in - helpTillPrevChr - ( strPos - 1 - , str - , absIdx - 1 - , stl - , origIdx - , findChr - , lastNonLine - , lastLine - , lastValid - ) - end - end - - fun fStart (strIdx, shd, _, absIdx, stl, ltl, findChr) = - (* we want to start iterating from Prev char after strIdx *) - if strIdx > 0 then - helpTillPrevChr - ( strIdx - 1 - , shd - , absIdx - 1 - , stl - , absIdx - , findChr - , absIdx - , absIdx - , absIdx - ) - else - case stl of - stlhd :: stltl => - helpTillPrevChr - ( String.size stlhd - 1 - , stlhd - , absIdx - 1 - , stltl - , absIdx - , findChr - , absIdx - , absIdx - , absIdx - ) - | [] => (* tl is empty; return 0 for lineGap start *) 0 + fun fStart (strIdx, shd, _, absIdx, stl, _, {findChr, count}) = + helpToPrevChr (strIdx - 1, shd, absIdx - 1, stl, ~1, findChr, count) end) - val tillPrevChr = TillPrevChr.foldPrev + val toPrevChr = ToPrevChr.foldPrev fun helpMatchPairNext (strPos, str, absIdx, stl, origIdx, openChr, openNum, closeChr, closeNum) = diff --git a/fcore/normal-mode/make-normal-delete.sml b/fcore/normal-mode/make-normal-delete.sml index 512ede8..bdd663a 100644 --- a/fcore/normal-mode/make-normal-delete.sml +++ b/fcore/normal-mode/make-normal-delete.sml @@ -757,6 +757,39 @@ struct end end + fun deleteToPrevChr (app: app_type, count, chr, time) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + let val length = cursorIdx - newCursorIdx + in deleteAndFinish (app, newCursorIdx, length, buffer, time) + end + end + + fun deleteTillPrevChr (app: app_type, count, chr, time) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val low = newCursorIdx + 1 + val length = cursorIdx - newCursorIdx - 1 + in + deleteAndFinish (app, low, length, buffer, time) + end + end + fun deleteToStart (app: app_type, time) : AppType.app_type = let val {cursorIdx, buffer, windowWidth, windowHeight, dfa, ...} = app @@ -964,7 +997,7 @@ struct val start = cursorIdx + 1 val buffer = LineGap.goToIdx (start, buffer) - val origLow = Cursor.toPrevChr (buffer, start, chr) + val origLow = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1}) val buffer = LineGap.goToIdx (origLow, buffer) val high = Cursor.matchPair (buffer, origLow) in @@ -1007,7 +1040,7 @@ struct val start = cursorIdx + 1 val buffer = LineGap.goToIdx (start, buffer) - val low = Cursor.toPrevChr (buffer, start, chr) + val low = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1}) val buffer = LineGap.goToIdx (low, buffer) val high = Cursor.matchPair (buffer, low) in diff --git a/fcore/normal-mode/normal-mode.sml b/fcore/normal-mode/normal-mode.sml index 3631603..0bedd94 100644 --- a/fcore/normal-mode/normal-mode.sml +++ b/fcore/normal-mode/normal-mode.sml @@ -132,9 +132,6 @@ struct end end - fun parseMoveToChr (count, app, fMove, chrCmd) = - NormalMove.moveToChr (app, count, fMove, chrCmd) - fun parseGo (count, app, chrCmd) = case chrCmd of #"e" => MoveToEndOfPrevWord.move (app, count) @@ -299,13 +296,9 @@ struct (* have to continue parsing string *) case String.sub (str, strPos + 1) of #"t" => NormalDelete.deleteTillNextChr (app, count, chrCmd, time) - | #"T" => - NormalDelete.deleteToChr - (app, 1, Cursor.tillPrevChr, op-, chrCmd, time) + | #"T" => NormalDelete.deleteTillPrevChr (app, count, chrCmd, time) | #"f" => NormalDelete.deleteToNextChr (app, count, chrCmd, time) - | #"F" => - NormalDelete.deleteToChr - (app, count, Cursor.toPrevChr, op-, chrCmd, time) + | #"F" => NormalDelete.deleteToPrevChr (app, count, chrCmd, time) | #"g" => parseDeleteGo (app, count, chrCmd, time) | #"i" => parseDeleteInside (app, chrCmd, time) | #"a" => parseDeleteAround (app, chrCmd, time) @@ -394,13 +387,9 @@ struct (* have to continue parsing string *) case String.sub (str, strPos + 1) of #"t" => NormalYankDelete.deleteTillNextChr (app, count, chrCmd, time) - | #"T" => - NormalYankDelete.deleteToChr - (app, 1, Cursor.tillPrevChr, op-, chrCmd, time) + | #"T" => NormalYankDelete.deleteTillPrevChr (app, count, chrCmd, time) | #"f" => NormalYankDelete.deleteToNextChr (app, count, chrCmd, time) - | #"F" => - NormalYankDelete.deleteToChr - (app, count, Cursor.toPrevChr, op-, chrCmd, time) + | #"F" => NormalYankDelete.deleteToPrevChr (app, count, chrCmd, time) | #"g" => parseDeleteGo (app, count, chrCmd, time) | #"i" => parseDeleteInside (app, chrCmd, time) | #"a" => parseDeleteAround (app, chrCmd, time) @@ -530,10 +519,9 @@ struct else case String.sub (str, strPos + 1) of #"t" => NormalYank.yankTillNextChr (app, count, chrCmd) - | #"T" => NormalYank.yankToChr (app, 1, Cursor.tillPrevChr, op-, chrCmd) + | #"T" => NormalYank.yankTillPrevChr (app, count, chrCmd) | #"f" => NormalYank.yankToNextChr (app, count, chrCmd) - | #"F" => - NormalYank.yankToChr (app, count, Cursor.toPrevChr, op-, chrCmd) + | #"F" => NormalYank.yankToPrevChr (app, count, chrCmd) | #"g" => parseYankGo (count, app, chrCmd) | #"i" => parseYankInside (app, chrCmd) | #"a" => parseYankAround (app, chrCmd) @@ -553,15 +541,11 @@ struct * *) case String.sub (str, strPos) of #"t" => NormalMove.tillNextChr (app, count, chrCmd) - | #"T" => - (* to just before chr, backward *) - parseMoveToChr (1, app, Cursor.tillPrevChr, chrCmd) + | #"T" => NormalMove.tillPrevChr (app, count, chrCmd) | #"y" => ParseYank.parseYank (strPos, str, count, app, chrCmd, time) | #"d" => ParseDelete.parseDelete (strPos, str, count, app, chrCmd, time) | #"f" => NormalMove.toNextChr (app, count, chrCmd) - | #"F" => - (* to chr, backward *) - parseMoveToChr (count, app, Cursor.toPrevChr, chrCmd) + | #"F" => NormalMove.toPrevChr (app, count, chrCmd) | #"g" => (* go *) parseGo (count, app, chrCmd) | #"c" => (* change *) NormalFinish.clearMode app | _ => diff --git a/fcore/normal-mode/normal-move.sml b/fcore/normal-mode/normal-move.sml index d2285c4..b6d01de 100644 --- a/fcore/normal-mode/normal-move.sml +++ b/fcore/normal-mode/normal-move.sml @@ -544,4 +544,32 @@ struct NormalFinish.buildTextAndClear (app, buffer, newCursorIdx - 1, searchList, [], bufferModifyTime) end + + fun toPrevChr (app: app_type, count, chr) = + let + val {cursorIdx, buffer, searchList, bufferModifyTime, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + NormalFinish.buildTextAndClear + (app, buffer, newCursorIdx, searchList, [], bufferModifyTime) + end + + fun tillPrevChr (app: app_type, count, chr) = + let + val {cursorIdx, buffer, searchList, bufferModifyTime, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + NormalFinish.buildTextAndClear + (app, buffer, newCursorIdx + 1, searchList, [], bufferModifyTime) + end end diff --git a/fcore/normal-mode/normal-yank.sml b/fcore/normal-mode/normal-yank.sml index 10be36f..c02978a 100644 --- a/fcore/normal-mode/normal-yank.sml +++ b/fcore/normal-mode/normal-yank.sml @@ -272,17 +272,46 @@ struct end end - fun yankToChr (app: app_type, count, fMove, fInc, chr) = - helpYankToChr - ( app - , #buffer app - , #cursorIdx app - , #cursorIdx app - , count - , fMove - , fInc - , chr - ) + fun yankToPrevChr (app: app_type, count, chr) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val length = cursorIdx - newCursorIdx + val str = LineGap.substring (newCursorIdx, length, buffer) + val msg = YANK str + val mode = NORMAL_MODE "" + in + NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg]) + end + end + + fun yankTillPrevChr (app: app_type, count, chr) = + let + val {buffer, cursorIdx, ...} = app + val buffer = LineGap.goToIdx (cursorIdx, buffer) + val newCursorIdx = + Cursor.toPrevChr (buffer, cursorIdx, {findChr = chr, count = count}) + in + if newCursorIdx = ~1 then + NormalFinish.clearMode app + else + let + val newCursorIdx = newCursorIdx + 1 + val length = cursorIdx - newCursorIdx + val str = LineGap.substring (newCursorIdx, length, buffer) + val msg = YANK str + val mode = NORMAL_MODE "" + in + NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg]) + end + end fun yankToStart (app: app_type) = let @@ -354,7 +383,7 @@ struct val start = cursorIdx + 1 val buffer = LineGap.goToIdx (start, buffer) - val low = Cursor.toPrevChr (buffer, start, chr) + val low = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1}) val buffer = LineGap.goToIdx (low, buffer) val high = Cursor.matchPair (buffer, low) val buffer = LineGap.goToIdx (high, buffer) @@ -386,7 +415,7 @@ struct val start = cursorIdx + 1 val buffer = LineGap.goToIdx (start, buffer) - val low = Cursor.toPrevChr (buffer, start, chr) + val low = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1}) val buffer = LineGap.goToIdx (low, buffer) val high = Cursor.matchPair (buffer, low) + 1 val buffer = LineGap.goToIdx (high, buffer)