Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some missing maps #1034

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ class ScrollPageDownActionTest : VimTestCase() {
assertVisibleArea(33, 67)
}

@TestWithoutNeovim(SkipNeovimReason.SCROLL)
@Test
fun `test scroll single page down with S-Enter`() {
configureByPages(5)
setPositionAndScroll(0, 0)
typeText("<S-Enter>")
assertPosition(33, 0)
assertVisibleArea(33, 67)
}

@TestWithoutNeovim(SkipNeovimReason.SCROLL)
@Test
fun `test scroll page down in insert mode with S-Down`() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,24 @@ import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.*

@CommandOrMotion(keys = ["<C-F>", "<PageDown>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
// The <S-Enter> mapping is interesting. Vim has multiple mappings to move the caret down: <Down>, obviously, but also
// <Enter>, <C-N>, `+` and `j`. While there are some differences (<Enter> and `+` have a flag that moves the caret to
// the start of the line), there is just one function to handle all of these keys and move the caret down.
// This function checks if Shift is held down, in which case it will scroll the page forward, because <S-Down> behaves
// the same as <C-F>. The side effect is that all shift+"down" shortcuts will now scroll forward, including <S-Enter>.
// However, Vim does not support shifted ctrl shortcuts because terminals only support simple ascii control characters.
// So <C-S-N> doesn't scroll forward. Shift+j becomes `J`, which joins multiple lines. And on a typical US/UK keyboard,
// `+` requires shift to type, so can only be typed with the numpad. Vim does not allow remapping <s-+>.
// (IdeaVim does not get shift+numpadPlus, only "typed +". We might get it for a keypress, but by the time it's
// converted to a typed char, we lose the modifier).
// The same logic holds for <Up> and shift - <C-P>, `k` and `-` should scroll backwards, but <C-S-P> isn't valid, `K` is
// a different action, and shift+numpadMinus works but can't be remapped (or handled by IdeaVim).
// Ironically, Vim registers separate functions for <S-Down> and <S-Up>, so the non-shifted functions don't actually
// need to check for shift. So this is all side effect...
// See https://github.com/vim/vim/issues/15107
// Note that IdeaVim handles <S-Down> separately because it behaves differently based on 'keymodel'
// TODO: Is there any way for IdeaVim to handle shift+numpadPlus?
@CommandOrMotion(keys = ["<C-F>", "<PageDown>", "<S-Enter>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class MotionScrollPageDownAction : VimActionHandler.SingleExecution() {

override val type: Command.Type = Command.Type.OTHER_READONLY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler

@CommandOrMotion(keys = ["gt"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
@CommandOrMotion(keys = ["gt", "<C-PageDown>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class NextTabAction : VimActionHandler.SingleExecution() {
override fun execute(
editor: VimEditor,
Expand All @@ -30,3 +30,19 @@ class NextTabAction : VimActionHandler.SingleExecution() {

override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
}

@CommandOrMotion(keys = ["<C-PageDown>"], modes = [Mode.INSERT])
class InsertNextTabAction : VimActionHandler.SingleExecution() {
override fun execute(
editor: VimEditor,
context: ExecutionContext,
cmd: Command,
operatorArguments: OperatorArguments,
): Boolean {
// Vim doesn't change mode
injector.motion.moveCaretGotoNextTab(editor, context, cmd.rawCount)
return true
}

override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler

@CommandOrMotion(keys = ["gT"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
@CommandOrMotion(keys = ["gT", "<C-PageUp>"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
class PreviousTabAction : VimActionHandler.SingleExecution() {
override fun execute(
editor: VimEditor,
Expand All @@ -30,3 +30,18 @@ class PreviousTabAction : VimActionHandler.SingleExecution() {

override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
}

@CommandOrMotion(keys = ["<C-PageUp>"], modes = [Mode.INSERT])
class InsertPreviousTabAction : VimActionHandler.SingleExecution() {
override fun execute(
editor: VimEditor,
context: ExecutionContext,
cmd: Command,
operatorArguments: OperatorArguments,
): Boolean {
injector.motion.moveCaretGotoPreviousTab(editor, context, cmd.rawCount)
return true
}

override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,101 +93,94 @@ abstract class VimStringParserBase : VimStringParser {
}
try {
name = String(Character.toChars(keyCode))
} catch (ignored: IllegalArgumentException) {
} catch (_: IllegalArgumentException) {
}
}
return if (name != null) "<$prefix$name>" else "<<$keyStroke>>"
}

override fun parseKeys(string: String): List<KeyStroke> {
val result: MutableList<KeyStroke> = ArrayList()
var specialKeyStart = '<'
override fun parseKeys(string: String): List<KeyStroke> = buildList {
val specialKeyBuilder = StringBuilder()
var state = KeyParserState.INIT
var specialKeyBuilder = StringBuilder()
for (element in string) {

for (c in string) {
when (state) {
KeyParserState.INIT -> when (element) {
KeyParserState.INIT -> when (c) {
'\\' -> state = KeyParserState.ESCAPE
'<', '«' -> {
specialKeyStart = element
'<' -> {
state = KeyParserState.SPECIAL
specialKeyBuilder = StringBuilder()
specialKeyBuilder.clear()
}
else -> {
val stroke: KeyStroke = if (element == '\t' || element == '\n') {
KeyStroke.getKeyStroke(element.code, 0)
} else if (isControlCharacter(element)) {
KeyStroke.getKeyStroke(element.code + 'A'.code - 1, InputEvent.CTRL_DOWN_MASK)
val stroke: KeyStroke = if (c == '\t' || c == '\n') {
KeyStroke.getKeyStroke(c.code, 0)
} else if (isControlCharacter(c)) {
KeyStroke.getKeyStroke(c.code + 'A'.code - 1, InputEvent.CTRL_DOWN_MASK)
} else {
KeyStroke.getKeyStroke(element)
KeyStroke.getKeyStroke(c)
}
result.add(stroke)
add(stroke)
}
}

KeyParserState.ESCAPE -> {
state = KeyParserState.INIT
if (element != '\\') {
result.add(KeyStroke.getKeyStroke('\\'))
if (c != '\\') {
add(KeyStroke.getKeyStroke('\\'))
}
result.add(KeyStroke.getKeyStroke(element))
add(KeyStroke.getKeyStroke(c))
}
KeyParserState.SPECIAL -> if (element == '>' || element == '»') {
state = KeyParserState.INIT
val specialKeyName = specialKeyBuilder.toString()
val lower = specialKeyName.lowercase(Locale.getDefault())
require("sid" != lower) { "<$specialKeyName> is not supported" }
if ("comma" == lower) {
result.add(KeyStroke.getKeyStroke(','))
} else if ("nop" != lower) {
val leader = parseMapLeader(specialKeyName)
val specialKey = parseSpecialKey(specialKeyName, 0)
if (leader != null) {
result.addAll(leader)
} else if (specialKey != null && specialKeyName.length > 1) {
result.add(specialKey)
} else {
result.add(KeyStroke.getKeyStroke('<'))
result.addAll(stringToKeys(specialKeyName))
result.add(KeyStroke.getKeyStroke('>'))

KeyParserState.SPECIAL -> {
if (c == '>') {
state = KeyParserState.INIT
val specialKeyName = specialKeyBuilder.toString()
val lower = specialKeyName.lowercase(Locale.getDefault())
require("sid" != lower) { "<$specialKeyName> is not supported" }

if ("leader" == lower) {
addAll(getMapLeader())
} else if ("nop" != lower) {
val specialKey = parseSpecialKey(specialKeyName, 0)
if (specialKey != null && specialKeyName.length > 1) {
add(specialKey)
} else {
add(KeyStroke.getKeyStroke('<'))
addAll(stringToKeys(specialKeyName))
add(KeyStroke.getKeyStroke('>'))
}
}
}
} else {
// e.g. move '<-2<CR> - the first part does not belong to any special key
if (element == '<' || element == '«') {
result.add(KeyStroke.getKeyStroke(specialKeyStart))
result.addAll(stringToKeys(specialKeyBuilder.toString()))
specialKeyBuilder = StringBuilder()
} else {
specialKeyBuilder.append(element)
// e.g. move '<-2<CR> - the first part does not belong to any special key
if (c == '<') {
add(KeyStroke.getKeyStroke('<'))
addAll(stringToKeys(specialKeyBuilder.toString()))
specialKeyBuilder.clear()
} else {
specialKeyBuilder.append(c)
}
}
}
}
}

if (state == KeyParserState.ESCAPE) {
result.add(KeyStroke.getKeyStroke('\\'))
add(KeyStroke.getKeyStroke('\\'))
} else if (state == KeyParserState.SPECIAL) {
result.add(KeyStroke.getKeyStroke(specialKeyStart))
result.addAll(stringToKeys(specialKeyBuilder.toString()))
add(KeyStroke.getKeyStroke('<'))
addAll(stringToKeys(specialKeyBuilder.toString()))
}
return result
}

private fun parseMapLeader(s: String): List<KeyStroke>? {
if ("leader".equals(s, ignoreCase = true)) {
val mapLeader: Any? = injector.variableService.getGlobalVariableValue("mapleader")
return if (mapLeader is VimString) {
stringToKeys(mapLeader.value)
} else {
stringToKeys("\\")
}
private fun getMapLeader(): List<KeyStroke> {
val mapLeader: Any? = injector.variableService.getGlobalVariableValue("mapleader")
return if (mapLeader is VimString) {
stringToKeys(mapLeader.value)
} else {
stringToKeys("\\")
}
return null
}

// override fun parseKeysSet(@NonNls vararg keys: String): Set<List<KeyStroke>> = List(keys.size) {
// injector.parser.parseKeys(keys[it])
// }.toSet()

override fun stringToKeys(string: @NonNls String): List<KeyStroke> {
val res: MutableList<KeyStroke> = ArrayList()
for (element in string) {
Expand All @@ -211,6 +204,7 @@ abstract class VimStringParserBase : VimStringParser {
return c < '\u0020'
}

@Suppress("SpellCheckingInspection")
private fun getVimKeyValue(c: Int): @NonNls String? {
return when (c) {
KeyEvent.VK_ENTER -> "cr"
Expand Down Expand Up @@ -498,6 +492,7 @@ abstract class VimStringParserBase : VimStringParser {
return null
}

@Suppress("SpellCheckingInspection")
private fun getVimKeyName(lower: @NonNls String?): Int? {
return when (lower) {
"cr", "enter", "return" -> KeyEvent.VK_ENTER
Expand Down Expand Up @@ -549,6 +544,7 @@ abstract class VimStringParserBase : VimStringParser {
}
}

@Suppress("SpellCheckingInspection")
private fun getVimTypedKeyName(lower: String): Char? {
return when (lower) {
"space" -> ' '
Expand Down
25 changes: 25 additions & 0 deletions vim-engine/src/main/resources/ksp-generated/engine_commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,26 @@
"class": "com.maddyhome.idea.vim.action.window.LookupUpAction",
"modes": "I"
},
{
"keys": "<C-PageDown>",
"class": "com.maddyhome.idea.vim.action.window.tabs.InsertNextTabAction",
"modes": "I"
},
{
"keys": "<C-PageDown>",
"class": "com.maddyhome.idea.vim.action.window.tabs.NextTabAction",
"modes": "NXO"
},
{
"keys": "<C-PageUp>",
"class": "com.maddyhome.idea.vim.action.window.tabs.InsertPreviousTabAction",
"modes": "I"
},
{
"keys": "<C-PageUp>",
"class": "com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction",
"modes": "NXO"
},
{
"keys": "<C-Q>",
"class": "com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction",
Expand Down Expand Up @@ -844,6 +864,11 @@
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction",
"modes": "INXS"
},
{
"keys": "<S-Enter>",
"class": "com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction",
"modes": "NXO"
},
{
"keys": "<S-Home>",
"class": "com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction",
Expand Down
Loading