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

Select leading whitespace with viw

Inner word/WORD motions will select leading whitespace at the start of a line without wrapping
This commit is contained in:
Matt Ellis 2025-01-16 13:27:55 +00:00 committed by Alex Pláte
parent 1769804c8a
commit d9e575d4a2
3 changed files with 231 additions and 15 deletions
src/test/java/org/jetbrains/plugins/ideavim/action/motion/object
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api

View File

@ -66,6 +66,54 @@ class MotionInnerBigWordActionTest : VimTestCase() {
)
}
@Test
fun `test select WORD from whitespace at start of line with multiple lines`() {
doTest(
"viW",
"""
|Lorem Ipsum
|
| ${c} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|${s} ${c} ${se}Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select WORD from whitespace at start of line with multiple lines 2`() {
doTest(
"viW",
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
| ${c} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
|${s} ${c} ${se}consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select WORD from whitespace at end of line`() {
doTest(
@ -126,6 +174,64 @@ class MotionInnerBigWordActionTest : VimTestCase() {
)
}
@Test
fun `test select WORD with existing right-to-left selection in whitespace selects leading whitespace at start of file`() {
doTest(
listOf("v", "h", "iW"),
" ${c} Lorem ipsum dolor sit amet",
"${s}${c} ${se} Lorem ipsum dolor sit amet",
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select WORD from whitespace at start of line with multiple lines and existing right-to-left selection`() {
doTest(
listOf("v", "h", "iW"),
"""
|Lorem Ipsum
|
| ${c} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|${s}${c} ${se} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select WORD from whitespace at start of line with multiple lines and existing right-to-left-selection 2`() {
doTest(
listOf("v", "h", "iW"),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
| ${c} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
|${s}${c} ${se} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@VimBehaviorDiffers(
originalVimAfter = "${s}Lorem${c}${se} ipsum dolor sit amet, consectetur adipiscing elit",
description = "Text objects are implicitly inclusive, because they set the selection." +

View File

@ -66,6 +66,54 @@ class MotionInnerWordActionTest : VimTestCase() {
)
}
@Test
fun `test select word from whitespace at start of line with multiple lines`() {
doTest(
"viw",
"""
|Lorem Ipsum
|
| ${c} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|${s} ${c} ${se}Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select word from whitespace at start of line with multiple lines 2`() {
doTest(
"viw",
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
| ${c} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
|${s} ${c} ${se}consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select word from whitespace at end of line`() {
doTest(
@ -126,6 +174,64 @@ class MotionInnerWordActionTest : VimTestCase() {
)
}
@Test
fun `test select word with existing right-to-left selection in whitespace selects leading whitespace at start of file`() {
doTest(
listOf("v", "h", "iw"),
" ${c} Lorem ipsum dolor sit amet",
"${s}${c} ${se} Lorem ipsum dolor sit amet",
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select word from whitespace at start of line with multiple lines and existing right-to-left selection`() {
doTest(
listOf("v", "h", "iw"),
"""
|Lorem Ipsum
|
| ${c} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|${s}${c} ${se} Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@Test
fun `test select word from whitespace at start of line with multiple lines and existing right-to-left-selection 2`() {
doTest(
listOf("v", "h", "iw"),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
| ${c} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem Ipsum
|
|Lorem ipsum dolor sit amet
|${s}${c} ${se} consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.VISUAL(SelectionType.CHARACTER_WISE),
)
}
@VimBehaviorDiffers(
originalVimAfter = "${s}Lorem${c}${se} ipsum dolor sit amet, consectetur adipiscing elit",
description = "Text objects are implicitly inclusive, because they set the selection." +

View File

@ -352,9 +352,8 @@ abstract class VimSearchHelperBase : VimSearchHelper {
}
type = charType(editor, chars[res], bigWord)
found = true
}
else if (newChar == '\n' && lineLength == 0) {
// An empty line is considered a word/WORD
} else if (newChar == '\n' && (spaceWords || lineLength == 0)) {
// An empty line is considered a word/WORD, and if we're matching spaces as words, new line is a terminator
res = if (step < 0) _pos + 1 else _pos
found = true
}
@ -1447,18 +1446,23 @@ abstract class VimSearchHelperBase : VimSearchHelper {
false
}
// Include preceding whitespace:
// ✓ Outer text object (`aw`) AND
// ✓ No forward heading selection AND
// ✓ Started on space, and there's no selection
// ✓ OR backward heading selection, but didn't start on space
// ✓ OR no whitespace after the word under cursor (see `:help v_a'`), as long as there's another word before
val includePrecedingWhitespace = isOuter
&& !hasForwardHeadingSelection
&& ((startSpace && !hasSelection)
|| (hasBackwardHeadingSelection && !startSpace)
|| (!hasFollowingWhitespace && editor.anyNonWhitespace(start, -1))
)
val includePrecedingWhitespace = if (isOuter) {
// Outer word motion. Include preceding whitespace:
// ✗ NEVER: Has forward-facing selection
// ✓ Started on space, and there's no (forward-facing) selection
// ✓ Started on word and has backward-facing selection
// ✓ No whitespace after word under cursor (see `:help v_a'`), but only if there's a preceding word on the line
!hasForwardHeadingSelection
&& ((startSpace && !hasSelection)
|| (hasBackwardHeadingSelection && !startSpace)
|| (!hasFollowingWhitespace && editor.anyNonWhitespace(start, -1)))
}
else {
// Inner word motion. Include preceding whitespace:
// ✓ Start on space with backwards-facing selection
// ✓ Start on space with no (forwards-facing) selection
startSpace && (hasBackwardHeadingSelection || !hasForwardHeadingSelection)
}
var goForward = dir == 1 && isOuter && ((!startSpace && !onWordEnd) || (startSpace && onWordEnd && hasSelection))
if (!goForward && dir == 1 && isOuter) {