2025-09-02 12:33:02 +01:00
|
|
|
structure NormalYank =
|
|
|
|
|
struct
|
|
|
|
|
open AppType
|
|
|
|
|
open DrawMsg
|
|
|
|
|
open MailboxType
|
|
|
|
|
|
|
|
|
|
fun yankLine (app: app_type, count) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = Cursor.vi0 (buffer, cursorIdx)
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (low, buffer)
|
|
|
|
|
val high = Cursor.viDlrForDelete (buffer, low, count)
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val length = high - low
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankToStartOfLine (app: app_type) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = Cursor.vi0 (buffer, cursorIdx)
|
|
|
|
|
|
|
|
|
|
val length = cursorIdx - low
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankWhenMovingBack (app: app_type, fMove, count) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = fMove (buffer, cursorIdx, count)
|
|
|
|
|
|
|
|
|
|
val length = cursorIdx - low
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
2025-09-05 23:46:10 +01:00
|
|
|
fun yankWhenMovingBackPlusOne (app: app_type, fMove, count) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = fMove (buffer, cursorIdx, count)
|
|
|
|
|
|
|
|
|
|
val length = (cursorIdx + 1) - low
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
2025-09-02 12:33:02 +01:00
|
|
|
fun yankWhenMovingForward (app: app_type, fMove, count) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val high = fMove (buffer, cursorIdx, count)
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val length = high - cursorIdx
|
|
|
|
|
val str = LineGap.substring (cursorIdx, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
2025-09-02 12:39:50 +01:00
|
|
|
|
|
|
|
|
fun yankToFirstNonSpaceChr (app: app_type) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val otherIdx = Cursor.vi0 (buffer, cursorIdx)
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (otherIdx, buffer)
|
|
|
|
|
val otherIdx = Cursor.firstNonSpaceChr (buffer, otherIdx)
|
|
|
|
|
in
|
|
|
|
|
if cursorIdx > otherIdx then
|
|
|
|
|
(* yanking backwards from cursorIdx *)
|
|
|
|
|
let
|
|
|
|
|
val length = cursorIdx - otherIdx + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (otherIdx, buffer)
|
|
|
|
|
|
|
|
|
|
val str = LineGap.substring (otherIdx, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
else if cursorIdx < otherIdx then
|
|
|
|
|
(* yanking forward from cursorIdx *)
|
|
|
|
|
let
|
|
|
|
|
val length = otherIdx - cursorIdx
|
|
|
|
|
val str = LineGap.substring (cursorIdx, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
NormalFinish.clearMode app
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankToEndOfText (app: app_type) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToEnd buffer
|
|
|
|
|
val {rightStrings, idx, ...} = buffer
|
|
|
|
|
val finishIdx = Int.max (0, idx - 1)
|
|
|
|
|
|
|
|
|
|
val length = finishIdx - cursorIdx
|
|
|
|
|
val str = LineGap.substring (cursorIdx, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankToMatchingPair (app: app_type) =
|
|
|
|
|
let
|
|
|
|
|
val {buffer, cursorIdx, ...} = app
|
|
|
|
|
val otherIdx = Cursor.matchPair (buffer, cursorIdx)
|
|
|
|
|
in
|
|
|
|
|
if cursorIdx = otherIdx then
|
|
|
|
|
NormalFinish.clearMode app
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val low = Int.min (cursorIdx, otherIdx)
|
|
|
|
|
val high = Int.max (cursorIdx, otherIdx)
|
|
|
|
|
val length = high - low + 1
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-09-02 12:46:30 +01:00
|
|
|
|
|
|
|
|
fun yankToNextMatch (app: app_type, count) =
|
|
|
|
|
let
|
|
|
|
|
val {cursorIdx, searchList, buffer, ...} = app
|
2025-10-08 08:16:20 +01:00
|
|
|
val high = PersistentVector.nextMatch (cursorIdx, searchList, count)
|
2025-09-02 12:46:30 +01:00
|
|
|
in
|
|
|
|
|
if high = ~1 orelse high <= cursorIdx then
|
|
|
|
|
NormalFinish.clearMode app
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val length = high - cursorIdx
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
|
|
|
|
|
val str = LineGap.substring (cursorIdx, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankToPrevMatch (app: app_type, count) =
|
|
|
|
|
let
|
|
|
|
|
val {cursorIdx, searchList, buffer, ...} = app
|
2025-10-08 10:27:19 +01:00
|
|
|
val low = PersistentVector.prevMatch (cursorIdx, searchList, count)
|
2025-09-02 12:46:30 +01:00
|
|
|
in
|
|
|
|
|
if low = ~1 orelse low >= cursorIdx then
|
|
|
|
|
NormalFinish.clearMode app
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val length = cursorIdx - low
|
|
|
|
|
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-09-04 00:50:16 +01:00
|
|
|
|
|
|
|
|
fun helpYankToChr
|
|
|
|
|
(app: app_type, buffer, cursorIdx, otherIdx, count, fMove, fInc, chr) =
|
|
|
|
|
if count = 0 then
|
|
|
|
|
let
|
|
|
|
|
val low = Int.min (cursorIdx, otherIdx)
|
|
|
|
|
val high = Int.max (cursorIdx, otherIdx)
|
|
|
|
|
val length = high - low
|
|
|
|
|
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val buffer = LineGap.goToIdx (otherIdx, buffer)
|
|
|
|
|
val newOtherIdx = fMove (buffer, otherIdx, chr)
|
|
|
|
|
val newCount = if newOtherIdx = otherIdx then 0 else count - 1
|
|
|
|
|
val newOtherIdx = fInc (newOtherIdx, 1)
|
|
|
|
|
in
|
|
|
|
|
helpYankToChr
|
|
|
|
|
(app, buffer, cursorIdx, newOtherIdx, newCount, fMove, fInc, chr)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankToChr (app: app_type, count, fMove, fInc, chr) =
|
|
|
|
|
helpYankToChr
|
|
|
|
|
( app
|
|
|
|
|
, #buffer app
|
|
|
|
|
, #cursorIdx app
|
|
|
|
|
, #cursorIdx app
|
|
|
|
|
, count
|
|
|
|
|
, fMove
|
|
|
|
|
, fInc
|
|
|
|
|
, chr
|
|
|
|
|
)
|
2025-09-05 23:46:10 +01:00
|
|
|
|
|
|
|
|
fun yankToStart (app: app_type) =
|
|
|
|
|
let
|
|
|
|
|
val {cursorIdx, buffer, ...} = app
|
2025-09-06 00:02:37 +01:00
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
2025-09-05 23:46:10 +01:00
|
|
|
|
|
|
|
|
val high = Cursor.viDlrForDelete (buffer, cursorIdx, 1)
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
|
|
|
|
|
val str = LineGap.substring (0, high, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
2025-09-06 01:12:59 +01:00
|
|
|
|
|
|
|
|
fun yankInsideWord (app: app_type) =
|
|
|
|
|
let
|
2025-10-08 05:40:29 +01:00
|
|
|
val {buffer, cursorIdx, ...} = app
|
2025-09-06 01:12:59 +01:00
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = Cursor.prevWordStrict (buffer, cursorIdx, 1)
|
|
|
|
|
val high = Cursor.endOfWordStrict (buffer, cursorIdx, 1)
|
|
|
|
|
|
|
|
|
|
val high = high + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val length = high - low
|
|
|
|
|
|
2025-09-06 01:15:45 +01:00
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
2025-09-06 02:27:01 +01:00
|
|
|
if str = "\n" then NormalFinish.clearMode app
|
2025-09-06 01:15:45 +01:00
|
|
|
else NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankInsideWORD (app: app_type) =
|
|
|
|
|
let
|
2025-10-08 05:40:29 +01:00
|
|
|
val {buffer, cursorIdx, ...} = app
|
2025-09-06 01:15:45 +01:00
|
|
|
val buffer = LineGap.goToIdx (cursorIdx, buffer)
|
|
|
|
|
val low = Cursor.prevWORDStrict (buffer, cursorIdx, 1)
|
|
|
|
|
val high = Cursor.endOfWORDStrict (buffer, cursorIdx, 1)
|
|
|
|
|
|
|
|
|
|
val high = high + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val length = high - low
|
|
|
|
|
|
2025-09-06 01:12:59 +01:00
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
2025-09-06 02:27:01 +01:00
|
|
|
if str = "\n" then NormalFinish.clearMode app
|
2025-09-06 01:12:59 +01:00
|
|
|
else NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
2025-09-06 02:27:01 +01:00
|
|
|
|
|
|
|
|
fun finishAfterYankInside (app: app_type, low, high, buffer) =
|
|
|
|
|
let
|
|
|
|
|
val length = high - low
|
|
|
|
|
val str = LineGap.substring (low, length, buffer)
|
|
|
|
|
val msg = YANK str
|
|
|
|
|
val mode = NORMAL_MODE ""
|
|
|
|
|
in
|
|
|
|
|
NormalModeWith.modeAndBuffer (app, buffer, mode, [DRAW msg])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankInsideChrOpen (app: app_type, chr) =
|
|
|
|
|
let
|
|
|
|
|
val {cursorIdx, buffer, ...} = app
|
|
|
|
|
|
|
|
|
|
val start = cursorIdx + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (start, buffer)
|
|
|
|
|
|
|
|
|
|
val low = Cursor.toPrevChr (buffer, start, chr)
|
|
|
|
|
val buffer = LineGap.goToIdx (low, buffer)
|
|
|
|
|
val high = Cursor.matchPair (buffer, low)
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
2025-09-06 02:59:05 +01:00
|
|
|
val low = low + 1
|
2025-09-06 02:27:01 +01:00
|
|
|
in
|
|
|
|
|
if low = high then NormalFinish.clearMode app
|
2025-09-06 02:59:05 +01:00
|
|
|
else finishAfterYankInside (app, low, high, buffer)
|
2025-09-06 02:27:01 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankInsideChrClose (app: app_type, chr) =
|
2025-09-06 02:59:05 +01:00
|
|
|
let
|
|
|
|
|
val {cursorIdx, buffer, ...} = app
|
|
|
|
|
|
|
|
|
|
val start = Int.max (cursorIdx - 1, 0)
|
|
|
|
|
val buffer = LineGap.goToIdx (start, buffer)
|
|
|
|
|
|
|
|
|
|
val high = Cursor.toNextChr (buffer, start, chr)
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val low = Cursor.matchPair (buffer, high) + 1
|
|
|
|
|
in
|
|
|
|
|
if low = high then NormalFinish.clearMode app
|
|
|
|
|
else finishAfterYankInside (app, low, high, buffer)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankAroundChrOpen (app: app_type, chr) =
|
|
|
|
|
let
|
|
|
|
|
val {cursorIdx, buffer, ...} = app
|
|
|
|
|
|
|
|
|
|
val start = cursorIdx + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (start, buffer)
|
|
|
|
|
|
|
|
|
|
val low = Cursor.toPrevChr (buffer, start, chr)
|
|
|
|
|
val buffer = LineGap.goToIdx (low, buffer)
|
|
|
|
|
val high = Cursor.matchPair (buffer, low) + 1
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val low = low
|
|
|
|
|
in
|
|
|
|
|
if low = high then NormalFinish.clearMode app
|
|
|
|
|
else finishAfterYankInside (app, low, high, buffer)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun yankAroundChrClose (app: app_type, chr) =
|
2025-09-06 02:27:01 +01:00
|
|
|
let
|
|
|
|
|
val {cursorIdx, buffer, ...} = app
|
|
|
|
|
|
|
|
|
|
val start = Int.max (cursorIdx - 1, 0)
|
|
|
|
|
val buffer = LineGap.goToIdx (start, buffer)
|
|
|
|
|
|
|
|
|
|
val high = Cursor.toNextChr (buffer, start, chr)
|
|
|
|
|
val buffer = LineGap.goToIdx (high, buffer)
|
|
|
|
|
val low = Cursor.matchPair (buffer, high)
|
2025-09-06 02:59:05 +01:00
|
|
|
val high = high + 1
|
2025-09-06 02:27:01 +01:00
|
|
|
in
|
|
|
|
|
if low = high then NormalFinish.clearMode app
|
|
|
|
|
else finishAfterYankInside (app, low, high, buffer)
|
|
|
|
|
end
|
2025-09-02 12:33:02 +01:00
|
|
|
end
|