Files
sml-projects/shf/fcore/normal-mode/normal-search-mode.sml
Humza Shahid 6b91d64fc3 Add 'shf/' from commit 'b6c5a95b664aeb861d7b33ffc9eefe447ba99dd7'
git-subtree-dir: shf
git-subtree-mainline: 401408448f
git-subtree-split: b6c5a95b66
2026-04-24 00:27:49 +01:00

275 lines
7.1 KiB
Standard ML

structure NormalSearchMode =
struct
open AppType
open InputMsg
open MailboxType
fun buildTempSearchList (searchString, buffer, cursorIdx, caseSensitive) =
let
val dfa =
if caseSensitive then CaseSensitiveDfa.fromString searchString
else CaseInsensitiveDfa.fromString searchString
in
SearchList.buildRange (buffer, cursorIdx + 1111, dfa)
end
fun addChr
( app: app_type
, searchString
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, chr
) =
let
val {cursorIdx, buffer, ...} = app
val c = String.implode [chr]
val searchString =
if searchCursorIdx = String.size searchString then
searchString ^ c
else
let
val sub1 = Substring.extract (searchString, 0, SOME searchCursorIdx)
val sub2 = Substring.full c
val sub3 = Substring.extract (searchString, searchCursorIdx, NONE)
in
Substring.concat [sub1, sub2, sub3]
end
val searchCursorIdx = searchCursorIdx + 1
val buffer = LineGap.goToIdx (cursorIdx - 1111, buffer)
val (buffer, tempSearchList) =
buildTempSearchList (searchString, buffer, cursorIdx, caseSensitive)
in
NormalSearchFinish.onSearchChanged
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, buffer
)
end
(* return to normal mode, keeping the same searchString and searchList
* from before entering this mode. *)
fun exitToNormalMode (app: app_type) =
let
val {buffer, cursorIdx, searchList, bufferModifyTime, ...} = app
in
NormalFinish.buildTextAndClear
(app, buffer, cursorIdx, searchList, [], bufferModifyTime)
end
(* save search string and searchList and return to normal mode *)
fun saveSearch (app: app_type, searchString, caseSensitive, time) =
let
val
{ buffer
, cursorIdx
, windowWidth
, windowHeight
, startLine
, visualScrollColumn
, ...
} = app
val dfa =
if caseSensitive then CaseSensitiveDfa.fromString searchString
else CaseInsensitiveDfa.fromString searchString
val buffer = LineGap.goToStart buffer
val (buffer, searchList) = SearchList.build (buffer, dfa)
(* move LineGap to first line displayed on screen *)
val buffer = LineGap.goToLine (startLine, buffer)
(* move buffer to new startLine as required by TextBuilder.build *)
val buffer = LineGap.goToLine (startLine, buffer)
val drawMsg = NormalModeTextBuilder.build
( startLine
, cursorIdx
, buffer
, windowWidth
, windowHeight
, searchList
, visualScrollColumn
)
val drawMsg = Vector.concat drawMsg
val drawMsg = DrawMsg.DRAW_TEXT drawMsg
val msgs = [DRAW drawMsg]
val mode = NORMAL_MODE ""
in
NormalSearchModeWith.returnToNormalMode
(app, buffer, searchList, startLine, mode, dfa, msgs)
end
fun backspace
( app: app_type
, searchString
, tempSearchList
, searchScrollColumn
, searchCursorIdx
, caseSensitive
) =
if searchCursorIdx = 0 then
app
else
let
val searchString =
if searchCursorIdx = String.size searchString then
String.substring (searchString, 0, String.size searchString - 1)
else
let
val sub1 = Substring.extract
(searchString, 0, SOME (searchCursorIdx - 1))
val sub2 = Substring.extract (searchString, searchCursorIdx, SOME
(String.size searchString - searchCursorIdx))
in
Substring.concat [sub1, sub2]
end
val searchCursorIdx = searchCursorIdx - 1
val {cursorIdx, buffer, ...} = app
val buffer = LineGap.goToIdx (cursorIdx - 1111, buffer)
val (buffer, tempSearchList) =
buildTempSearchList (searchString, buffer, cursorIdx, caseSensitive)
in
NormalSearchFinish.onSearchChanged
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, buffer
)
end
fun moveLeft
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
) =
if searchCursorIdx = 0 then
app
else
let
val searchCursorIdx = Int.max (0, searchCursorIdx - 1)
in
NormalSearchFinish.onSearchChanged
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, #buffer app
)
end
fun moveRight
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
) =
if searchCursorIdx = String.size searchString then
app
else
let
val searchCursorIdx =
Int.min (searchCursorIdx + 1, String.size searchString)
in
NormalSearchFinish.onSearchChanged
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, #buffer app
)
end
fun update
( app
, { searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
}
, msg
, time
) =
case msg of
CHAR_EVENT chr =>
addChr
( app
, searchString
, searchCursorIdx
, searchScrollColumn
, caseSensitive
, chr
)
| KEY_BACKSPACE =>
backspace
( app
, searchString
, tempSearchList
, searchScrollColumn
, searchCursorIdx
, caseSensitive
)
| KEY_ESC => exitToNormalMode app
| KEY_ENTER => saveSearch (app, searchString, caseSensitive, time)
| ARROW_LEFT =>
moveLeft
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
)
| ARROW_RIGHT =>
moveRight
( app
, searchString
, tempSearchList
, searchCursorIdx
, searchScrollColumn
, caseSensitive
)
| RESIZE_EVENT (width, height) =>
NormalSearchFinish.resize
( app
, width
, height
, searchString
, searchCursorIdx
, tempSearchList
, searchScrollColumn
, caseSensitive
)
(* In Vim's search mode, the up and down arrows can be used
* to scroll through the search history.
* I don't find this feature too useful as it is often easier to type
* the whole search string again, so I'm leaving it unimplemented
* until/unless I find that I wish this functionality was there
* while using the program. *)
| ARROW_UP => app
| ARROW_DOWN => app
end