amend 'dw' motion in line with previous commit

This commit is contained in:
2025-12-27 07:32:22 +00:00
parent 9846750c51
commit 742b571b4e
6 changed files with 93 additions and 28 deletions

View File

@@ -16,8 +16,11 @@ struct
val newlineToNewline: Word8.word = 0w9
val chrToNewline: Word8.word = 0w10
val alphaToPunct: Word8.word = 0w11
val punctToAlpha: Word8.word = 0w12
val newlineToAlpha: Word8.word = 0w11
val newlineToPunct: Word8.word = 0w12
val alphaToPunct: Word8.word = 0w13
val punctToAlpha: Word8.word = 0w14
fun makeStart i =
let
@@ -63,10 +66,10 @@ struct
let
val chr = Char.chr i
in
if Char.isAlphaNum chr orelse chr = #"_" then startAlpha
if Char.isAlphaNum chr orelse chr = #"_" then newlineToAlpha
else if chr = #"\n" then newlineToNewline
else if Char.isSpace chr then startSpace
else startPunct
else newlineToPunct
end
val startTable = Vector.tabulate (255, makeStart)
@@ -99,6 +102,9 @@ struct
, newlineTable
, newlineTable
, newlineTable
, startAlphaTable
, startPunctTable
]
structure StartOfNextWord =
@@ -117,6 +123,8 @@ struct
orelse currentState = spaceToAlpha
orelse currentState = spaceToPunct
orelse currentState = newlineToNewline
orelse currentState = newlineToAlpha
orelse currentState = newlineToPunct
fun finish x = x
end)

View File

@@ -33,6 +33,9 @@ struct
val low =
if Cursor.isOnNewlineAfterChr (buffer, low) then low - 1 else low
val buffer =
if #textLength buffer = 0 then LineGap.fromString "\n" else buffer
in
finishAfterDeletingBuffer (app, low, buffer, time, initialMsg)
end
@@ -324,6 +327,52 @@ struct
end
end
fun deleteWord (app as {buffer, ...}: app_type, count, time) =
if #textLength buffer = 1 then
NormalFinish.clearMode app
else
let
val {buffer, cursorIdx, ...} = app
val buffer = LineGap.goToIdx (cursorIdx, buffer)
val high = Cursor.nextWord (buffer, cursorIdx, count)
val buffer = LineGap.goToIdx (high, buffer)
in
(* The Cursor.nextWord skips newlines in some cases,
* which makes sense for the 'w' move motion.
* However, we sometimes don't want to skip newlines when deleting.
* For example, when 'dw' is used on the last word in a line,
* the 'w' motion would go to the first character of the next line
* but the 'dw' motion should delete until the newline. *)
if high >= #textLength buffer then
let
val finish = #textLength buffer - 1
val buffer = LineGap.goToIdx (finish, buffer)
val length =
if Cursor.isCursorAtStartOfLine (buffer, finish) then
finish - cursorIdx
else
high - cursorIdx
in
deleteAndFinish (app, cursorIdx, length, buffer, time)
end
else if Cursor.isCursorAtStartOfLine (buffer, high) then
deleteAndFinish (app, cursorIdx, high - cursorIdx, buffer, time)
else
let
val beforeHigh = high - 1
val buffer = LineGap.goToIdx (beforeHigh, buffer)
val high =
if
Cursor.isCursorAtStartOfLine (buffer, beforeHigh)
andalso beforeHigh <> cursorIdx
then beforeHigh
else high
in
deleteAndFinish (app, cursorIdx, high - cursorIdx, buffer, time)
end
end
fun deleteByDfa (app as {buffer, ...}: app_type, count, fMove, time) =
if #textLength buffer = 1 then
NormalFinish.clearMode app

View File

@@ -257,7 +257,7 @@ struct
* other cursor motions *)
| #"j" => NormalDelete.deleteLineDown (app, count, time)
| #"k" => NormalDelete.deleteLineBack (app, count, time)
| #"w" => NormalDelete.deleteByDfa (app, count, Cursor.nextWord, time)
| #"w" => NormalDelete.deleteWord (app, count, time)
| #"W" => NormalDelete.deleteByDfa (app, count, Cursor.nextWORD, time)
| #"b" => NormalDelete.deleteByDfa (app, count, Cursor.prevWord, time)
| #"B" => NormalDelete.deleteByDfa (app, count, Cursor.prevWORD, time)
@@ -346,7 +346,7 @@ struct
* other cursor motions *)
| #"j" => NormalYankDelete.deleteLineDown (app, count, time)
| #"k" => NormalYankDelete.deleteLineBack (app, count, time)
| #"w" => NormalYankDelete.deleteByDfa (app, count, Cursor.nextWord, time)
| #"w" => NormalYankDelete.deleteWord (app, count, time)
| #"W" => NormalYankDelete.deleteByDfa (app, count, Cursor.nextWORD, time)
| #"b" => NormalYankDelete.deleteByDfa (app, count, Cursor.prevWord, time)
| #"B" => NormalYankDelete.deleteByDfa (app, count, Cursor.prevWORD, time)

View File

@@ -1,4 +1,3 @@
hello
world
again

View File

@@ -944,30 +944,27 @@ struct
in
Expect.isTrue (stringsAreExpected andalso cursorsAreExpected)
end)
, test
"deletes newline when there is a newline after current word \
\and there is another word following that newline"
(fn _ =>
let
(* arrange *)
val originalString = "hello\nworld\nagain\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 1)
, test "does not delete newline following word" (fn _ =>
let
(* arrange *)
val originalString = "hello\nworld\nagain\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, 0)
(* act *)
val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "dw")
(* act *)
val {buffer, cursorIdx, ...} = TestUtils.updateMany (app, "dw")
(* assert *)
val expectedString = "hworld\nagain\n"
val expectedCursor = 1
(* assert *)
val expectedString = "\nworld\nagain\n"
val expectedCursor = 0
val actualString = LineGap.toString buffer
val actualString = LineGap.toString buffer
val stringIsExpected = expectedString = actualString
val cursorIsExpected = expectedCursor = cursorIdx
in
Expect.isTrue (stringIsExpected andalso cursorIsExpected)
end)
val stringIsExpected = expectedString = actualString
val cursorIsExpected = expectedCursor = cursorIdx
in
Expect.isTrue (stringIsExpected andalso cursorIsExpected)
end)
, test
"deletes until first punctuation char when on an alpha char \
\and there is no space between alpha and punctuation"

View File

@@ -754,6 +754,18 @@ struct
(* assert *)
Expect.isTrue (#cursorIdx app = 4)
end)
, test "moves cursor to character after newline" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\nworld\nagain\n"
val app = AppWith.idx (app, 0)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 6)
end)
]
val WMove = describe "move motion 'W'"