use concurrency for rebuilding search list after deletion so we don't block main thread on very, very large files

This commit is contained in:
2025-08-07 12:20:57 +01:00
parent fab8cfcf20
commit 704854c80f
10 changed files with 220 additions and 137 deletions

View File

@@ -9,6 +9,14 @@ struct
fun clearMode app =
AppWith.mode (app, NORMAL_MODE "", [])
fun withSearchList (app: app_type, searchList) =
let
val {buffer, searchString, cursorIdx, ...} = app
val app = AppWith.searchList (app, searchList, buffer, searchString)
in
Finish.buildTextAndClear (app, buffer, cursorIdx, searchList, [])
end
fun resizeText (app: app_type, newWidth, newHeight) =
let
val
@@ -33,6 +41,7 @@ struct
, newHeight
, searchList
, searchString
, []
)
in
AppWith.bufferAndSize
@@ -44,7 +53,8 @@ struct
* where the cursor may possibly jump off window by a wide marigin.
* Since the cursor may move away a lot, it is best to recenter.
* *)
fun buildTextAndClearAfterChr (app: app_type, buffer, cursorIdx, searchList) =
fun buildTextAndClearAfterChr
(app: app_type, buffer, cursorIdx, searchList, initialMsg) =
let
val {windowWidth, windowHeight, startLine, searchString, ...} = app
@@ -68,6 +78,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
val mode = NORMAL_MODE ""
@@ -104,6 +115,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
in
AppWith.bufferAndCursorIdx
@@ -129,6 +141,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
val mode = NORMAL_MODE ""
@@ -169,6 +182,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
val mode = NORMAL_MODE ""
@@ -211,6 +225,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
val mode = NORMAL_MODE ""
@@ -253,6 +268,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
in
AppWith.bufferAndCursorIdx
@@ -283,6 +299,7 @@ struct
, windowHeight
, searchList
, searchString
, []
)
in
AppWith.bufferAndCursorIdx
@@ -309,12 +326,12 @@ struct
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val cursorIdx = Cursor.firstNonSpaceChr (buffer, cursorIdx)
in
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app)
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app, [])
end
fun helpMoveToChr (app: app_type, buffer, cursorIdx, count, fMove, chr) =
if count = 0 then
buildTextAndClearAfterChr (app, buffer, cursorIdx, #searchList app)
buildTextAndClearAfterChr (app, buffer, cursorIdx, #searchList app, [])
else
let
(* move LineGap to cursorIdx, which is necessary for finding newCursorIdx *)
@@ -335,6 +352,7 @@ struct
CHAR_EVENT chr => moveToChr (app, count, fMove, chr)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
fun handleGo (count, app, newCmd) =
case newCmd of
@@ -346,12 +364,19 @@ struct
| _ => clearMode app)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
(* text-delete functions *)
(** equivalent of vi's 'x' command **)
fun helpRemoveChr (app: app_type, buffer, searchList, cursorIdx, count) =
fun helpRemoveChr (app: app_type, buffer, cursorIdx, count) =
if count = 0 then
Finish.buildTextAndClear (app, buffer, cursorIdx, searchList)
let
val buffer = LineGap.goToEnd buffer
val initialMsg = [SEARCH (buffer, #searchString app)]
in
Finish.buildTextAndClear
(app, buffer, cursorIdx, SearchList.empty, initialMsg)
end
else
let
val buffer = LineGap.goToIdx (cursorIdx, buffer)
@@ -374,9 +399,9 @@ struct
(* vi simply doesn't do anything on 'x' command
* when cursor is at start of line, and next chr is line break
* so skip to end of loop by passing count of 0 *)
helpRemoveChr (app, buffer, searchList, cursorIdx, 0)
helpRemoveChr (app, buffer, cursorIdx, 0)
else if cursorIsStart then
helpRemoveChr (app, buffer, searchList, cursorIdx, 0)
helpRemoveChr (app, buffer, cursorIdx, 0)
else if nextIsEnd then
let
(* delete char at cursor and then decrement cursorIdx by 1
@@ -384,8 +409,6 @@ struct
val searchString = #searchString app
val buffer = LineGap.delete (cursorIdx, 1, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
val cursorIdx =
if
Cursor.isPrevChrStartOfLine (buffer, cursorIdx)
@@ -393,21 +416,19 @@ struct
then cursorIdx
else cursorIdx - 1
in
helpRemoveChr (app, buffer, searchList, cursorIdx, count - 1)
helpRemoveChr (app, buffer, cursorIdx, count - 1)
end
else
let
val searchString = #searchString app
val buffer = LineGap.delete (cursorIdx, 1, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
in
helpRemoveChr (app, buffer, searchList, cursorIdx, count - 1)
helpRemoveChr (app, buffer, cursorIdx, count - 1)
end
end
fun removeChr (app: app_type, count) =
helpRemoveChr (app, #buffer app, #searchList app, #cursorIdx app, count)
helpRemoveChr (app, #buffer app, #cursorIdx app, count)
fun helpDelete (app: app_type, buffer, cursorIdx, otherIdx, count, fMove) =
(* As a small optimisation to reduce allocations,
@@ -426,8 +447,9 @@ struct
val buffer = LineGap.delete (low, length, buffer)
val buffer = LineGap.goToEnd buffer
val searchString = #searchString app
val (buffer, searchList) = SearchList.build (buffer, searchString)
val initialMsg = [SEARCH (buffer, searchString)]
(* If we have deleted from the buffer so that cursorIdx
* is no longer a valid idx,
@@ -435,7 +457,8 @@ struct
val buffer = LineGap.goToIdx (low, buffer)
val cursorIdx = Cursor.clipIdx (buffer, low)
in
Finish.buildTextAndClear (app, buffer, cursorIdx, searchList)
Finish.buildTextAndClear
(app, buffer, cursorIdx, SearchList.empty, initialMsg)
end
else
let
@@ -463,11 +486,12 @@ struct
val buffer = LineGap.delete (low, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
val buffer = LineGap.goToEnd buffer
val initialMsg = [SEARCH (buffer, searchString)]
val buffer = LineGap.goToIdx (low, buffer)
in
Finish.buildTextAndClear (app, buffer, low, searchList)
Finish.buildTextAndClear (app, buffer, low, SearchList.empty, initialMsg)
end
fun deleteToEndOfLine (app: app_type) =
@@ -489,12 +513,8 @@ struct
val lastChr = Cursor.viDlr (buffer, cursorIdx, 1)
val length = lastChr - cursorIdx
val buffer = LineGap.delete (cursorIdx, length, buffer)
(* delete from searchList and map *)
val searchString = #searchString app
val (buffer, searchList) = SearchList.build (buffer, searchString)
in
helpRemoveChr (app, buffer, searchList, cursorIdx, 1)
helpRemoveChr (app, buffer, cursorIdx, 1)
end
end
@@ -509,11 +529,13 @@ struct
val length = finishIdx - startIdx
val buffer = LineGap.delete (startIdx, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
val buffer = LineGap.goToEnd buffer
val initialMsg = [SEARCH (buffer, searchString)]
val buffer = LineGap.goToIdx (startIdx, buffer)
in
Finish.buildTextAndClear (app, buffer, startIdx, searchList)
Finish.buildTextAndClear
(app, buffer, startIdx, SearchList.empty, initialMsg)
end
fun helpDeleteLineBack (app, buffer, low, high, count) =
@@ -523,12 +545,14 @@ struct
val length = high - low
val buffer = LineGap.delete (low, length, buffer)
val buffer = LineGap.goToEnd buffer
val searchString = #searchString app
val (buffer, searchList) = SearchList.build (buffer, searchString)
val initialMsg = [SEARCH (buffer, searchString)]
val buffer = LineGap.goToIdx (low, buffer)
in
Finish.buildTextAndClear (app, buffer, low, searchList)
Finish.buildTextAndClear
(app, buffer, low, SearchList.empty, initialMsg)
end
else
let
@@ -575,9 +599,11 @@ struct
val length = high - low
val buffer = LineGap.delete (low, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
val buffer = LineGap.goToEnd buffer
val initialMsg = [SEARCH (buffer, searchString)]
in
Finish.buildTextAndClear (app, buffer, low, searchList)
Finish.buildTextAndClear (app, buffer, low, SearchList.empty, initialMsg)
end
fun helpDeleteToChr
@@ -589,10 +615,12 @@ struct
val length = high - low
val buffer = LineGap.delete (low, length, buffer)
val buffer = LineGap.goToEnd buffer
val searchString = #searchString app
val (buffer, searchList) = SearchList.build (buffer, searchString)
val initialMsg = [SEARCH (buffer, searchString)]
in
buildTextAndClearAfterChr (app, buffer, low, searchList)
buildTextAndClearAfterChr
(app, buffer, low, SearchList.empty, initialMsg)
end
else
let
@@ -625,6 +653,9 @@ struct
val buffer = LineGap.delete (0, cursorIdx, buffer)
val (buffer, searchList) = SearchList.build (buffer, searchString)
val buffer = LineGap.goToEnd buffer
val initialMsg = [SEARCH (buffer, #searchString app)]
val cursorIdx = 0
val startLine = 0
val buffer = LineGap.goToIdx (cursorIdx, buffer)
@@ -637,6 +668,7 @@ struct
, windowHeight
, searchList
, searchString
, initialMsg
)
val mode = NORMAL_MODE ""
@@ -767,6 +799,7 @@ struct
| _ => clearMode app)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
else
(* have to continue parsing string *)
case String.sub (str, strPos + 1) of
@@ -776,27 +809,31 @@ struct
CHAR_EVENT chr =>
deleteToChr (app, 1, Cursor.tillNextChr, op+, chr)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height))
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList))
| #"T" =>
(* delete till chr, backwards *)
(case newCmd of
CHAR_EVENT chr =>
deleteToChr (app, 1, Cursor.tillPrevChr, op-, chr)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height))
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList))
| #"f" =>
(case newCmd of
CHAR_EVENT chr =>
deleteToChr (app, count, Cursor.toNextChr, op+, chr)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height))
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList))
| #"F" =>
(* delete to chr, backwards *)
(case newCmd of
CHAR_EVENT chr =>
deleteToChr (app, count, Cursor.toPrevChr, op-, chr)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height))
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList))
| #"g" =>
(* same events as handleGo *)
(case newCmd of
@@ -807,7 +844,8 @@ struct
| #"g" => deleteToStart app
| _ => clearMode app)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height))
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList))
| _ => clearMode app
(* useful reference as list of non-terminal commands *)
@@ -849,6 +887,7 @@ struct
CHAR_EVENT chr => handleChr (app, 1, chr, str)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
else if String.size str = 1 then
case newCmd of
CHAR_EVENT chr =>
@@ -857,6 +896,7 @@ struct
| NONE => parseAfterCount (0, str, 1, app, newCmd))
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
else
let
val numLength = getNumLength (0, str)
@@ -872,6 +912,7 @@ struct
CHAR_EVENT chr => handleChr (app, count, chr, str)
| KEY_ESC => clearMode app
| RESIZE_EVENT (width, height) => resizeText (app, width, height)
| WITH_SEARCH_LIST searchList => withSearchList (app, searchList)
else
(* continue parsing. *)
parseAfterCount (numLength, str, count, app, newCmd)