mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-05 00:34:04 +02:00
Fix Del and BS not working in Select mode
Fixes VIM-3618
This commit is contained in:
parent
f30e376e11
commit
1d5fc01d65
src
main/java/com/maddyhome/idea/vim/group
test/java/org/jetbrains/plugins/ideavim/action/motion/select
vim-engine/src/main
kotlin/com/maddyhome/idea/vim/action/motion/select
resources/ksp-generated
@ -314,7 +314,7 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
||||
if (c instanceof JComponent) {
|
||||
final List<AnAction> actions = ActionUtil.getActions((JComponent)c);
|
||||
for (AnAction action : actions) {
|
||||
if (action instanceof VimShortcutKeyAction) {
|
||||
if (action instanceof VimShortcutKeyAction || action == VimShortcutKeyAction.getInstance()) {
|
||||
continue;
|
||||
}
|
||||
final Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
|
||||
@ -334,7 +334,11 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
||||
final Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
|
||||
for (String id : keymap.getActionIds(keyStroke)) {
|
||||
final AnAction action = ActionManager.getInstance().getAction(id);
|
||||
if (action != null) {
|
||||
|
||||
// EmptyAction is used to reserve a shortcut, but can't be executed. Code can ask for an action by ID and
|
||||
// use its shortcut(s) to dynamically register a new action on a component in the UI hierarchy. It's not
|
||||
// useful for our needs here - we'll pick up the real action when we get local actions.
|
||||
if (action != null && !(action instanceof EmptyAction)) {
|
||||
results.add(action);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2003-2025 The IdeaVim authors
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE.txt file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.action.motion.select
|
||||
|
||||
import com.maddyhome.idea.vim.state.mode.Mode
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class SelectDeleteActionTest : VimTestCase() {
|
||||
@Test
|
||||
fun `test Delete removes text and returns to Normal mode`() {
|
||||
doTest(
|
||||
listOf("ve", "<C-G>", "<Del>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.NORMAL()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test Delete removes text and returns to Insert mode when invoked from Insert Select`() {
|
||||
doTest(
|
||||
listOf("i", "<S-Right>".repeat(5), "<Del>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.INSERT
|
||||
) {
|
||||
enterCommand("set selectmode=key keymodel=startsel")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test Delete removes text and returns to Replace mode when invoked from Select with pending Replace mode`() {
|
||||
doTest(
|
||||
listOf("R", "<S-Right>".repeat(5), "<Del>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.REPLACE
|
||||
) {
|
||||
enterCommand("set selectmode=key keymodel=startsel")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test Backspace deletes text and returns to Normal mode`() {
|
||||
doTest(
|
||||
listOf("ve", "<C-G>", "<Del>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.NORMAL()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test Backspace removes text and returns to Insert mode when invoked from Insert Select`() {
|
||||
doTest(
|
||||
listOf("i", "<S-Right>".repeat(5), "<BS>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.INSERT
|
||||
) {
|
||||
enterCommand("set selectmode=key keymodel=startsel")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test Backspace removes text and returns to Replace mode when invoked from Select with pending Replace mode`() {
|
||||
doTest(
|
||||
listOf("R", "<S-Right>".repeat(5), "<BS>"),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I ${c}found it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
"""
|
||||
|Lorem Ipsum
|
||||
|
|
||||
|I $c it in a legendary land
|
||||
|consectetur adipiscing elit
|
||||
|Sed in orci mauris.
|
||||
|Cras id tellus in ex imperdiet egestas.
|
||||
""".trimMargin(),
|
||||
Mode.REPLACE
|
||||
) {
|
||||
enterCommand("set selectmode=key keymodel=startsel")
|
||||
}
|
||||
}
|
||||
}
|
@ -19,30 +19,45 @@ import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
/**
|
||||
* @author Alex Plate
|
||||
*/
|
||||
@CommandOrMotion(keys = ["<DEL>"], modes = [Mode.SELECT])
|
||||
class SelectDeleteAction : SelectDeleteBackspaceActionBase() {
|
||||
override val keyStroke: KeyStroke
|
||||
get() = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)
|
||||
}
|
||||
|
||||
@CommandOrMotion(keys = ["<BS>", "<DEL>"], modes = [Mode.SELECT])
|
||||
class SelectDeleteAction : VimActionHandler.SingleExecution() {
|
||||
@CommandOrMotion(keys = ["<BS>"], modes = [Mode.SELECT])
|
||||
class SelectBackspaceAction : SelectDeleteBackspaceActionBase() {
|
||||
override val keyStroke: KeyStroke
|
||||
get() = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
|
||||
}
|
||||
|
||||
abstract class SelectDeleteBackspaceActionBase : VimActionHandler.SingleExecution() {
|
||||
override val type: Command.Type = Command.Type.INSERT
|
||||
|
||||
abstract val keyStroke: KeyStroke
|
||||
|
||||
override fun execute(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
cmd: Command,
|
||||
operatorArguments: OperatorArguments,
|
||||
): Boolean {
|
||||
val enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
|
||||
val actions = injector.keyGroup.getActions(editor, enterKeyStroke)
|
||||
// TODO: It would be nice to know _why_ we use native actions for Delete/Backspace
|
||||
// If there's some kind of additional native editor action bound to Delete or Backspace (e.g. cancelling something,
|
||||
// etc.) then we should of course invoke it, like we do with Escape or Enter. But if we do, we should reconsider
|
||||
// unconditionally exiting Select mode. If the additional native editor action doesn't delete the text, then we're
|
||||
// exiting Select mode incorrectly. If there isn't an additional native editor action, then would it just be simpler
|
||||
// to delete the selected text using editor APIs?
|
||||
val actions = injector.keyGroup.getActions(editor, keyStroke)
|
||||
for (action in actions) {
|
||||
if (injector.actionExecutor.executeAction(editor, action, context)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Note that Vim returns to the pending mode. I.e., when starting Select from Normal/Visual, it will return to
|
||||
// Normal. When returning from Insert or Replace pending Select (via shifted keys), it will return to Insert/Replace
|
||||
editor.exitSelectModeNative(true)
|
||||
injector.changeGroup.insertBeforeCursor(editor, context)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@
|
||||
},
|
||||
{
|
||||
"keys": "<BS>",
|
||||
"class": "com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction",
|
||||
"class": "com.maddyhome.idea.vim.action.motion.select.SelectBackspaceAction",
|
||||
"modes": "S"
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user