1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-05-05 00:34:04 +02:00

Fix end of file edge case deleting previous word

Adds extra tests to confirm that deleting previous word in Insert mode was already working as expected (relates to VIM-1650)

Also fixes an edge case for a test that was marked as behaving differently to Vim, but was actually showing buggy behaviour due to its unorthodox caret placement. It looked like the caret was placed at the end of the line, but it was actually placed _passed_ the last character in the file. Adding extra text below the caret placement would cause the action to behave as expected, and the test would then match Vim behaviour. However, it is possible to get this caret position in the editor and in Vim, with `virtualedit=onemore`, and the IdeaVim implementation was wrong. The test has been updated to provide the correct scenario, and the implementation has been fixed.
This commit is contained in:
Matt Ellis 2025-01-15 12:16:56 +00:00 committed by Alex Pláte
parent be1cc67566
commit afd69eef95
2 changed files with 67 additions and 17 deletions
src/test/java/org/jetbrains/plugins/ideavim/action/change/insert
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api

View File

@ -12,7 +12,6 @@ package org.jetbrains.plugins.ideavim.action.change.insert
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test
@ -76,17 +75,63 @@ class InsertDeletePreviousWordActionTest : VimTestCase() {
)
}
@VimBehaviorDiffers(
"""
If (found) {
if (it) {
legendary
}
${c}
""",
)
@Test
fun `test delete starting from the line end`() {
fun `test delete previous word and trailing whitespace`() {
doTest(
listOf("i", "<C-W>"),
"Lorem ${c}ipsum",
"${c}ipsum",
Mode.INSERT,
)
}
@Test
fun `test delete leading whitespace but not previous new line`() {
doTest(
listOf("i", "<C-W>"),
"""
|Lorem Ipsum
|.....${c}.....
|Lorem ipsum dolor sit amet,
""".trimMargin().dotToSpace(),
"""
|Lorem Ipsum
|${c}.....
|Lorem ipsum dolor sit amet,
""".trimMargin().dotToSpace(),
Mode.INSERT
)
}
// VIM-1650
@Test
fun `test delete leading whitespace but not previous new line 2`() {
doTest(
listOf("i", "<C-W>"),
"""
| public static void Main()
| {
|..${c}..
| }
""".trimMargin().dotToSpace(),
"""
| public static void Main()
| {
|${c}..
| }
""".trimMargin().dotToSpace(),
Mode.INSERT
)
}
@Test
fun `test delete starting from the last character of the file`() {
// This test was originally trying to delete the previous word with the caret positioned at the end of line and
// recorded different behaviour to Vim. The problem was that the caret was incorrectly positioned _passed_ the end
// of the line, and indeed passed the end of the file.
// This placement is valid, both in IdeaVim and Vim, but only when `:set virtualedit=onemore` is set. The test was
// showing a bug in the implementation in this scenario. The test is now explicit in what it's trying to do, and
// matches Vim's behaviour.
doTest(
listOf("i", "<C-W>"),
"""
@ -100,10 +145,13 @@ class InsertDeletePreviousWordActionTest : VimTestCase() {
If (found) {
if (it) {
legendary
${c}
}
${c}
""".trimIndent(),
Mode.INSERT,
)
) {
enterCommand("set virtualedit=onemore")
}
}
// VIM-569 |a| |i_CTRL-W|

View File

@ -316,17 +316,19 @@ abstract class VimSearchHelperBase : VimSearchHelper {
spaceWords: Boolean,
): Int {
var found = false
var _pos = if (pos < size) pos else min(size, (chars.length - 1))
var _pos = pos // CAREFUL! This might be at the end of the file, but we need this for calculations below
// For back searches, skip any current whitespace so we start at the end of a word
if (step < 0 && _pos > 0) {
if (charType(editor, chars[_pos - 1], bigWord) === CharacterHelper.CharacterType.WHITESPACE && !spaceWords) {
_pos = skipSpace(editor, chars, _pos - 1, step, size) + 1
_pos = skipSpace(editor, chars, pos - 1, step, size) + 1
}
if (_pos > 0 && charType(editor, chars[_pos], bigWord) !== charType(editor, chars[_pos - 1], bigWord)) {
// _pos might be at the end of file. Handle this so we don't try to walk backwards based on incorrect char type
if (_pos == size || (_pos > 0 && charType(editor, chars[_pos], bigWord) !== charType(editor, chars[_pos - 1], bigWord))) {
_pos += step
}
}
var res = _pos
var res = _pos.coerceAtMost(size - 1)
if (_pos < 0 || _pos >= size) {
return _pos
}