add additional test for 'dn' motion after finding bug, fixed bug (rewrote high-level delete fundtion in persistent-vector.sml to address it), and begin adding tests for 'dN' motion

This commit is contained in:
2026-03-28 00:45:08 +00:00
parent 3f6eaa730a
commit 9d46ec9f34
4 changed files with 118 additions and 67 deletions

View File

@@ -483,7 +483,7 @@ struct
else else
if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then
empty empty
else if splitIdx < Vector.sub (sizes, 0) then else if splitIdx < #start (Vector.sub (items, 0)) then
tree tree
else else
let let
@@ -743,13 +743,6 @@ struct
let let
val finish = start + length val finish = start + length
val matchBeforeStart = prevMatch (start, tree, 1)
val matchBeforeStart =
if matchBeforeStart >= start then
~1
else
matchBeforeStart
val matchAfterFinish = nextMatch (finish, tree, 1) val matchAfterFinish = nextMatch (finish, tree, 1)
val matchAfterFinish = val matchAfterFinish =
if matchAfterFinish < finish then if matchAfterFinish < finish then
@@ -757,63 +750,47 @@ struct
else else
matchAfterFinish matchAfterFinish
in in
if matchBeforeStart = ~1 andalso matchAfterFinish = ~1 then let
empty val left = splitLeft (start, tree)
else if matchAfterFinish = ~1 then val right = splitRight (finish, tree)
(* there is no match after 'finish', so just split left. in
* No need to decrement or split right, if isEmpty left andalso isEmpty right then
* because the right vector would be empty. *) empty
splitLeft (start, tree) else if isEmpty left then
else if matchBeforeStart = ~1 then (* just decrement right and return it *)
(* We don't want to use left split let
* because there are no elements val rightStart = getStartIdx right
* before the deletion range's 'start'. val shouldBeStartIdx = matchAfterFinish - length
* So we make a right split and then decrement it. *) val difference = rightStart - shouldBeStartIdx
let in
val right = splitRight (finish, tree) if difference = 0 then
in right
if isEmpty right then else
empty decrementBy (difference, right)
else end
let else if isEmpty right then
val startIdx = getStartIdx right (* return left half without doing anything *)
val shouldBeStartIdx = matchAfterFinish - length left
val difference = startIdx - shouldBeStartIdx else
in (* decrement right, and then merge both together *)
if difference = 0 then let
right val leftSize = getFinishIdx left
else if isEmpty right then val rightStartRelative = getStartIdx right
empty val rightStartAbsolute = leftSize + rightStartRelative
else
decrementBy (difference, right)
end
end
else
let
val left = splitLeft (start, tree)
val right = splitRight (finish, tree)
in
if isEmpty right then
left
else
let
val leftSize = getFinishIdx left
val rightStartRelative = getStartIdx right
val rightStartAbsolute = leftSize + rightStartRelative
val shouldBeStartIdx = matchAfterFinish - length val shouldBeStartIdx = matchAfterFinish - length
val difference = rightStartAbsolute - shouldBeStartIdx val difference = rightStartAbsolute - shouldBeStartIdx
in in
if difference = 0 then if difference = 0 then
merge (left, right)
else
let
val right = decrementBy (difference, right)
in
merge (left, right) merge (left, right)
else end
let end
val right = decrementBy (difference, right) end
in
merge (left, right)
end
end
end
end end
(* Usually, when inserting, we want the absolute metadata (* Usually, when inserting, we want the absolute metadata

View File

@@ -144,13 +144,13 @@ struct
in in
(buffer, searchList) (buffer, searchList)
end end
else if PersistentVector.isInRange (idx, searchList) then
(buffer, searchList)
else if Dfa.isDead curState then else if Dfa.isDead curState then
if prevFinalPos = ~1 then if prevFinalPos = ~1 then
(* no match found: restart search from `startPos + 1` *) (* no match found: restart search from `startPos + 1` *)
insertUntilMatch insertUntilMatch
(startPos + 1, buffer, searchList, dfa, 0, startPos + 1, ~1) (startPos + 1, buffer, searchList, dfa, 0, startPos + 1, ~1)
else if PersistentVector.isInRange (prevFinalPos, searchList) then
(buffer, searchList)
else else
(* new match. Insert and continue *) (* new match. Insert and continue *)
let let

View File

@@ -1 +1,2 @@
hellohello hello hello hello
world world world

View File

@@ -5824,7 +5824,6 @@ struct
(* assert *) (* assert *)
Expect.isTrue assertion Expect.isTrue assertion
end) end)
, test "extends match when match should extend after deletion" (fn _ => , test "extends match when match should extend after deletion" (fn _ =>
let let
(* arrange *) (* arrange *)
@@ -5850,6 +5849,41 @@ struct
[{start = 0, finish = 4}, {start = 6, finish = 10}] [{start = 0, finish = 4}, {start = 6, finish = 10}]
val expectedNewSearchList = [{start = 0, finish = 9}] val expectedNewSearchList = [{start = 0, finish = 9}]
val assertion =
oldSearchList = expectedOldSearchList
andalso newSearchList = expectedNewSearchList
in
Expect.isTrue assertion
end)
, test "detects match when we delete in middle of it" (fn _ =>
let
(* arrange *)
val originalIdx = 1
val originalString = "hello hello hello\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, originalIdx)
val app = TestUtils.updateMany (app, "/hello")
val app = AppUpdate.update (app, InputMsg.KEY_ENTER, Time.now ())
(* act *)
val newApp = TestUtils.updateMany (app, "dn")
(* assert *)
val oldSearchList = #searchList app
val oldSearchList = PersistentVector.toList oldSearchList
val newSearchList = #searchList newApp
val newSearchList = PersistentVector.toList newSearchList
val expectedOldSearchList =
[ {start = 0, finish = 4}
, {start = 6, finish = 10}
, {start = 12, finish = 16}
]
val expectedNewSearchList =
[{start = 1, finish = 5}, {start = 7, finish = 11}]
val assertion = val assertion =
oldSearchList = expectedOldSearchList oldSearchList = expectedOldSearchList
andalso newSearchList = expectedNewSearchList andalso newSearchList = expectedNewSearchList
@@ -5952,6 +5986,45 @@ struct
(actualString = expectedString (actualString = expectedString
andalso cursorIdx = expectedCursorIdx) andalso cursorIdx = expectedCursorIdx)
end) end)
, test
"decrements subsequent matches in search list \
\when we delete prior to last match"
(fn _ =>
let
(* arrange *)
val originalIdx = 1
val originalString = "hello hello hello\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, originalIdx)
val app = TestUtils.updateMany (app, "/hello")
val app = AppUpdate.update (app, InputMsg.KEY_ENTER, Time.now ())
(* act *)
val newApp = TestUtils.updateMany (app, "dN")
(* assert *)
val oldSearchList = #searchList app
val oldSearchList = PersistentVector.toList oldSearchList
val newSearchList = #searchList newApp
val newSearchList = PersistentVector.toList newSearchList
val expectedOldSearchList =
[ {start = 0, finish = 4}
, {start = 6, finish = 10}
, {start = 12, finish = 16}
]
val expectedNewSearchList =
[{start = 5, finish = 9}, {start = 11, finish = 15}]
val assertion =
oldSearchList = expectedOldSearchList
andalso newSearchList = expectedNewSearchList
in
Expect.isTrue assertion
end)
] ]
val dfDelete = describe "delete motion 'df<char>'" val dfDelete = describe "delete motion 'df<char>'"