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

Remove Visual when updating incsearch for a command

This commit is contained in:
Matt Ellis 2025-01-04 00:32:23 +00:00 committed by Alex Pláte
parent 1f68b756d5
commit 308996c4c1
3 changed files with 45 additions and 1 deletions
src
main/java/com/maddyhome/idea/vim/ui/ex
test/java/org/jetbrains/plugins/ideavim/group/search
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/helper

View File

@ -28,6 +28,7 @@ import com.maddyhome.idea.vim.api.VimCommandLineCaret;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
import com.maddyhome.idea.vim.ex.ranges.LineRange;
import com.maddyhome.idea.vim.helper.EngineModeExtensionsKt;
import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
import com.maddyhome.idea.vim.helper.UiHelper;
import com.maddyhome.idea.vim.key.interceptors.VimInputInterceptor;
@ -362,6 +363,15 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
SearchHighlightsHelper.updateIncsearchHighlights(editor, pattern, count1, forwards, caretOffset,
searchRange);
if (matchOffset != -1) {
// Moving the caret will update the Visual selection, which is only valid while performing a search. We want
// to remove the Visual selection when the incsearch is for a command, as this is always unrelated to the
// current selection.
// E.g. `V/foo` should update the selection to the location of the search result. But `V` followed by
// `:<C-U>%s/foo` should remove the selection first.
// We're actually in Command-line with Visual pending. Exiting Visual replaces this with just Command-line
if (searchCommand) {
EngineModeExtensionsKt.exitVisualMode(new IjVimEditor(editor));
}
new IjVimCaret(editor.getCaretModel().getPrimaryCaret()).moveToOffset(matchOffset);
}
else {

View File

@ -987,4 +987,34 @@ class IncsearchTests : VimTestCase() {
enterCommand("set hlsearch incsearch")
}
}
@Test
fun `test incsearch removes Visual when searching with no Visual range`() {
doTest(
listOf("v", ":<C-U>%s/dolor"),
"""
|Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
"""
|Lorem ipsum ${c}dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin(),
Mode.CMD_LINE(Mode.NORMAL())
) {
enterCommand("set hlsearch incsearch")
}
assertSearchHighlights("dolor",
"""
|Lorem ipsum dolor sit amet,
|consectetur adipiscing elit
|Sed in orci mauris.
|Cras id tellus in ex imperdiet egestas.
""".trimMargin()
)
}
}

View File

@ -15,6 +15,7 @@ import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.inBlockSelection
import com.maddyhome.idea.vim.state.mode.inCommandLineModeWithVisual
import com.maddyhome.idea.vim.state.mode.inVisualMode
import com.maddyhome.idea.vim.state.mode.selectionType
@ -26,7 +27,7 @@ fun VimEditor.exitVisualMode() {
}
nativeCarets().forEach(VimCaret::removeSelection)
}
if (inVisualMode) {
if (inVisualMode || inCommandLineModeWithVisual) {
vimLastSelectionType = selectionType
injector.markService.setVisualSelectionMarks(this)
nativeCarets().forEach { it.vimSelectionStartClear() }
@ -34,9 +35,12 @@ fun VimEditor.exitVisualMode() {
// We usually want to return to the mode that we were in before we started Visual. Typically, this will be NORMAL,
// but can be INSERT for "Insert Visual" (`i<C-O>v`). For "Select Visual" (`gh<C-O>`) we can't return to SELECT,
// because we've just removed the selection. We have to return to NORMAL.
// We might also be in Visual while working with the command line, i.e. Command-line with Visual pending. In this
// case, we need to get rid of Visual, but keep the Command-line
val mode = this.mode
this.mode = when {
mode is Mode.VISUAL && mode.isSelectPending -> Mode.NORMAL()
mode is Mode.CMD_LINE && mode.isVisualPending -> Mode.CMD_LINE(Mode.NORMAL())
else -> mode.returnTo
}
}