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

Deprecate OperatorArguments.isOperatorPending

Register specific handlers for Operator-pending mode instead of relying on a runtime flag for behaviour. Also refactors and renames some arrow motion handlers.
This commit is contained in:
Matt Ellis 2024-08-11 00:44:09 +01:00 committed by Alex Pláte
parent 55fef03a4a
commit d185672e2f
11 changed files with 209 additions and 101 deletions

View File

@ -19,10 +19,21 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.NonShiftedSpecialKeyHandler
@CommandOrMotion(keys = ["<Left>", "<kLeft>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class MotionArrowLeftAction : NonShiftedSpecialKeyHandler() {
private fun doMotion(
editor: VimEditor,
caret: ImmutableVimCaret,
count1: Int,
whichwrapKey: String,
allowPastEnd: Boolean,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains(whichwrapKey)
return injector.motion.getHorizontalMotion(editor, caret, count1, allowPastEnd, allowWrap)
}
abstract class MotionNonShiftedArrowLeftBaseAction() : NonShiftedSpecialKeyHandler() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun motion(
@ -32,8 +43,38 @@ class MotionArrowLeftAction : NonShiftedSpecialKeyHandler() {
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains("<")
val allowEnd = operatorArguments.isOperatorPending // d<Left> deletes \n with wrap enabled
return injector.motion.getHorizontalMotion(editor, caret, -operatorArguments.count1, allowEnd, allowWrap)
return doMotion(editor, caret, -operatorArguments.count1, "<", allowPastEnd)
}
protected open val allowPastEnd: Boolean = false
}
// Note that Select mode is handled in [SelectMotionArrowLeftAction]
@CommandOrMotion(keys = ["<Left>", "<kLeft>"], modes = [Mode.NORMAL, Mode.VISUAL])
class MotionArrowLeftAction : MotionNonShiftedArrowLeftBaseAction()
@CommandOrMotion(keys = ["<Left>", "<kLeft>"], modes = [Mode.OP_PENDING])
class MotionArrowLeftOpPendingAction : MotionNonShiftedArrowLeftBaseAction() {
// When the motion is used with an operator, the EOL character is counted.
// This allows e.g., `d<Left>` to delete the end of line character on the previous line when wrap is active
// ('whichwrap' contains "<")
// See `:help whichwrap`. This says a delete or change operator, but it appears to apply to all operators
override val allowPastEnd = true
}
// Just needs to be a plain motion handler - it's not shifted, and the non-shifted actions don't apply in Insert mode
@CommandOrMotion(keys = ["<Left>", "<kLeft>"], modes = [Mode.INSERT])
class MotionArrowLeftInsertModeAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun getOffset(
editor: VimEditor,
caret: ImmutableVimCaret,
context: ExecutionContext,
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
// Insert mode is always allowed past the end of the line
return doMotion(editor, caret, -operatorArguments.count1, "[", allowPastEnd = true)
}
}

View File

@ -19,12 +19,23 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.NonShiftedSpecialKeyHandler
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.usesVirtualSpace
@CommandOrMotion(keys = ["<Right>", "<kRight>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class MotionArrowRightAction : NonShiftedSpecialKeyHandler() {
private fun doMotion(
editor: VimEditor,
caret: ImmutableVimCaret,
count1: Int,
whichwrapKey: String,
allowPastEnd: Boolean,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains(whichwrapKey)
return injector.motion.getHorizontalMotion(editor, caret, count1, allowPastEnd, allowWrap)
}
abstract class MotionNonShiftedArrowRightBaseAction() : NonShiftedSpecialKeyHandler() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun motion(
@ -34,9 +45,38 @@ class MotionArrowRightAction : NonShiftedSpecialKeyHandler() {
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
val allowPastEnd = editor.usesVirtualSpace || editor.isEndAllowed ||
operatorArguments.isOperatorPending // because of `d<Right>` removing the last character
val allowWrap = injector.options(editor).whichwrap.contains(">")
return injector.motion.getHorizontalMotion(editor, caret, operatorArguments.count1, allowPastEnd, allowWrap)
return doMotion(editor, caret, operatorArguments.count1, ">", allowPastEnd(editor))
}
protected open fun allowPastEnd(editor: VimEditor) = editor.usesVirtualSpace || editor.isEndAllowed
}
// Note that Select mode is handled with [SelectMotionArrowRightAction]
@CommandOrMotion(keys = ["<Right>", "<kRight>"], modes = [Mode.NORMAL, Mode.VISUAL])
class MotionArrowRightAction : MotionNonShiftedArrowRightBaseAction()
@CommandOrMotion(keys = ["<Right>", "<kRight>"], modes = [Mode.OP_PENDING])
class MotionArrowRightOpPendingAction : MotionNonShiftedArrowRightBaseAction() {
// When the motion is used with an operator, the EOL character is counted.
// This allows e.g., `d<Right>` to delete the last character in a line. Note that we can't use editor.isEndAllowed to
// give us this because the current mode when we execute the operator/motion is no longer OP_PENDING.
// See `:help whichwrap`. This says a delete or change operator, but it appears to apply to all operators
override fun allowPastEnd(editor: VimEditor) = true
}
// Just needs to be a plain motion handler - it's not shifted, and the non-shifted actions don't apply in Insert mode
@CommandOrMotion(keys = ["<Right>", "<kRight>"], modes = [Mode.INSERT])
class MotionArrowRightInsertModeAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun getOffset(
editor: VimEditor,
caret: ImmutableVimCaret,
context: ExecutionContext,
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
// Insert mode is always allowed past the end of the line
return doMotion(editor, caret, operatorArguments.count1, "]", allowPastEnd = true)
}
}

View File

@ -27,13 +27,9 @@ import com.maddyhome.idea.vim.state.mode.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed
import java.util.*
@CommandOrMotion(keys = ["<End>"], modes = [Mode.INSERT])
class MotionLastColumnInsertAction : MotionLastColumnAction() {
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
}
abstract class MotionLastColumnBaseAction(private val isMotionForOperator: Boolean = false)
: MotionActionHandler.ForEachCaret() {
@CommandOrMotion(keys = ["$"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
open class MotionLastColumnAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.INCLUSIVE
override fun getOffset(
@ -43,13 +39,26 @@ open class MotionLastColumnAction : MotionActionHandler.ForEachCaret() {
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
val allow = if (editor.inVisualMode) {
val allowPastEnd = if (editor.inVisualMode) {
injector.options(editor).selection != "old"
} else {
if (operatorArguments.isOperatorPending) false else editor.isEndAllowed
// Don't allow past end if this motion is for an operator. I.e., for something like `d$`, we don't want to delete
// the end of line character
if (isMotionForOperator) false else editor.isEndAllowed
}
val offset = injector.motion.moveCaretToRelativeLineEnd(editor, caret, operatorArguments.count1 - 1, allow)
val offset = injector.motion.moveCaretToRelativeLineEnd(editor, caret, operatorArguments.count1 - 1, allowPastEnd)
return Motion.AdjustedOffset(offset, VimMotionGroupBase.LAST_COLUMN)
}
}
@CommandOrMotion(keys = ["$"], modes = [Mode.NORMAL, Mode.VISUAL])
open class MotionLastColumnAction : MotionLastColumnBaseAction()
@CommandOrMotion(keys = ["$"], modes = [Mode.OP_PENDING])
class MotionLastColumnOpPendingAction : MotionLastColumnBaseAction(isMotionForOperator = true)
@CommandOrMotion(keys = ["<End>"], modes = [Mode.INSERT])
class MotionLastColumnInsertAction : MotionLastColumnAction() {
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
}

View File

@ -21,8 +21,7 @@ import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
@CommandOrMotion(keys = ["h"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class MotionLeftAction : MotionActionHandler.ForEachCaret() {
abstract class MotionLeftBaseAction(private val allowPastEnd: Boolean) : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun getOffset(
@ -33,23 +32,16 @@ class MotionLeftAction : MotionActionHandler.ForEachCaret() {
operatorArguments: OperatorArguments,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains("h")
val allowEnd = operatorArguments.isOperatorPending // dh deletes \n with wrap enabled
return injector.motion.getHorizontalMotion(editor, caret, -operatorArguments.count1, allowEnd, allowWrap)
return injector.motion.getHorizontalMotion(editor, caret, -operatorArguments.count1, allowPastEnd, allowWrap)
}
}
@CommandOrMotion(keys = ["<Left>", "<kLeft>"], modes = [Mode.INSERT])
class MotionLeftInsertModeAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
@CommandOrMotion(keys = ["h"], modes = [Mode.NORMAL, Mode.VISUAL])
class MotionLeftAction : MotionLeftBaseAction(allowPastEnd = false)
override fun getOffset(
editor: VimEditor,
caret: ImmutableVimCaret,
context: ExecutionContext,
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains("[")
return injector.motion.getHorizontalMotion(editor, caret, -operatorArguments.count1, true, allowWrap)
}
}
// When the motion is used with an operator, the EOL character is counted.
// This allows e.g., `dh` to delete the end of line character on the previous line when wrap is active
// ('whichwrap' contains "h")
// See `:help whichwrap`. This says a delete or change operator, but it appears to apply to all operators
@CommandOrMotion(keys = ["h"], modes = [Mode.OP_PENDING])
class MotionLeftOpPendingModeAction : MotionLeftBaseAction(allowPastEnd = true)

View File

@ -23,8 +23,7 @@ import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.usesVirtualSpace
@CommandOrMotion(keys = ["l"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class MotionRightAction : MotionActionHandler.ForEachCaret() {
abstract class MotionRightBaseAction() : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
override fun getOffset(
@ -35,24 +34,20 @@ class MotionRightAction : MotionActionHandler.ForEachCaret() {
operatorArguments: OperatorArguments,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains("l")
val allowEnd = editor.usesVirtualSpace || editor.isEndAllowed ||
operatorArguments.isOperatorPending // because of `dl` removing the last character
return injector.motion.getHorizontalMotion(editor, caret, operatorArguments.count1, allowPastEnd = allowEnd, allowWrap)
return injector.motion.getHorizontalMotion(editor, caret, operatorArguments.count1, allowPastEnd(editor), allowWrap)
}
protected open fun allowPastEnd(editor: VimEditor) = editor.usesVirtualSpace || editor.isEndAllowed
}
@CommandOrMotion(keys = ["<Right>", "<kRight>"], modes = [Mode.INSERT])
class MotionRightInsertAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
@CommandOrMotion(keys = ["l"], modes = [Mode.NORMAL, Mode.VISUAL])
class MotionRightAction : MotionRightBaseAction()
override fun getOffset(
editor: VimEditor,
caret: ImmutableVimCaret,
context: ExecutionContext,
argument: Argument?,
operatorArguments: OperatorArguments,
): Motion {
val allowWrap = injector.options(editor).whichwrap.contains("]")
return injector.motion.getHorizontalMotion(editor, caret, operatorArguments.count1, allowPastEnd = true, allowWrap)
}
@CommandOrMotion(keys = ["l"], modes = [Mode.OP_PENDING])
class MotionRightOpPendingAction : MotionRightBaseAction() {
// When the motion is used with an operator, the EOL character is counted.
// This allows e.g., `dl` to delete the last character in a line. Note that we can't use editor.isEndAllowed to give
// us this because the current mode when we execute the operator/motion is no longer OP_PENDING.
// See `:help whichwrap`. This says a delete or change operator, but it appears to apply to all operators
override fun allowPastEnd(editor: VimEditor) = true
}

View File

@ -18,23 +18,19 @@ import com.maddyhome.idea.vim.api.moveToMotion
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.handler.ShiftedArrowKeyHandler
/**
* @author Alex Plate
*/
@CommandOrMotion(keys = ["<S-Left>"], modes = [Mode.INSERT, Mode.NORMAL, Mode.VISUAL, Mode.SELECT])
class MotionShiftLeftAction : ShiftedArrowKeyHandler(true) {
class MotionShiftArrowLeftAction : ShiftedArrowKeyHandler(true) {
override val type: Command.Type = Command.Type.OTHER_READONLY
override fun motionWithKeyModel(editor: VimEditor, caret: VimCaret, context: ExecutionContext, cmd: Command) {
val vertical = injector.motion.getHorizontalMotion(editor, caret, -cmd.count, true)
caret.moveToMotion(vertical)
val motion = injector.motion.getHorizontalMotion(editor, caret, -cmd.count, true)
caret.moveToMotion(motion)
}
override fun motionWithoutKeyModel(editor: VimEditor, context: ExecutionContext, cmd: Command) {
val caret = editor.currentCaret()
val newOffset = injector.motion.findOffsetOfNextWord(editor, caret.offset, -cmd.count, false)
caret.moveToMotion(newOffset)
val motion = injector.motion.findOffsetOfNextWord(editor, caret.offset, -cmd.count, false)
caret.moveToMotion(motion)
}
}

View File

@ -16,28 +16,21 @@ import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.moveToMotion
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.ShiftedArrowKeyHandler
/**
* @author Alex Plate
*/
@CommandOrMotion(keys = ["<S-Right>"], modes = [Mode.INSERT, Mode.NORMAL, Mode.VISUAL, Mode.SELECT])
class MotionShiftRightAction : ShiftedArrowKeyHandler(true) {
class MotionShiftArrowRightAction : ShiftedArrowKeyHandler(true) {
override val type: Command.Type = Command.Type.OTHER_READONLY
override fun motionWithKeyModel(editor: VimEditor, caret: VimCaret, context: ExecutionContext, cmd: Command) {
val vertical = injector.motion.getHorizontalMotion(editor, caret, cmd.count, true)
caret.moveToMotion(vertical)
val motion = injector.motion.getHorizontalMotion(editor, caret, cmd.count, true)
caret.moveToMotion(motion)
}
override fun motionWithoutKeyModel(editor: VimEditor, context: ExecutionContext, cmd: Command) {
val caret = editor.currentCaret()
val newOffset = injector.motion.findOffsetOfNextWord(editor, caret.offset, cmd.count, false)
if (newOffset is Motion.AbsoluteOffset) {
caret.moveToOffset(newOffset.offset)
}
val motion = injector.motion.findOffsetOfNextWord(editor, caret.offset, cmd.count, false)
caret.moveToMotion(motion)
}
}

View File

@ -18,6 +18,7 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotion
@ -28,7 +29,7 @@ import com.maddyhome.idea.vim.options.OptionConstants
*/
@CommandOrMotion(keys = ["<Left>"], modes = [Mode.SELECT])
class SelectMotionLeftAction : MotionActionHandler.ForEachCaret() {
class SelectMotionArrowLeftAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
@ -58,6 +59,6 @@ class SelectMotionLeftAction : MotionActionHandler.ForEachCaret() {
}
private companion object {
private val logger = injector.getLogger(SelectMotionLeftAction::class.java)
private val logger = vimLogger<SelectMotionArrowLeftAction>()
}
}

View File

@ -18,6 +18,7 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotion
@ -28,7 +29,7 @@ import com.maddyhome.idea.vim.options.OptionConstants
*/
@CommandOrMotion(keys = ["<Right>"], modes = [Mode.SELECT])
class SelectMotionRightAction : MotionActionHandler.ForEachCaret() {
class SelectMotionArrowRightAction : MotionActionHandler.ForEachCaret() {
override val motionType: MotionType = MotionType.EXCLUSIVE
@ -58,6 +59,6 @@ class SelectMotionRightAction : MotionActionHandler.ForEachCaret() {
}
private companion object {
private val logger = injector.getLogger(SelectMotionRightAction::class.java)
private val logger = vimLogger<SelectMotionArrowRightAction>()
}
}

View File

@ -19,21 +19,26 @@ import com.maddyhome.idea.vim.state.mode.Mode
* Problems with this class:
* * The name is misleading, as it is used when executing motions that do not have an operator, as well as when
* executing the operator itself. Or even when executing actions that are neither operators nor motions
* * [mode] is not necessarily the same as [VimEditor.mode], but it's not clear how or why
* * [mode] is the mode _before_ the command is completed, which is not guaranteed to be the same as the mode once the
* command completes
* * The count is (and must be) the count for the whole command, rather than the operator, or for the in-progress
* motion. This is not it's not clear in this class
*
* @param isOperatorPending `true` if the editor is in [Mode.OP_PENDING] at the time of creating this class.
* @param isOperatorPending Deprecated. The value is used to indicate that a command is operator+motion and changes the
* behaviour of the motion (the EOL character is counted in this scenario - see `:help whichwrap`). It is better to
* register a separate action for [Mode.OP_PENDING] rather than expect a runtime flag for something that can be handled
* statically.
* @param count0 The raw count of the entire command. E.g., if the command is `2d3w`, then this count will be `6`, even
* if when this class is passed to the `d` operator action (the count applies to the motion).
* if when this class is passed to the `d` operator action (the count applies to the motion).
* @param mode The current mode of the editor. This is not guaranteed to match [VimEditor.mode], but it is unclear why.
*/
data class OperatorArguments
@Deprecated(
"Use overload without isOperatorPending. Value can be calculated from mode",
replaceWith = ReplaceWith("OperatorArguments(count0, mode)")
replaceWith = ReplaceWith("OperatorArguments(count0, mode)"),
) constructor(
val isOperatorPending: Boolean,
// This is used by EasyMotion
@Deprecated("It is better to register a separate OP_PENDING action than switch on a runtime flag") val isOperatorPending: Boolean,
val count0: Int,
val mode: Mode,
) {

View File

@ -17,7 +17,12 @@
{
"keys": "$",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "$",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnOpPendingAction",
"modes": "O"
},
{
"keys": "%",
@ -742,16 +747,21 @@
{
"keys": "<Left>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "<Left>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftInsertModeAction",
"modes": "I"
},
{
"keys": "<Left>",
"class": "com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftOpPendingAction",
"modes": "O"
},
{
"keys": "<Left>",
"class": "com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionArrowLeftAction",
"modes": "S"
},
{
@ -792,16 +802,21 @@
{
"keys": "<Right>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "<Right>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightInsertModeAction",
"modes": "I"
},
{
"keys": "<Right>",
"class": "com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightOpPendingAction",
"modes": "O"
},
{
"keys": "<Right>",
"class": "com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionArrowRightAction",
"modes": "S"
},
{
@ -831,7 +846,7 @@
},
{
"keys": "<S-Left>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftArrowLeftAction",
"modes": "INXS"
},
{
@ -841,7 +856,7 @@
},
{
"keys": "<S-Right>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftArrowRightAction",
"modes": "INXS"
},
{
@ -887,23 +902,33 @@
{
"keys": "<kLeft>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "<kLeft>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftInsertModeAction",
"modes": "I"
},
{
"keys": "<kLeft>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftOpPendingAction",
"modes": "O"
},
{
"keys": "<kRight>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "<kRight>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightInsertModeAction",
"modes": "I"
},
{
"keys": "<kRight>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightOpPendingAction",
"modes": "O"
},
{
"keys": "<kUp>",
"class": "com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction",
@ -1667,7 +1692,12 @@
{
"keys": "h",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "h",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionLeftOpPendingModeAction",
"modes": "O"
},
{
"keys": "i",
@ -1777,7 +1807,12 @@
{
"keys": "l",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction",
"modes": "NXO"
"modes": "NX"
},
{
"keys": "l",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionRightOpPendingAction",
"modes": "O"
},
{
"keys": "m",