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:
@@ -9,6 +9,14 @@ struct
|
|||||||
fun clearMode app =
|
fun clearMode app =
|
||||||
AppWith.mode (app, NORMAL_MODE "", [])
|
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) =
|
fun resizeText (app: app_type, newWidth, newHeight) =
|
||||||
let
|
let
|
||||||
val
|
val
|
||||||
@@ -33,6 +41,7 @@ struct
|
|||||||
, newHeight
|
, newHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
AppWith.bufferAndSize
|
AppWith.bufferAndSize
|
||||||
@@ -44,7 +53,8 @@ struct
|
|||||||
* where the cursor may possibly jump off window by a wide marigin.
|
* 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.
|
* 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
|
let
|
||||||
val {windowWidth, windowHeight, startLine, searchString, ...} = app
|
val {windowWidth, windowHeight, startLine, searchString, ...} = app
|
||||||
|
|
||||||
@@ -68,6 +78,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
@@ -104,6 +115,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
AppWith.bufferAndCursorIdx
|
AppWith.bufferAndCursorIdx
|
||||||
@@ -129,6 +141,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
@@ -169,6 +182,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
@@ -211,6 +225,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
@@ -253,6 +268,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
AppWith.bufferAndCursorIdx
|
AppWith.bufferAndCursorIdx
|
||||||
@@ -283,6 +299,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, []
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
AppWith.bufferAndCursorIdx
|
AppWith.bufferAndCursorIdx
|
||||||
@@ -309,12 +326,12 @@ struct
|
|||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
||||||
val cursorIdx = Cursor.firstNonSpaceChr (buffer, cursorIdx)
|
val cursorIdx = Cursor.firstNonSpaceChr (buffer, cursorIdx)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app)
|
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
fun helpMoveToChr (app: app_type, buffer, cursorIdx, count, fMove, chr) =
|
fun helpMoveToChr (app: app_type, buffer, cursorIdx, count, fMove, chr) =
|
||||||
if count = 0 then
|
if count = 0 then
|
||||||
buildTextAndClearAfterChr (app, buffer, cursorIdx, #searchList app)
|
buildTextAndClearAfterChr (app, buffer, cursorIdx, #searchList app, [])
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
(* move LineGap to cursorIdx, which is necessary for finding newCursorIdx *)
|
(* move LineGap to cursorIdx, which is necessary for finding newCursorIdx *)
|
||||||
@@ -335,6 +352,7 @@ struct
|
|||||||
CHAR_EVENT chr => moveToChr (app, count, fMove, chr)
|
CHAR_EVENT chr => moveToChr (app, count, fMove, chr)
|
||||||
| KEY_ESC => 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)
|
||||||
|
|
||||||
fun handleGo (count, app, newCmd) =
|
fun handleGo (count, app, newCmd) =
|
||||||
case newCmd of
|
case newCmd of
|
||||||
@@ -346,12 +364,19 @@ struct
|
|||||||
| _ => clearMode app)
|
| _ => clearMode app)
|
||||||
| KEY_ESC => 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)
|
||||||
|
|
||||||
(* text-delete functions *)
|
(* text-delete functions *)
|
||||||
(** equivalent of vi's 'x' command **)
|
(** 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
|
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
|
else
|
||||||
let
|
let
|
||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
||||||
@@ -374,9 +399,9 @@ struct
|
|||||||
(* vi simply doesn't do anything on 'x' command
|
(* vi simply doesn't do anything on 'x' command
|
||||||
* when cursor is at start of line, and next chr is line break
|
* when cursor is at start of line, and next chr is line break
|
||||||
* so skip to end of loop by passing count of 0 *)
|
* 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
|
else if cursorIsStart then
|
||||||
helpRemoveChr (app, buffer, searchList, cursorIdx, 0)
|
helpRemoveChr (app, buffer, cursorIdx, 0)
|
||||||
else if nextIsEnd then
|
else if nextIsEnd then
|
||||||
let
|
let
|
||||||
(* delete char at cursor and then decrement cursorIdx by 1
|
(* delete char at cursor and then decrement cursorIdx by 1
|
||||||
@@ -384,8 +409,6 @@ struct
|
|||||||
val searchString = #searchString app
|
val searchString = #searchString app
|
||||||
val buffer = LineGap.delete (cursorIdx, 1, buffer)
|
val buffer = LineGap.delete (cursorIdx, 1, buffer)
|
||||||
|
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
|
||||||
|
|
||||||
val cursorIdx =
|
val cursorIdx =
|
||||||
if
|
if
|
||||||
Cursor.isPrevChrStartOfLine (buffer, cursorIdx)
|
Cursor.isPrevChrStartOfLine (buffer, cursorIdx)
|
||||||
@@ -393,21 +416,19 @@ struct
|
|||||||
then cursorIdx
|
then cursorIdx
|
||||||
else cursorIdx - 1
|
else cursorIdx - 1
|
||||||
in
|
in
|
||||||
helpRemoveChr (app, buffer, searchList, cursorIdx, count - 1)
|
helpRemoveChr (app, buffer, cursorIdx, count - 1)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
val searchString = #searchString app
|
val searchString = #searchString app
|
||||||
val buffer = LineGap.delete (cursorIdx, 1, buffer)
|
val buffer = LineGap.delete (cursorIdx, 1, buffer)
|
||||||
|
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
|
||||||
in
|
in
|
||||||
helpRemoveChr (app, buffer, searchList, cursorIdx, count - 1)
|
helpRemoveChr (app, buffer, cursorIdx, count - 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fun removeChr (app: app_type, count) =
|
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) =
|
fun helpDelete (app: app_type, buffer, cursorIdx, otherIdx, count, fMove) =
|
||||||
(* As a small optimisation to reduce allocations,
|
(* As a small optimisation to reduce allocations,
|
||||||
@@ -426,8 +447,9 @@ struct
|
|||||||
|
|
||||||
val buffer = LineGap.delete (low, length, buffer)
|
val buffer = LineGap.delete (low, length, buffer)
|
||||||
|
|
||||||
|
val buffer = LineGap.goToEnd buffer
|
||||||
val searchString = #searchString app
|
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
|
(* If we have deleted from the buffer so that cursorIdx
|
||||||
* is no longer a valid idx,
|
* is no longer a valid idx,
|
||||||
@@ -435,7 +457,8 @@ struct
|
|||||||
val buffer = LineGap.goToIdx (low, buffer)
|
val buffer = LineGap.goToIdx (low, buffer)
|
||||||
val cursorIdx = Cursor.clipIdx (buffer, low)
|
val cursorIdx = Cursor.clipIdx (buffer, low)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, cursorIdx, searchList)
|
Finish.buildTextAndClear
|
||||||
|
(app, buffer, cursorIdx, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
@@ -463,11 +486,12 @@ struct
|
|||||||
|
|
||||||
val buffer = LineGap.delete (low, length, buffer)
|
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)
|
val buffer = LineGap.goToIdx (low, buffer)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, low, searchList)
|
Finish.buildTextAndClear (app, buffer, low, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun deleteToEndOfLine (app: app_type) =
|
fun deleteToEndOfLine (app: app_type) =
|
||||||
@@ -489,12 +513,8 @@ struct
|
|||||||
val lastChr = Cursor.viDlr (buffer, cursorIdx, 1)
|
val lastChr = Cursor.viDlr (buffer, cursorIdx, 1)
|
||||||
val length = lastChr - cursorIdx
|
val length = lastChr - cursorIdx
|
||||||
val buffer = LineGap.delete (cursorIdx, length, buffer)
|
val buffer = LineGap.delete (cursorIdx, length, buffer)
|
||||||
|
|
||||||
(* delete from searchList and map *)
|
|
||||||
val searchString = #searchString app
|
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
|
||||||
in
|
in
|
||||||
helpRemoveChr (app, buffer, searchList, cursorIdx, 1)
|
helpRemoveChr (app, buffer, cursorIdx, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -509,11 +529,13 @@ struct
|
|||||||
val length = finishIdx - startIdx
|
val length = finishIdx - startIdx
|
||||||
val buffer = LineGap.delete (startIdx, length, buffer)
|
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)
|
val buffer = LineGap.goToIdx (startIdx, buffer)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, startIdx, searchList)
|
Finish.buildTextAndClear
|
||||||
|
(app, buffer, startIdx, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun helpDeleteLineBack (app, buffer, low, high, count) =
|
fun helpDeleteLineBack (app, buffer, low, high, count) =
|
||||||
@@ -523,12 +545,14 @@ struct
|
|||||||
val length = high - low
|
val length = high - low
|
||||||
val buffer = LineGap.delete (low, length, buffer)
|
val buffer = LineGap.delete (low, length, buffer)
|
||||||
|
|
||||||
|
val buffer = LineGap.goToEnd buffer
|
||||||
val searchString = #searchString app
|
val searchString = #searchString app
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
val initialMsg = [SEARCH (buffer, searchString)]
|
||||||
|
|
||||||
val buffer = LineGap.goToIdx (low, buffer)
|
val buffer = LineGap.goToIdx (low, buffer)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, low, searchList)
|
Finish.buildTextAndClear
|
||||||
|
(app, buffer, low, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
@@ -575,9 +599,11 @@ struct
|
|||||||
val length = high - low
|
val length = high - low
|
||||||
|
|
||||||
val buffer = LineGap.delete (low, length, buffer)
|
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
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, low, searchList)
|
Finish.buildTextAndClear (app, buffer, low, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun helpDeleteToChr
|
fun helpDeleteToChr
|
||||||
@@ -589,10 +615,12 @@ struct
|
|||||||
val length = high - low
|
val length = high - low
|
||||||
val buffer = LineGap.delete (low, length, buffer)
|
val buffer = LineGap.delete (low, length, buffer)
|
||||||
|
|
||||||
|
val buffer = LineGap.goToEnd buffer
|
||||||
val searchString = #searchString app
|
val searchString = #searchString app
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
val initialMsg = [SEARCH (buffer, searchString)]
|
||||||
in
|
in
|
||||||
buildTextAndClearAfterChr (app, buffer, low, searchList)
|
buildTextAndClearAfterChr
|
||||||
|
(app, buffer, low, SearchList.empty, initialMsg)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
@@ -625,6 +653,9 @@ struct
|
|||||||
val buffer = LineGap.delete (0, cursorIdx, buffer)
|
val buffer = LineGap.delete (0, cursorIdx, buffer)
|
||||||
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
val (buffer, searchList) = SearchList.build (buffer, searchString)
|
||||||
|
|
||||||
|
val buffer = LineGap.goToEnd buffer
|
||||||
|
val initialMsg = [SEARCH (buffer, #searchString app)]
|
||||||
|
|
||||||
val cursorIdx = 0
|
val cursorIdx = 0
|
||||||
val startLine = 0
|
val startLine = 0
|
||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
||||||
@@ -637,6 +668,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, initialMsg
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
@@ -767,6 +799,7 @@ struct
|
|||||||
| _ => clearMode app)
|
| _ => clearMode app)
|
||||||
| KEY_ESC => 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)
|
||||||
else
|
else
|
||||||
(* have to continue parsing string *)
|
(* have to continue parsing string *)
|
||||||
case String.sub (str, strPos + 1) of
|
case String.sub (str, strPos + 1) of
|
||||||
@@ -776,27 +809,31 @@ struct
|
|||||||
CHAR_EVENT chr =>
|
CHAR_EVENT chr =>
|
||||||
deleteToChr (app, 1, Cursor.tillNextChr, op+, chr)
|
deleteToChr (app, 1, Cursor.tillNextChr, op+, chr)
|
||||||
| KEY_ESC => 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))
|
||||||
| #"T" =>
|
| #"T" =>
|
||||||
(* delete till chr, backwards *)
|
(* delete till chr, backwards *)
|
||||||
(case newCmd of
|
(case newCmd of
|
||||||
CHAR_EVENT chr =>
|
CHAR_EVENT chr =>
|
||||||
deleteToChr (app, 1, Cursor.tillPrevChr, op-, chr)
|
deleteToChr (app, 1, Cursor.tillPrevChr, op-, chr)
|
||||||
| KEY_ESC => 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))
|
||||||
| #"f" =>
|
| #"f" =>
|
||||||
(case newCmd of
|
(case newCmd of
|
||||||
CHAR_EVENT chr =>
|
CHAR_EVENT chr =>
|
||||||
deleteToChr (app, count, Cursor.toNextChr, op+, chr)
|
deleteToChr (app, count, Cursor.toNextChr, op+, chr)
|
||||||
| KEY_ESC => 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))
|
||||||
| #"F" =>
|
| #"F" =>
|
||||||
(* delete to chr, backwards *)
|
(* delete to chr, backwards *)
|
||||||
(case newCmd of
|
(case newCmd of
|
||||||
CHAR_EVENT chr =>
|
CHAR_EVENT chr =>
|
||||||
deleteToChr (app, count, Cursor.toPrevChr, op-, chr)
|
deleteToChr (app, count, Cursor.toPrevChr, op-, chr)
|
||||||
| KEY_ESC => 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))
|
||||||
| #"g" =>
|
| #"g" =>
|
||||||
(* same events as handleGo *)
|
(* same events as handleGo *)
|
||||||
(case newCmd of
|
(case newCmd of
|
||||||
@@ -807,7 +844,8 @@ struct
|
|||||||
| #"g" => deleteToStart app
|
| #"g" => deleteToStart app
|
||||||
| _ => clearMode app)
|
| _ => clearMode app)
|
||||||
| KEY_ESC => 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
|
| _ => clearMode app
|
||||||
|
|
||||||
(* useful reference as list of non-terminal commands *)
|
(* useful reference as list of non-terminal commands *)
|
||||||
@@ -849,6 +887,7 @@ struct
|
|||||||
CHAR_EVENT chr => handleChr (app, 1, chr, str)
|
CHAR_EVENT chr => handleChr (app, 1, chr, str)
|
||||||
| KEY_ESC => 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)
|
||||||
else if String.size str = 1 then
|
else if String.size str = 1 then
|
||||||
case newCmd of
|
case newCmd of
|
||||||
CHAR_EVENT chr =>
|
CHAR_EVENT chr =>
|
||||||
@@ -857,6 +896,7 @@ struct
|
|||||||
| NONE => parseAfterCount (0, str, 1, app, newCmd))
|
| NONE => parseAfterCount (0, str, 1, app, newCmd))
|
||||||
| KEY_ESC => 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)
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
val numLength = getNumLength (0, str)
|
val numLength = getNumLength (0, str)
|
||||||
@@ -872,6 +912,7 @@ struct
|
|||||||
CHAR_EVENT chr => handleChr (app, count, chr, str)
|
CHAR_EVENT chr => handleChr (app, count, chr, str)
|
||||||
| KEY_ESC => 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)
|
||||||
else
|
else
|
||||||
(* continue parsing. *)
|
(* continue parsing. *)
|
||||||
parseAfterCount (numLength, str, count, app, newCmd)
|
parseAfterCount (numLength, str, count, app, newCmd)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ structure Finish =
|
|||||||
struct
|
struct
|
||||||
open AppType
|
open AppType
|
||||||
|
|
||||||
fun buildTextAndClear (app: app_type, buffer, cursorIdx, searchList) =
|
fun buildTextAndClear (app: app_type, buffer, cursorIdx, searchList, msgs) =
|
||||||
let
|
let
|
||||||
val {windowWidth, windowHeight, startLine, searchString, ...} = app
|
val {windowWidth, windowHeight, startLine, searchString, ...} = app
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ struct
|
|||||||
val buffer = LineGap.goToLine (startLine, buffer)
|
val buffer = LineGap.goToLine (startLine, buffer)
|
||||||
val lineIdx = TextBuilder.getLineAbsIdx (startLine, buffer)
|
val lineIdx = TextBuilder.getLineAbsIdx (startLine, buffer)
|
||||||
|
|
||||||
val drawMsg = TextBuilder.build
|
val msgs = TextBuilder.build
|
||||||
( startLine
|
( startLine
|
||||||
, cursorIdx
|
, cursorIdx
|
||||||
, buffer
|
, buffer
|
||||||
@@ -26,11 +26,12 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList
|
, searchList
|
||||||
, searchString
|
, searchString
|
||||||
|
, msgs
|
||||||
)
|
)
|
||||||
|
|
||||||
val mode = NORMAL_MODE ""
|
val mode = NORMAL_MODE ""
|
||||||
in
|
in
|
||||||
AppWith.bufferAndCursorIdx
|
AppWith.bufferAndCursorIdx
|
||||||
(app, buffer, cursorIdx, mode, startLine, searchList, drawMsg)
|
(app, buffer, cursorIdx, mode, startLine, searchList, msgs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ functor MakeMove(Fn: MOVE): MAKE_MOVE =
|
|||||||
struct
|
struct
|
||||||
fun helpMove (app: AppType.app_type, buffer, cursorIdx, count) =
|
fun helpMove (app: AppType.app_type, buffer, cursorIdx, count) =
|
||||||
if count = 0 then
|
if count = 0 then
|
||||||
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app)
|
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app, [])
|
||||||
else
|
else
|
||||||
(* move LineGap to cursorIdx, which is necessary for finding newCursorIdx *)
|
(* move LineGap to cursorIdx, which is necessary for finding newCursorIdx *)
|
||||||
let
|
let
|
||||||
@@ -62,7 +62,7 @@ struct
|
|||||||
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
||||||
val cursorIdx = Fn.fMove (buffer, cursorIdx, count)
|
val cursorIdx = Fn.fMove (buffer, cursorIdx, count)
|
||||||
in
|
in
|
||||||
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app)
|
Finish.buildTextAndClear (app, buffer, cursorIdx, #searchList app, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,43 +4,22 @@ sig
|
|||||||
val getLineAbsIdx: int * LineGap.t -> int
|
val getLineAbsIdx: int * LineGap.t -> int
|
||||||
|
|
||||||
(* Prerequisites: LineGap is moved to requested line first. *)
|
(* Prerequisites: LineGap is moved to requested line first. *)
|
||||||
val build: int * int * LineGap.t * int * int * SearchList.t * string
|
val build:
|
||||||
-> MailboxType.t list
|
int
|
||||||
|
* int
|
||||||
|
* LineGap.t
|
||||||
|
* int
|
||||||
|
* int
|
||||||
|
* SearchList.t
|
||||||
|
* string
|
||||||
|
* MailboxType.t list
|
||||||
|
-> MailboxType.t list
|
||||||
end
|
end
|
||||||
|
|
||||||
structure TextBuilder :> TEXT_BUILDER =
|
structure TextBuilder :> TEXT_BUILDER =
|
||||||
struct
|
struct
|
||||||
open TextConstants
|
open TextConstants
|
||||||
|
|
||||||
fun accToDrawMsg (textAcc, cursorAcc, bgAcc) =
|
|
||||||
let
|
|
||||||
open MailboxType
|
|
||||||
open DrawMsg
|
|
||||||
|
|
||||||
val textAcc = Vector.concat textAcc
|
|
||||||
val bgAcc = Vector.concat bgAcc
|
|
||||||
|
|
||||||
val textMsg = REDRAW_TEXT textAcc
|
|
||||||
val cursorMsg = REDRAW_CURSOR cursorAcc
|
|
||||||
val bgMsg = REDRAW_BG bgAcc
|
|
||||||
in
|
|
||||||
[DRAW bgMsg, DRAW textMsg, DRAW cursorMsg]
|
|
||||||
end
|
|
||||||
|
|
||||||
(* builds text from a string with char-wrap.
|
|
||||||
* char-wrap is a similar concept to word-wrap,
|
|
||||||
* but it breaks on character in the middle of a word.
|
|
||||||
*
|
|
||||||
* Will likely want multiple versions of these two mutually recursive
|
|
||||||
* functions for each selection and cursor type:
|
|
||||||
* cursor over an individual character,
|
|
||||||
* range selection where multiple characters are selected, etc.
|
|
||||||
*
|
|
||||||
* Todo:
|
|
||||||
* - Possibly add visual horizontal indentation when char-wrap occurs
|
|
||||||
* on an indented line *)
|
|
||||||
(* same as buildTextStringAfterCursor, except this keeps track of absolute
|
|
||||||
* index and cursor pos too *)
|
|
||||||
type env_data =
|
type env_data =
|
||||||
{ r: Real32.real
|
{ r: Real32.real
|
||||||
, g: Real32.real
|
, g: Real32.real
|
||||||
@@ -57,8 +36,40 @@ struct
|
|||||||
(* fw/fh = float window width and float window height *)
|
(* fw/fh = float window width and float window height *)
|
||||||
, fw: Real32.real
|
, fw: Real32.real
|
||||||
, fh: Real32.real
|
, fh: Real32.real
|
||||||
|
, msgs: MailboxType.t list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun accToDrawMsg (textAcc, cursorAcc, bgAcc, env: env_data) =
|
||||||
|
let
|
||||||
|
open MailboxType
|
||||||
|
open DrawMsg
|
||||||
|
|
||||||
|
val msgs = #msgs env
|
||||||
|
|
||||||
|
val textAcc = Vector.concat textAcc
|
||||||
|
val bgAcc = Vector.concat bgAcc
|
||||||
|
|
||||||
|
val textMsg = REDRAW_TEXT textAcc
|
||||||
|
val cursorMsg = REDRAW_CURSOR cursorAcc
|
||||||
|
val bgMsg = REDRAW_BG bgAcc
|
||||||
|
in
|
||||||
|
DRAW bgMsg :: DRAW textMsg :: DRAW cursorMsg :: msgs
|
||||||
|
end
|
||||||
|
|
||||||
|
(* builds text from a string with char-wrap.
|
||||||
|
* char-wrap is a similar concept to word-wrap,
|
||||||
|
* but it breaks on character in the middle of a word.
|
||||||
|
*
|
||||||
|
* Will likely want multiple versions of these two mutually recursive
|
||||||
|
* functions for each selection and cursor type:
|
||||||
|
* cursor over an individual character,
|
||||||
|
* range selection where multiple characters are selected, etc.
|
||||||
|
*
|
||||||
|
* Todo:
|
||||||
|
* - Possibly add visual horizontal indentation when char-wrap occurs
|
||||||
|
* on an indented line *)
|
||||||
|
(* same as buildTextStringAfterCursor, except this keeps track of absolute
|
||||||
|
* index and cursor pos too *)
|
||||||
fun buildTextString
|
fun buildTextString
|
||||||
( pos
|
( pos
|
||||||
, str
|
, str
|
||||||
@@ -159,7 +170,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
| chr =>
|
| chr =>
|
||||||
let
|
let
|
||||||
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
|
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
|
||||||
@@ -213,7 +224,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
else
|
else
|
||||||
(* equal to cursor *)
|
(* equal to cursor *)
|
||||||
let
|
let
|
||||||
@@ -278,7 +289,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -299,7 +310,7 @@ struct
|
|||||||
, bgAcc
|
, bgAcc
|
||||||
, env
|
, env
|
||||||
)
|
)
|
||||||
| [] => accToDrawMsg (acc, cursorAcc, bgAcc)
|
| [] => accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
|
|
||||||
fun isInSearchRange (absIdx, searchPos, searchHd, searchLen) =
|
fun isInSearchRange (absIdx, searchPos, searchHd, searchLen) =
|
||||||
let val searchIdx = Vector.sub (searchHd, searchPos)
|
let val searchIdx = Vector.sub (searchHd, searchPos)
|
||||||
@@ -329,21 +340,21 @@ struct
|
|||||||
, searchLen
|
, searchLen
|
||||||
) =
|
) =
|
||||||
if searchPos = Vector.length searchHd then
|
if searchPos = Vector.length searchHd then
|
||||||
(* exhausted search list so call normal build function *)
|
(* exhausted search list so call normal build function *)
|
||||||
buildTextString
|
buildTextString
|
||||||
( pos
|
( pos
|
||||||
, str
|
, str
|
||||||
, acc
|
, acc
|
||||||
, posX
|
, posX
|
||||||
, posY
|
, posY
|
||||||
, startX
|
, startX
|
||||||
, tl
|
, tl
|
||||||
, absIdx
|
, absIdx
|
||||||
, cursorPos
|
, cursorPos
|
||||||
, cursorAcc
|
, cursorAcc
|
||||||
, bgAcc
|
, bgAcc
|
||||||
, env
|
, env
|
||||||
)
|
)
|
||||||
else if pos < String.size str then
|
else if pos < String.size str then
|
||||||
case String.sub (str, pos) of
|
case String.sub (str, pos) of
|
||||||
#" " =>
|
#" " =>
|
||||||
@@ -474,7 +485,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
| chr =>
|
| chr =>
|
||||||
let
|
let
|
||||||
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
|
val chrFun = Vector.sub (CozetteAscii.asciiTable, Char.ord chr)
|
||||||
@@ -582,7 +593,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
else
|
else
|
||||||
(* equal to cursor *)
|
(* equal to cursor *)
|
||||||
let
|
let
|
||||||
@@ -652,7 +663,7 @@ struct
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
accToDrawMsg (acc, cursorAcc, bgAcc)
|
accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -676,7 +687,7 @@ struct
|
|||||||
, searchPos
|
, searchPos
|
||||||
, searchLen
|
, searchLen
|
||||||
)
|
)
|
||||||
| [] => accToDrawMsg (acc, cursorAcc, bgAcc)
|
| [] => accToDrawMsg (acc, cursorAcc, bgAcc, env)
|
||||||
|
|
||||||
(* gets line start idx, relative to right hd *)
|
(* gets line start idx, relative to right hd *)
|
||||||
fun helpGetLineStartIdx (startLine, curLine, rLnHd) =
|
fun helpGetLineStartIdx (startLine, curLine, rLnHd) =
|
||||||
@@ -718,6 +729,7 @@ struct
|
|||||||
, windowHeight
|
, windowHeight
|
||||||
, searchList: SearchList.t
|
, searchList: SearchList.t
|
||||||
, searchString
|
, searchString
|
||||||
|
, msgs
|
||||||
) =
|
) =
|
||||||
let
|
let
|
||||||
val {rightStrings, rightLines, line = curLine, idx = curIdx, ...} =
|
val {rightStrings, rightLines, line = curLine, idx = curIdx, ...} =
|
||||||
@@ -742,44 +754,45 @@ struct
|
|||||||
, hr = 0.211
|
, hr = 0.211
|
||||||
, hg = 0.219
|
, hg = 0.219
|
||||||
, hb = 0.25
|
, hb = 0.25
|
||||||
|
, msgs = msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
val cursorAcc = Vector.fromList []
|
val cursorAcc = Vector.fromList []
|
||||||
val searchPos = BinSearch.equalOrMore (absIdx, searchList)
|
val searchPos = BinSearch.equalOrMore (absIdx, searchList)
|
||||||
in
|
in
|
||||||
if searchPos < Vector.length searchList then
|
if searchPos < Vector.length searchList then
|
||||||
buildTextStringSearch
|
buildTextStringSearch
|
||||||
( startIdx
|
( startIdx
|
||||||
, rStrHd
|
, rStrHd
|
||||||
, []
|
, []
|
||||||
, 5
|
, 5
|
||||||
, 5
|
, 5
|
||||||
, 5
|
, 5
|
||||||
, rStrTl
|
, rStrTl
|
||||||
, absIdx
|
, absIdx
|
||||||
, cursorPos
|
, cursorPos
|
||||||
, cursorAcc
|
, cursorAcc
|
||||||
, []
|
, []
|
||||||
, env
|
, env
|
||||||
, searchList
|
, searchList
|
||||||
, searchPos
|
, searchPos
|
||||||
, String.size searchString
|
, String.size searchString
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
buildTextString
|
buildTextString
|
||||||
( startIdx
|
( startIdx
|
||||||
, rStrHd
|
, rStrHd
|
||||||
, []
|
, []
|
||||||
, 5
|
, 5
|
||||||
, 5
|
, 5
|
||||||
, 5
|
, 5
|
||||||
, rStrTl
|
, rStrTl
|
||||||
, absIdx
|
, absIdx
|
||||||
, cursorPos
|
, cursorPos
|
||||||
, cursorAcc
|
, cursorAcc
|
||||||
, []
|
, []
|
||||||
, env
|
, env
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
| (_, _) =>
|
| (_, _) =>
|
||||||
(* requested line goes beyond the buffer,
|
(* requested line goes beyond the buffer,
|
||||||
|
|||||||
@@ -1,2 +1,8 @@
|
|||||||
structure InputMsg =
|
structure InputMsg =
|
||||||
struct datatype t = CHAR_EVENT of char | KEY_ESC | RESIZE_EVENT of int * int end
|
struct
|
||||||
|
datatype t =
|
||||||
|
CHAR_EVENT of char
|
||||||
|
| KEY_ESC
|
||||||
|
| RESIZE_EVENT of int * int
|
||||||
|
| WITH_SEARCH_LIST of int vector
|
||||||
|
end
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
structure MailboxType = struct datatype t = DRAW of DrawMsg.t end
|
structure MailboxType =
|
||||||
|
struct datatype t = DRAW of DrawMsg.t | SEARCH of LineGap.t * string end
|
||||||
|
|||||||
14
shell/search-thread.sml
Normal file
14
shell/search-thread.sml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
structure SearchThread =
|
||||||
|
struct
|
||||||
|
open CML
|
||||||
|
|
||||||
|
(* Prerequisite to sending message: move buffer to end. *)
|
||||||
|
fun loop (searchMailbox, inputMailbox) =
|
||||||
|
let
|
||||||
|
val (buffer, searchString) = Mailbox.recv searchMailbox
|
||||||
|
val (_, searchList) = SearchList.build (buffer, searchString)
|
||||||
|
val () = Mailbox.send (inputMailbox, InputMsg.WITH_SEARCH_LIST searchList)
|
||||||
|
in
|
||||||
|
loop (searchMailbox, inputMailbox)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -6,6 +6,7 @@ struct
|
|||||||
(* create mailboxes for CML communication *)
|
(* create mailboxes for CML communication *)
|
||||||
val inputMailbox = Mailbox.mailbox ()
|
val inputMailbox = Mailbox.mailbox ()
|
||||||
val drawMailbox = Mailbox.mailbox ()
|
val drawMailbox = Mailbox.mailbox ()
|
||||||
|
val searchMailbox = Mailbox.mailbox ()
|
||||||
|
|
||||||
fun frameBufferSizeCallback (width, height) =
|
fun frameBufferSizeCallback (width, height) =
|
||||||
Mailbox.send (inputMailbox, RESIZE_EVENT (width, height))
|
Mailbox.send (inputMailbox, RESIZE_EVENT (width, height))
|
||||||
@@ -79,7 +80,9 @@ struct
|
|||||||
|
|
||||||
val _ = CML.spawn (fn () => GlDraw.loop (drawMailbox, window))
|
val _ = CML.spawn (fn () => GlDraw.loop (drawMailbox, window))
|
||||||
val _ = CML.spawn (fn () =>
|
val _ = CML.spawn (fn () =>
|
||||||
UpdateThread.loop (app, inputMailbox, drawMailbox))
|
UpdateThread.loop (app, inputMailbox, drawMailbox, searchMailbox))
|
||||||
|
val _ = CML.spawn (fn () =>
|
||||||
|
SearchThread.loop (searchMailbox, inputMailbox))
|
||||||
in
|
in
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,18 +4,21 @@ struct
|
|||||||
open MailboxType
|
open MailboxType
|
||||||
open InputMsg
|
open InputMsg
|
||||||
|
|
||||||
fun sendMsg (msg, drawMailbox) =
|
fun sendMsg (msg, drawMailbox, searchMailbox) =
|
||||||
case msg of DRAW msg => Mailbox.send (drawMailbox, msg)
|
case msg of
|
||||||
|
DRAW msg => Mailbox.send (drawMailbox, msg)
|
||||||
|
| SEARCH (buffer, searchString) =>
|
||||||
|
Mailbox.send (searchMailbox, (buffer, searchString))
|
||||||
|
|
||||||
fun sendMsgs (msgList, drawMailbox) =
|
fun sendMsgs (msgList, drawMailbox, searchMailbox) =
|
||||||
case msgList of
|
case msgList of
|
||||||
hd :: tl =>
|
hd :: tl =>
|
||||||
let val _ = sendMsg (hd, drawMailbox)
|
let val _ = sendMsg (hd, drawMailbox, searchMailbox)
|
||||||
in sendMsgs (tl, drawMailbox)
|
in sendMsgs (tl, drawMailbox, searchMailbox)
|
||||||
end
|
end
|
||||||
| [] => ()
|
| [] => ()
|
||||||
|
|
||||||
fun loop (app: AppType.app_type, inputMailbox, drawMailbox) =
|
fun loop (app: AppType.app_type, inputMailbox, drawMailbox, searchMailbox) =
|
||||||
let
|
let
|
||||||
val inputMsg = Mailbox.recv inputMailbox
|
val inputMsg = Mailbox.recv inputMailbox
|
||||||
val () =
|
val () =
|
||||||
@@ -33,8 +36,8 @@ struct
|
|||||||
val app = AppUpdate.update (app, inputMsg)
|
val app = AppUpdate.update (app, inputMsg)
|
||||||
handle e => ExceptionLogger.log e
|
handle e => ExceptionLogger.log e
|
||||||
|
|
||||||
val () = sendMsgs (#msgs app, drawMailbox)
|
val () = sendMsgs (#msgs app, drawMailbox, searchMailbox)
|
||||||
in
|
in
|
||||||
loop (app, inputMailbox, drawMailbox)
|
loop (app, inputMailbox, drawMailbox, searchMailbox)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user