in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/key/consumers/DigraphConsumer.kt [57:170]
override fun consumeKey(
key: KeyStroke,
editor: VimEditor,
allowKeyMappings: Boolean,
keyProcessResultBuilder: KeyProcessResult.KeyProcessResultBuilder,
): Boolean {
logger.trace { "Entered DigraphConsumer" }
logger.debug("Handling digraph")
// Support starting a digraph/literal sequence if the operator accepts one as an argument, e.g. 'r' or 'f'.
// Normally, we start the sequence (in Insert or CmdLine mode) through a VimAction that can be mapped. Our
// VimActions don't work as arguments for operators, so we have to special case here. Helpfully, Vim appears to
// hardcode the shortcuts, and doesn't support mapping, so everything works nicely.
val keyState = keyProcessResultBuilder.state
val commandBuilder = keyState.commandBuilder
val digraphSequence = keyState.digraphSequence
if (commandBuilder.expectedArgumentType == Argument.Type.DIGRAPH) {
logger.trace("Expected argument is digraph")
if (digraphSequence.isDigraphStart(key)) {
digraphSequence.startDigraphSequence()
commandBuilder.addTypedKeyStroke(key)
return true
}
if (digraphSequence.isLiteralStart(key)) {
digraphSequence.startLiteralSequence()
commandBuilder.addTypedKeyStroke(key)
return true
}
}
val res = digraphSequence.processKey(key, editor)
val keyHandler = KeyHandler.getInstance()
when (res) {
is DigraphResult.Handled -> {
keyProcessResultBuilder.addExecutionStep { lambdaKeyState, _, _ ->
keyHandler.setPromptCharacterEx(res.promptCharacter)
lambdaKeyState.commandBuilder.addTypedKeyStroke(key)
}
return true
}
is DigraphResult.Done -> {
val commandLine = injector.commandLine.getActiveCommandLine()
if (commandLine != null) {
if (key.keyCode == KeyEvent.VK_C && key.modifiers and InputEvent.CTRL_DOWN_MASK != 0) {
return false
} else {
keyProcessResultBuilder.addExecutionStep { _, _, _ ->
commandLine.clearCurrentAction()
}
}
}
keyProcessResultBuilder.addExecutionStep { lambdaKeyState, _, _ ->
if (lambdaKeyState.commandBuilder.expectedArgumentType === Argument.Type.DIGRAPH) {
lambdaKeyState.commandBuilder.fallbackToCharacterArgument()
}
}
val codepoint = res.codepoint ?: return false
keyProcessResultBuilder.addExecutionStep { lambdaKeyState, lambdaEditorState, lambdaContext ->
lambdaKeyState.commandBuilder.addTypedKeyStroke(key)
if (Character.isSupplementaryCodePoint(codepoint)) {
val charArray = Character.toChars(codepoint)
val highSurrogate = charArray[0]
val lowSurrogate = charArray[1]
val keyStrokeHigh = KeyStroke.getKeyStroke(highSurrogate)
keyHandler.handleKey(lambdaEditorState, keyStrokeHigh, lambdaContext, lambdaKeyState)
val keyStrokeLow = KeyStroke.getKeyStroke(lowSurrogate)
keyHandler.handleKey(lambdaEditorState, keyStrokeLow, lambdaContext, lambdaKeyState)
}
else {
val stroke = KeyStroke.getKeyStroke(codepoint.toChar())
keyHandler.handleKey(lambdaEditorState, stroke, lambdaContext, lambdaKeyState)
}
}
return true
}
is DigraphResult.Bad -> {
val commandLine = injector.commandLine.getActiveCommandLine()
if (commandLine != null) {
if (key.keyCode == KeyEvent.VK_C && key.modifiers and InputEvent.CTRL_DOWN_MASK != 0) {
return false
} else {
keyProcessResultBuilder.addExecutionStep { _, _, _ ->
commandLine.clearCurrentAction()
}
}
}
keyProcessResultBuilder.addExecutionStep { lambdaKeyState, lambdaEditor, _ ->
// BAD is an error. We were expecting a valid character, and we didn't get it.
if (lambdaKeyState.commandBuilder.expectedArgumentType != null) {
KeyHandler.getInstance().setBadCommand(lambdaEditor, lambdaKeyState)
}
}
return true
}
is DigraphResult.Unhandled -> {
// UNHANDLED means the keystroke made no sense in the context of a digraph, but isn't an error in the current
// state. E.g. waiting for {char} <BS> {char}. Let the key handler have a go at it.
if (commandBuilder.expectedArgumentType === Argument.Type.DIGRAPH) {
commandBuilder.fallbackToCharacterArgument()
keyProcessResultBuilder.addExecutionStep { lambdaKeyState, lambdaEditor, lambdaContext ->
keyHandler.handleKey(lambdaEditor, key, lambdaContext, lambdaKeyState)
}
return true
}
return false
}
}
}