finish reimplementing 'di<symbol>' and 'da<symbol>' motions so that they align more closely with the behaviour of Vim. (Todo: test them next)

This commit is contained in:
2026-01-02 20:07:36 +00:00
parent 886f384490
commit bce2a5a22d
4 changed files with 138 additions and 154 deletions

View File

@@ -260,7 +260,7 @@ struct
end
fun fStart (strPos, str, _, absIdx, stl, _, {openChr, closeChr}) =
loop (strPos, str, absIdx, stl, openChr, closeChr, 0)
loop (strPos + 1, str, absIdx + 1, stl, openChr, closeChr, 0)
end)
val toCloseChrNext = ToCloseChrNext.foldNext

View File

@@ -1035,143 +1035,140 @@ struct
deleteAndFinish (app, low, length, buffer, time)
end
fun finishDeletingInsidePair (app, buffer, cursorIdx, otherIdx, dfa, time) =
let
val low = Int.min (cursorIdx, otherIdx)
val high = Int.max (cursorIdx, otherIdx)
in
if high = low + 1 then
NormalFinish.clearMode app
else
let
val deleteLow = low + 1
val length = high - deleteLow
val buffer = LineGap.goToIdx (high, buffer)
val initialMsg = Fn.initMsgs (deleteLow, length, buffer)
val buffer = LineGap.delete (deleteLow, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, dfa)
val buffer = LineGap.goToIdx (low, buffer)
in
NormalFinish.buildTextAndClear
(app, buffer, low, searchList, initialMsg, time)
end
end
fun deleteInsidePair (app: app_type, openChr, closeChr, time) =
let
val {buffer, cursorIdx, dfa, ...} = app
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val nextIdx =
Cursor.toCloseChrNext
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
val cursorChr = LineGap.sub (cursorIdx, buffer)
in
if nextIdx = ~1 then
NormalFinish.clearMode app
if cursorChr = openChr orelse cursorChr = closeChr then
let
val otherIdx = Cursor.matchPair (buffer, cursorIdx)
in
finishDeletingInsidePair (app, buffer, cursorIdx, otherIdx, dfa, time)
end
else
let
val buffer = LineGap.goToIdx (nextIdx, buffer)
val matchIdx = Cursor.matchPair (buffer, nextIdx)
val nextIdx =
Cursor.toCloseChrNext
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
in
if matchIdx = ~1 then
if nextIdx = ~1 then
NormalFinish.clearMode app
else
let
val low = Int.min (nextIdx, matchIdx)
val high = Int.max (nextIdx, matchIdx)
val buffer = LineGap.goToIdx (nextIdx, buffer)
val matchIdx = Cursor.matchPair (buffer, nextIdx)
in
if high = low + 1 then
if matchIdx = ~1 then
NormalFinish.clearMode app
else
let
val deleteLow = low + 1
val length = high - deleteLow
val buffer = LineGap.goToIdx (high, buffer)
val initialMsg = Fn.initMsgs (deleteLow, length, buffer)
val buffer = LineGap.delete (deleteLow, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, dfa)
val buffer = LineGap.goToIdx (low, buffer)
in
NormalFinish.buildTextAndClear
(app, buffer, low, searchList, initialMsg, time)
end
finishDeletingInsidePair
(app, buffer, nextIdx, matchIdx, dfa, time)
end
end
end
fun finishAfterDeleteInside (app: app_type, origLow, high, time) =
if origLow = high then
NormalFinish.clearMode app
else
let
val {cursorIdx, buffer, dfa, ...} = app
val low = origLow + 1
val length = high - low
val buffer = LineGap.goToIdx (high, buffer)
val initialMsg = Fn.initMsgs (low, length, buffer)
val buffer = LineGap.delete (low, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, dfa)
val buffer = LineGap.goToIdx (origLow, buffer)
in
NormalFinish.buildTextAndClear
(app, buffer, origLow, searchList, initialMsg, time)
end
fun deleteInsideChrOpen (app: app_type, chr, time) =
fun finishDeleteAroundPair (app, buffer, chr1Idx, chr2Idx, time) =
let
val {cursorIdx, buffer, ...} = app
val low = Int.min (chr1Idx, chr2Idx)
val high = Int.max (chr1Idx, chr2Idx) + 1
val length = high - low
val start = cursorIdx + 1
val buffer = LineGap.goToIdx (start, buffer)
val origLow = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1})
val buffer = LineGap.goToIdx (origLow, buffer)
val high = Cursor.matchPair (buffer, origLow)
in
finishAfterDeleteInside (app, origLow, high, time)
end
fun deleteInsideChrClose (app: app_type, chr, time) =
let
val {cursorIdx, buffer, ...} = app
val start = Int.max (cursorIdx - 1, 0)
val buffer = LineGap.goToIdx (start, buffer)
val high = Cursor.toNextChr (buffer, start, {findChr = chr, count = 1})
val buffer = LineGap.goToIdx (high, buffer)
val origLow = Cursor.matchPair (buffer, high)
in
finishAfterDeleteInside (app, origLow, high, time)
end
fun finishDeleteAroundChr (app, low, high, buffer, time) =
let
val length = high - low + 1
val buffer = LineGap.goToIdx (high, buffer)
val initialMsg = Fn.initMsgs (low, length, buffer)
val buffer = LineGap.delete (low, length, buffer)
val buffer = LineGap.goToIdx (low, buffer)
val low =
if Cursor.isCursorAtStartOfLine (buffer, low) then Int.max (low - 1, 0)
else low
if Cursor.isOnNewlineAfterChr (buffer, low) then low - 1 else low
val buffer = LineGap.goToIdx (low, buffer)
in
finishAfterDeletingBuffer (app, low, buffer, time, initialMsg)
end
fun deleteAroundChrOpen (app: app_type, chr, time) =
fun finishDeletingPair (app, buffer, cursorIdx, otherIdx, dfa, time) =
let
val {cursorIdx, buffer, ...} = app
val low = Int.min (cursorIdx, otherIdx)
val high = Int.max (cursorIdx, otherIdx)
val length = high - low + 1
val start = cursorIdx + 1
val buffer = LineGap.goToIdx (start, buffer)
val buffer = LineGap.goToIdx (high, buffer)
val initialMsg = Fn.initMsgs (low, length, buffer)
val buffer = LineGap.delete (low, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, dfa)
val buffer = LineGap.goToIdx (low, buffer)
val low =
if Cursor.isCursorAtStartOfLine (buffer, low) then
(* we may have deleted the last character of this current line,
* and if we did, we have to move the cursor back by 1 *)
Int.max (low - 1, 0)
else
low
val low = Cursor.toPrevChr (buffer, start, {findChr = chr, count = 1})
val buffer = LineGap.goToIdx (low, buffer)
val high = Cursor.matchPair (buffer, low)
in
if low = high then NormalFinish.clearMode app
else finishDeleteAroundChr (app, low, high, buffer, time)
NormalFinish.buildTextAndClear
(app, buffer, low, searchList, initialMsg, time)
end
fun deleteAroundChrClose (app: app_type, chr, time) =
fun deleteAroundPair (app: app_type, openChr, closeChr, time) =
let
val {cursorIdx, buffer, ...} = app
val {buffer, cursorIdx, dfa, ...} = app
val start = Int.max (cursorIdx - 1, 0)
val buffer = LineGap.goToIdx (start, buffer)
val high = Cursor.toNextChr (buffer, start, {findChr = chr, count = 1})
val buffer = LineGap.goToIdx (high, buffer)
val low = Cursor.matchPair (buffer, high)
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val cursorChr = LineGap.sub (cursorIdx, buffer)
in
if low = high then NormalFinish.clearMode app
else finishDeleteAroundChr (app, low, high, buffer, time)
if cursorChr = closeChr orelse cursorChr = openChr then
let val pairIdx = Cursor.matchPair (buffer, cursorIdx)
in finishDeletingPair (app, buffer, cursorIdx, pairIdx, dfa, time)
end
else
let
val nextIdx =
Cursor.toCloseChrNext
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
in
if nextIdx = ~1 then
NormalFinish.clearMode app
else
let
val buffer = LineGap.goToIdx (nextIdx, buffer)
val matchIdx = Cursor.matchPair (buffer, nextIdx)
in
if matchIdx = ~1 then NormalFinish.clearMode app
else finishDeleteAroundPair (app, buffer, nextIdx, matchIdx, time)
end
end
end
fun deletePair (app: app_type, time) =
@@ -1187,35 +1184,8 @@ struct
val buffer = LineGap.goToIdx (otherIdx, buffer)
val otherIdx = Cursor.matchPair (buffer, otherIdx)
in
if otherIdx = ~1 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 initialMsg = Fn.initMsgs (low, length, buffer)
val buffer = LineGap.delete (low, length, buffer)
val (buffer, searchList) = SearchList.build (buffer, dfa)
val buffer = LineGap.goToIdx (low, buffer)
val low =
if Cursor.isCursorAtStartOfLine (buffer, low) then
(* we may have deleted the last character of this current line,
* and if we did, we have to move the cursor back by 1 *)
Int.max (low - 1, 0)
else
low
val buffer = LineGap.goToIdx (low, buffer)
in
NormalFinish.buildTextAndClear
(app, buffer, low, searchList, initialMsg, time)
end
if otherIdx = ~1 then NormalFinish.clearMode app
else finishDeletingPair (app, buffer, cursorIdx, otherIdx, dfa, time)
end
end
end

View File

@@ -240,14 +240,19 @@ struct
case chr of
#"w" => NormalDelete.deleteAroundWord (app, time)
| #"W" => NormalDelete.deleteAroundWORD (app, time)
| #"(" => NormalDelete.deleteAroundChrOpen (app, chr, time)
| #"[" => NormalDelete.deleteAroundChrOpen (app, chr, time)
| #"{" => NormalDelete.deleteAroundChrOpen (app, chr, time)
| #"<" => NormalDelete.deleteAroundChrOpen (app, chr, time)
| #")" => NormalDelete.deleteAroundChrClose (app, chr, time)
| #"]" => NormalDelete.deleteAroundChrClose (app, chr, time)
| #"}" => NormalDelete.deleteAroundChrClose (app, chr, time)
| #">" => NormalDelete.deleteAroundChrClose (app, chr, time)
| #"(" => NormalDelete.deleteAroundPair (app, #"(", #")", time)
| #")" => NormalDelete.deleteAroundPair (app, #"(", #")", time)
| #"[" => NormalDelete.deleteAroundPair (app, #"[", #"]", time)
| #"]" => NormalDelete.deleteAroundPair (app, #"[", #"]", time)
| #"{" => NormalDelete.deleteAroundPair (app, #"{", #"}", time)
| #"}" => NormalDelete.deleteAroundPair (app, #"{", #"}", time)
| #"<" => NormalDelete.deleteAroundPair (app, #"<", #">", time)
| #">" => NormalDelete.deleteAroundPair (app, #"<", #">", time)
| _ => NormalFinish.clearMode app
fun parseDeleteTerminal (str, count, app, chrCmd, time) =
@@ -317,26 +322,37 @@ struct
case chr of
#"w" => NormalYankDelete.deleteInsideWord (app, time)
| #"W" => NormalYankDelete.deleteInsideWORD (app, time)
| #"(" => NormalYankDelete.deleteInsideChrOpen (app, chr, time)
| #"[" => NormalYankDelete.deleteInsideChrOpen (app, chr, time)
| #"{" => NormalYankDelete.deleteInsideChrOpen (app, chr, time)
| #"<" => NormalYankDelete.deleteInsideChrOpen (app, chr, time)
| #")" => NormalYankDelete.deleteInsideChrClose (app, chr, time)
| #"]" => NormalYankDelete.deleteInsideChrClose (app, chr, time)
| #"}" => NormalYankDelete.deleteInsideChrClose (app, chr, time)
| #">" => NormalYankDelete.deleteInsideChrClose (app, chr, time)
| #"(" => NormalYankDelete.deleteInsidePair (app, #"(", #")", time)
| #")" => NormalYankDelete.deleteInsidePair (app, #"(", #")", time)
| #"[" => NormalYankDelete.deleteInsidePair (app, #"[", #"]", time)
| #"]" => NormalYankDelete.deleteInsidePair (app, #"[", #"]", time)
| #"{" => NormalYankDelete.deleteInsidePair (app, #"{", #"}", time)
| #"}" => NormalYankDelete.deleteInsidePair (app, #"{", #"}", time)
| #"<" => NormalYankDelete.deleteInsidePair (app, #"<", #">", time)
| #">" => NormalYankDelete.deleteInsidePair (app, #"<", #">", time)
| _ => NormalFinish.clearMode app
fun parseDeleteAround (app, chr, time) =
case chr of
#"(" => NormalYankDelete.deleteAroundChrOpen (app, chr, time)
| #"[" => NormalYankDelete.deleteAroundChrOpen (app, chr, time)
| #"{" => NormalYankDelete.deleteAroundChrOpen (app, chr, time)
| #"<" => NormalYankDelete.deleteAroundChrOpen (app, chr, time)
| #")" => NormalYankDelete.deleteAroundChrClose (app, chr, time)
| #"]" => NormalYankDelete.deleteAroundChrClose (app, chr, time)
| #"}" => NormalYankDelete.deleteAroundChrClose (app, chr, time)
| #">" => NormalYankDelete.deleteAroundChrClose (app, chr, time)
#"w" => NormalYankDelete.deleteAroundWord (app, time)
| #"W" => NormalYankDelete.deleteAroundWORD (app, time)
| #"(" => NormalYankDelete.deleteAroundPair (app, #"(", #")", time)
| #")" => NormalYankDelete.deleteAroundPair (app, #"(", #")", time)
| #"[" => NormalYankDelete.deleteAroundPair (app, #"[", #"]", time)
| #"]" => NormalYankDelete.deleteAroundPair (app, #"[", #"]", time)
| #"{" => NormalYankDelete.deleteAroundPair (app, #"{", #"}", time)
| #"}" => NormalYankDelete.deleteAroundPair (app, #"{", #"}", time)
| #"<" => NormalYankDelete.deleteAroundPair (app, #"<", #">", time)
| #">" => NormalYankDelete.deleteAroundPair (app, #"<", #">", time)
| _ => NormalFinish.clearMode app
fun parseDeleteTerminal (str, count, app, chrCmd, time) =

View File

@@ -1,9 +1,7 @@
# To-do list
- Add tests for:
- Reimplement `di<symbol>` and `da<symbol>`
- They should search for the next char in the specific pair, the same way in Vim
- Add tests for both
- `di<symbol>` and `da<symbol>`
Afterwards, add tests for yanking.