make implementation of 'di<symbol>' more robust (we check if the cursor is inside a symbol-pair before checking if there is a symbol pair after the cursor), and add tests for 'di<symbol>' motion

This commit is contained in:
2026-01-03 08:09:08 +00:00
parent bce2a5a22d
commit ba6798f476
5 changed files with 153 additions and 42 deletions

View File

@@ -209,61 +209,69 @@ struct
val toPrevChr = ToPrevChr.foldPrev val toPrevChr = ToPrevChr.foldPrev
structure ToCloseChrNext = structure ToOpenChrPrev =
MakeIfCharFolderNext MakeIfCharFolderPrev
(struct (struct
type env = {openChr: char, closeChr: char} type env = {openChr: char, closeChr: char}
fun loop (strPos, str, absIdx, stl, openChr, closeChr, openCount) = fun loop (strPos, str, absIdx, stl, openChr, closeChr, closeCount) =
if strPos = String.size str then if strPos < 0 then
case stl of case stl of
str :: stl => str :: stl =>
loop (0, str, absIdx, stl, openChr, closeChr, openCount) loop
( String.size str - 1
, str
, absIdx
, stl
, openChr
, closeChr
, closeCount
)
| [] => ~1 | [] => ~1
else else
let let
val chr = String.sub (str, strPos) val chr = String.sub (str, strPos)
in in
if chr = openChr then if chr = openChr then
loop if closeCount = 0 then
( strPos + 1
, str
, absIdx + 1
, stl
, openChr
, closeChr
, openCount + 1
)
else if chr = closeChr then
if openCount = 0 then
absIdx absIdx
else else
loop loop
( strPos + 1 ( strPos - 1
, str , str
, absIdx + 1 , absIdx - 1
, stl , stl
, openChr , openChr
, closeChr , closeChr
, openCount - 1 , closeCount - 1
) )
else else if chr = closeChr then
loop loop
( strPos + 1 ( strPos - 1
, str , str
, absIdx + 1 , absIdx - 1
, stl , stl
, openChr , openChr
, closeChr , closeChr
, openCount , closeCount + 1
)
else
loop
( strPos - 1
, str
, absIdx - 1
, stl
, openChr
, closeChr
, closeCount
) )
end end
fun fStart (strPos, str, _, absIdx, stl, _, {openChr, closeChr}) = fun fStart (strPos, str, _, absIdx, stl, _, {openChr, closeChr}) =
loop (strPos + 1, str, absIdx + 1, stl, openChr, closeChr, 0) loop (strPos, str, absIdx, stl, openChr, closeChr, 0)
end) end)
val toCloseChrNext = ToCloseChrNext.foldNext val toOpenChrPrev = ToOpenChrPrev.foldPrev
structure NextPairChr = structure NextPairChr =
MakeIfCharFolderNext MakeIfCharFolderNext

View File

@@ -1068,29 +1068,56 @@ struct
val cursorChr = LineGap.sub (cursorIdx, buffer) val cursorChr = LineGap.sub (cursorIdx, buffer)
in in
if cursorChr = openChr orelse cursorChr = closeChr then if cursorChr = openChr orelse cursorChr = closeChr then
(* cursor is at pair, so match and delete *)
let let
val otherIdx = Cursor.matchPair (buffer, cursorIdx) val otherIdx = Cursor.matchPair (buffer, cursorIdx)
in in
finishDeletingInsidePair (app, buffer, cursorIdx, otherIdx, dfa, time) if otherIdx = ~1 then
end
else
let
val nextIdx =
Cursor.toCloseChrNext
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
in
if nextIdx = ~1 then
NormalFinish.clearMode app NormalFinish.clearMode app
else else
finishDeletingInsidePair
(app, buffer, cursorIdx, otherIdx, dfa, time)
end
else
(* check to see if we are inside pair *)
let
val prevIdx =
Cursor.toOpenChrPrev
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
in
if prevIdx = ~1 then
(* no openChr before cursor, so check after cursor *)
let let
val buffer = LineGap.goToIdx (nextIdx, buffer) val nextIdx =
val matchIdx = Cursor.matchPair (buffer, nextIdx) Cursor.toNextChr
(buffer, cursorIdx, {findChr = openChr, count = 1})
in in
if matchIdx = ~1 then 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
finishDeletingInsidePair
(app, buffer, nextIdx, matchIdx, dfa, time)
end
end
else
(* there is an openChr before cursor, so match it,
* and if there is a match, then delete *)
let
val buffer = LineGap.goToIdx (prevIdx, buffer)
val otherIdx = Cursor.matchPair (buffer, prevIdx)
in
if otherIdx = ~1 then
NormalFinish.clearMode app NormalFinish.clearMode app
else else
finishDeletingInsidePair finishDeletingInsidePair
(app, buffer, nextIdx, matchIdx, dfa, time) (app, buffer, prevIdx, otherIdx, dfa, time)
end end
end end
end end
@@ -1155,8 +1182,7 @@ struct
else else
let let
val nextIdx = val nextIdx =
Cursor.toCloseChrNext Cursor.toNextChr (buffer, cursorIdx, {findChr = openChr, count = 1})
(buffer, cursorIdx, {openChr = openChr, closeChr = closeChr})
in in
if nextIdx = ~1 then if nextIdx = ~1 then
NormalFinish.clearMode app NormalFinish.clearMode app

View File

@@ -1 +1 @@
( ( ( hello ) ) ) ( ( hello ) )

View File

@@ -5075,6 +5075,82 @@ struct
end) end)
] ]
val diParenDelete = describe "delete motion 'di('"
[ test "does not delete when there is no ( after the cursor" (fn _ =>
let
(* arrange *)
val originalString = " ( ) hello\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 7)
(* act *)
val {buffer, ...} = TestUtils.updateMany (app, "di(")
(* assert *)
val expectedString = originalString
val actualString = LineGap.toString buffer
in
Expect.isTrue (expectedString = actualString)
end)
, test
"deletes pair after cursor when there is a pair \
\before the cursor and after the cursor"
(fn _ =>
let
(* arrange *)
val originalString = " ( abc ) xyz ( def )\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 9)
(* act *)
val {buffer, ...} = TestUtils.updateMany (app, "di(")
(* assert *)
val expectedString = " ( abc ) xyz ()\n"
val actualString = LineGap.toString buffer
in
Expect.isTrue (expectedString = actualString)
end)
, test
"deletes inside outer parens when cursor is in \
\outer paren, and there is an inner paren after cursor"
(fn _ =>
let
(* arrange *)
val originalString = "( ( hello ) )\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 1)
(* act *)
val {buffer, ...} = TestUtils.updateMany (app, "di(")
(* assert *)
val expectedString = "()\n"
val actualString = LineGap.toString buffer
in
Expect.isTrue (expectedString = actualString)
end)
, test
"deletes inside inner parren when cursor is in inner paren-pair, \
\and there is an outer paren above this inner paren"
(fn _ =>
let
(* arrange *)
val originalString = "( ( hello ) )\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 5)
(* act *)
val {buffer, ...} = TestUtils.updateMany (app, "di(")
(* assert *)
val expectedString = "( () )\n"
val actualString = LineGap.toString buffer
in
Expect.isTrue (expectedString = actualString)
end)
]
val tests = val tests =
[ dhDelete [ dhDelete
, dlDelete , dlDelete
@@ -5105,5 +5181,6 @@ struct
, dawDelete , dawDelete
, daWDelete , daWDelete
, pairDelete , pairDelete
, diParenDelete
] ]
end end

View File

@@ -1,7 +1,7 @@
# To-do list # To-do list
- Add tests for: - Add tests for:
- `di<symbol>` and `da<symbol>` - `da<symbol>`
Afterwards, add tests for yanking. Afterwards, add tests for yanking.