mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-02 10:34:04 +02:00
Fix incsearch not updating empty selection
As a by-product, this also fixes an off-by-one error where incsearch would effectively treat all Visual searches as exclusive
This commit is contained in:
parent
a969b93ba6
commit
e9e86b07fb
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
@ -308,6 +308,9 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
||||
protected void textChanged(@NotNull DocumentEvent e) {
|
||||
try {
|
||||
final Editor editor = entry.getEditor();
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String labelText = label.getText(); // Either '/', '?' or ':'boolean searchCommand = false;
|
||||
|
||||
@ -351,8 +354,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
||||
|
||||
if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
|
||||
final boolean forwards = !labelText.equals("?"); // :s, :g, :v are treated as forwards
|
||||
int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
||||
final String pattern = searchText.substring(0, pattenEnd);
|
||||
int patternEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
||||
final String pattern = searchText.substring(0, patternEnd);
|
||||
|
||||
VimPlugin.getEditor().closeEditorSearchSession(editor);
|
||||
final int matchOffset =
|
||||
|
@ -563,7 +563,67 @@ class IncsearchTests : VimTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test incsearch updates selection when started in Visual mode`() {
|
||||
fun `test incsearch updates Visual selection`() {
|
||||
doTest(
|
||||
listOf("ve", "/dolor"),
|
||||
"""
|
||||
|Lorem ipsum dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|${s}Lorem ipsum ${c}d${se}olor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
|
||||
) {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test incsearch updates empty Visual selection`() {
|
||||
doTest(
|
||||
"v/ipsum",
|
||||
"""
|
||||
|Lorem ipsum dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|${s}Lorem ${c}i${se}psum dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
|
||||
) {
|
||||
enterCommand("set hlsearch incsearch")
|
||||
}
|
||||
assertSearchHighlights("ipsum",
|
||||
"""
|
||||
|Lorem ‷ipsum‴ dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test incsearch updates exclusive Visual selection`() {
|
||||
doTest(
|
||||
listOf("ve", "/dolor"),
|
||||
"""
|
||||
@ -580,8 +640,48 @@ class IncsearchTests : VimTestCase() {
|
||||
""".trimMargin(),
|
||||
Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
|
||||
) {
|
||||
enterCommand("set selection=exclusive")
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test incsearch updates empty exclusive Visual selection`() {
|
||||
doTest(
|
||||
"v/ipsum",
|
||||
"""
|
||||
|Lorem ipsum dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|${s}Lorem ${c}${se}ipsum dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
|
||||
) {
|
||||
enterCommand("set selection=exclusive")
|
||||
enterCommand("set hlsearch incsearch")
|
||||
}
|
||||
assertSearchHighlights("ipsum",
|
||||
"""
|
||||
|Lorem ‷ipsum‴ dolor sit amet,
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -20,7 +20,7 @@ import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||
import com.maddyhome.idea.vim.register.Register
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
||||
import com.maddyhome.idea.vim.state.mode.inCommandLineMode
|
||||
import com.maddyhome.idea.vim.state.mode.inCommandLineModeWithVisual
|
||||
import com.maddyhome.idea.vim.state.mode.inSelectMode
|
||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||
import javax.swing.KeyStroke
|
||||
@ -98,27 +98,26 @@ per-caret marks.
|
||||
// Make sure to always reposition the caret, even if the offset hasn't changed. We might need to reposition due to
|
||||
// changes in surrounding text, especially with inline inlays.
|
||||
val oldOffset = this.offset
|
||||
var caretAfterMove = moveToInlayAwareOffset(offset)
|
||||
var updatedCaret = moveToInlayAwareOffset(offset)
|
||||
|
||||
// Similarly, always make sure the caret is positioned within the view. Adding or removing text could move the caret
|
||||
// position relative to the view, without changing offset.
|
||||
if (this == editor.primaryCaret()) {
|
||||
injector.scroll.scrollCaretIntoView(editor)
|
||||
}
|
||||
caretAfterMove = if (editor.inVisualMode || editor.inSelectMode) {
|
||||
|
||||
// If we're in Visual or Select mode, update the selection. We also need to handle Command-line mode, with Visual
|
||||
// pending, e.g. `v/foo` or `v:<C-U>normal 3j`
|
||||
updatedCaret = if (editor.inVisualMode || editor.inSelectMode || editor.inCommandLineModeWithVisual) {
|
||||
// Another inconsistency with immutable caret. This method should be called on the new caret instance.
|
||||
caretAfterMove.vimMoveSelectionToCaret(this.vimSelectionStart)
|
||||
editor.findLastVersionOfCaret(caretAfterMove) ?: caretAfterMove
|
||||
} else if (editor.inCommandLineMode && caretAfterMove.hasSelection()) {
|
||||
// If we're updating the caret in Command-line mode, it's most likely due to incsearch
|
||||
caretAfterMove.setSelection(caretAfterMove.selectionStart, offset)
|
||||
editor.findLastVersionOfCaret(caretAfterMove) ?: caretAfterMove
|
||||
updatedCaret.vimMoveSelectionToCaret(this.vimSelectionStart)
|
||||
editor.findLastVersionOfCaret(updatedCaret) ?: updatedCaret
|
||||
} else {
|
||||
editor.exitVisualMode()
|
||||
caretAfterMove
|
||||
updatedCaret
|
||||
}
|
||||
injector.motion.onAppCodeMovement(editor, this, offset, oldOffset)
|
||||
return caretAfterMove
|
||||
return updatedCaret
|
||||
}
|
||||
|
||||
fun moveToOffsetNative(offset: Int)
|
||||
|
@ -20,6 +20,7 @@ import com.maddyhome.idea.vim.helper.RWLockLabel
|
||||
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.inSelectMode
|
||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||
import com.maddyhome.idea.vim.state.mode.selectionType
|
||||
@ -122,7 +123,7 @@ fun vimMoveBlockSelectionToOffset(editor: VimEditor, offset: Int) {
|
||||
* @see vimMoveBlockSelectionToOffset for blockwise selection
|
||||
*/
|
||||
fun VimCaret.vimMoveSelectionToCaret(vimSelectionStart: Int = this.vimSelectionStart) {
|
||||
if (!editor.inVisualMode && !editor.inSelectMode) error("Attempt to extent selection in non-visual mode")
|
||||
if (!editor.inVisualMode && !editor.inSelectMode && !editor.inCommandLineModeWithVisual) error("Attempt to extent selection in non-visual mode")
|
||||
if (editor.inBlockSelection) error("Move caret with [vimMoveBlockSelectionToOffset]")
|
||||
|
||||
val startOffsetMark = vimSelectionStart
|
||||
|
@ -156,6 +156,13 @@ sealed interface Mode {
|
||||
"CMD_LINE mode can be active only in NORMAL, OP_PENDING, VISUAL or INSERT modes, not ${returnTo.javaClass.simpleName}"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Visual mode is pending, by starting Command-line with a Visual selection
|
||||
*
|
||||
* For example, `v/foo` or `v:<C-U>normal 3j`
|
||||
*/
|
||||
val isVisualPending = returnTo is VISUAL
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,9 @@ val VimEditor.inSelectMode: Boolean
|
||||
val VimEditor.inCommandLineMode: Boolean
|
||||
get() = this.mode is Mode.CMD_LINE
|
||||
|
||||
val VimEditor.inCommandLineModeWithVisual: Boolean
|
||||
get() = (this.mode as? Mode.CMD_LINE)?.isVisualPending == true
|
||||
|
||||
val VimEditor.singleModeActive: Boolean
|
||||
get() = this.mode.isSingleModeActive
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user