Skip to content

Commit

Permalink
Merge pull request #337 from citizenmatt/feature/guicursor
Browse files Browse the repository at this point in the history
guicursor!
  • Loading branch information
AlexPl292 authored Oct 5, 2021
2 parents 362f8a3 + ee74367 commit 067af83
Show file tree
Hide file tree
Showing 61 changed files with 1,621 additions and 560 deletions.
1 change: 1 addition & 0 deletions resources/dictionaries/ideavim.dic
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ideavimrc


gdefault
guicursor
hlsearch
ideamarks
ignorecase
Expand Down
4 changes: 4 additions & 0 deletions resources/messages/IdeaVimBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ E475=E475: Invalid argument: {0}
# Vim's message includes alternate files and the :p:h file name modifier, which we don't support
# E499: Empty file name for '%' or '#', only works with ":p:h"
E499=E499: Empty file name for '%'
E545=E545: Missing colon: {0}
E546=E546: Illegal mode: {0}
E548=E548: Digit expected: {0}
E549=E549: Illegal percentage: {0}
E774=E774: 'operatorfunc' is empty

action.VimPluginToggle.text=Vim Emulator
Expand Down
24 changes: 17 additions & 7 deletions src/com/maddyhome/idea/vim/KeyHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Ref;
import com.maddyhome.idea.vim.action.change.VimRepeater;
import com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction;
import com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction;
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction;
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction;
import com.maddyhome.idea.vim.action.macro.ToggleRecordingAction;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.group.ChangeGroup;
import com.maddyhome.idea.vim.group.RegisterGroup;
import com.maddyhome.idea.vim.group.visual.VisualGroupKt;
import com.maddyhome.idea.vim.handler.ActionBeanClass;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.*;
Expand Down Expand Up @@ -327,6 +327,7 @@ else if (commandBuilder.isBad()) {
LOG.trace("Command builder is set to BAD");
editorState.resetOpPending();
editorState.resetRegisterPending();
editorState.resetReplaceCharacter();
VimPlugin.indicateError();
reset(editor);
}
Expand Down Expand Up @@ -363,7 +364,11 @@ public static <T> boolean isPrefix(@NotNull List<T> list1, @NotNull List<T> list
}

private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, final @NotNull DataContext context, @NotNull CommandState editorState) {
if (editorState.getCommandBuilder().isAtDefaultState()) {
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
if (commandBuilder.isAwaitingCharOrDigraphArgument()) {
editorState.resetReplaceCharacter();
}
if (commandBuilder.isAtDefaultState()) {
RegisterGroup register = VimPlugin.getRegister();
if (register.getCurrentRegister() == register.getDefaultRegister()) {
boolean indicateError = true;
Expand All @@ -383,7 +388,6 @@ private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, f
}
}
reset(editor);
ChangeGroup.resetCaret(editor, false);
}

private boolean handleKeyMapping(final @NotNull Editor editor,
Expand Down Expand Up @@ -688,6 +692,8 @@ private void handleCharArgument(@NotNull KeyStroke key, char chKey, @NotNull Com
// Oops - this isn't a valid character argument
commandBuilder.setCommandState(CurrentCommandState.BAD_COMMAND);
}

commandState.resetReplaceCharacter();
}

private boolean handleDigraph(@NotNull Editor editor,
Expand Down Expand Up @@ -899,7 +905,8 @@ private void startWaitingForArgument(Editor editor,
if (action instanceof InsertCompletedDigraphAction) {
editorState.startDigraphSequence();
setPromptCharacterEx('?');
} else if (action instanceof InsertCompletedLiteralAction) {
}
else if (action instanceof InsertCompletedLiteralAction) {
editorState.startLiteralSequence();
setPromptCharacterEx('^');
}
Expand All @@ -912,6 +919,11 @@ private void startWaitingForArgument(Editor editor,
editorState.pushModes(CommandState.Mode.CMD_LINE, CommandState.SubMode.NONE);
break;
}

// Another special case. Force a mode change to update the caret shape
if (action instanceof ChangeCharacterAction || action instanceof ChangeVisualCharacterAction) {
editorState.pushModes(editorState.getMode(), CommandState.SubMode.REPLACE_CHARACTER);
}
}

private boolean checkArgumentCompatibility(@Nullable Argument.Type expectedArgumentType, @NotNull EditorActionHandlerBase action) {
Expand Down Expand Up @@ -971,7 +983,6 @@ public void fullReset(@NotNull Editor editor) {
if (registerGroup != null) {
registerGroup.resetRegister();
}
VisualGroupKt.updateCaretState(editor);
editor.getSelectionModel().removeSelection();
}

Expand Down Expand Up @@ -1066,7 +1077,6 @@ public void run() {
if (editorState.getSubMode() == CommandState.SubMode.SINGLE_COMMAND &&
(!cmd.getFlags().contains(CommandFlags.FLAG_EXPECT_MORE))) {
editorState.popModes();
VisualGroupKt.resetShape(CommandStateHelper.getMode(editor), editor);
}

if (editorState.getCommandBuilder().isDone()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.visual.updateCaretState
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
Expand Down Expand Up @@ -60,7 +59,6 @@ class SelectToggleVisualMode : VimActionHandler.SingleExecution() {
}
}
}
updateCaretState(editor)
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.option.ListOption
import com.maddyhome.idea.vim.option.OptionsManager.selectmode
import com.maddyhome.idea.vim.option.StringListOption

class VisualToggleBlockModeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_READONLY

override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
val listOption: ListOption = selectmode
val listOption: StringListOption = selectmode
return if (listOption.contains("cmd")) {
VimPlugin.getVisualMotion().enterSelectMode(editor, CommandState.SubMode.VISUAL_BLOCK)
} else VimPlugin.getVisualMotion()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.option.ListOption
import com.maddyhome.idea.vim.option.OptionsManager.selectmode
import com.maddyhome.idea.vim.option.StringListOption

class VisualToggleCharacterModeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_READONLY

override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
val listOption: ListOption = selectmode
val listOption: StringListOption = selectmode
return if (listOption.contains("cmd")) {
VimPlugin.getVisualMotion().enterSelectMode(editor, CommandState.SubMode.VISUAL_CHARACTER)
} else VimPlugin.getVisualMotion()
Expand Down
50 changes: 35 additions & 15 deletions src/com/maddyhome/idea/vim/command/CommandState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import com.maddyhome.idea.vim.helper.DigraphSequence
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.VimNlsSafe
import com.maddyhome.idea.vim.helper.noneOfEnum
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
import com.maddyhome.idea.vim.helper.updateCaretsVisualPosition
import com.maddyhome.idea.vim.helper.vimCommandState
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.option.OptionsManager.showmode
Expand All @@ -35,17 +37,17 @@ import java.util.*
import javax.swing.KeyStroke

/**
* Used to maintain state while entering a Vim command (operator, motion, text object, etc.)
* Used to maintain state before and while entering a Vim command (operator, motion, text object, etc.)
*/
class CommandState private constructor() {
class CommandState private constructor(private val editor: Editor) {
val commandBuilder = CommandBuilder(getKeyRootNode(MappingMode.NORMAL))
private val modeStates = Stack<ModeState>()
val mappingState = MappingState()
private val digraphSequence = DigraphSequence()
var isRecording = false
set(value) {
field = value
updateStatus()
doShowMode()
}
var isDotRepeatInProgress = false

Expand Down Expand Up @@ -78,17 +80,26 @@ class CommandState private constructor() {

fun pushModes(mode: Mode, submode: SubMode) {
val newModeState = ModeState(mode, submode)

logger.debug("Push new mode state: ${newModeState.toSimpleString()}")
logger.debug { "Stack of mode states before push: ${toSimpleString()}" }

val previousMode = currentModeState()
modeStates.push(newModeState)
setMappingMode()
updateStatus()

if (previousMode != newModeState) {
onModeChanged()
}
}

fun popModes() {
val popped = modeStates.pop()
setMappingMode()
updateStatus()
if (popped != currentModeState()) {
onModeChanged()
}

logger.debug("Popped mode state: ${popped.toSimpleString()}")
logger.debug { "Stack of mode states after pop: ${toSimpleString()}" }
}
Expand All @@ -99,6 +110,12 @@ class CommandState private constructor() {
}
}

fun resetReplaceCharacter() {
if (subMode == SubMode.REPLACE_CHARACTER) {
popModes()
}
}

fun resetRegisterPending() {
if (subMode == SubMode.REGISTER_PENDING) {
popModes()
Expand All @@ -107,13 +124,18 @@ class CommandState private constructor() {

private fun resetModes() {
modeStates.clear()
onModeChanged()
setMappingMode()
}

private fun onModeChanged() {
editor.updateCaretsVisualAttributes()
editor.updateCaretsVisualPosition()
doShowMode()
}

private fun setMappingMode() {
val modeState = currentModeState()
val newMappingMode = if (modeState.mode == Mode.OP_PENDING) MappingMode.OP_PENDING else modeToMappingMode(mode)
mappingState.mappingMode = newMappingMode
mappingState.mappingMode = modeToMappingMode(mode)
}

@Contract(pure = true)
Expand All @@ -124,7 +146,7 @@ class CommandState private constructor() {
Mode.VISUAL -> MappingMode.VISUAL
Mode.SELECT -> MappingMode.SELECT
Mode.CMD_LINE -> MappingMode.CMD_LINE
else -> error("Unexpected mode: $mode")
Mode.OP_PENDING -> MappingMode.OP_PENDING
}
}

Expand All @@ -137,7 +159,6 @@ class CommandState private constructor() {
val modeState = currentModeState()
popModes()
pushModes(modeState.mode, submode)
updateStatus()
}

fun startDigraphSequence() {
Expand Down Expand Up @@ -183,7 +204,6 @@ class CommandState private constructor() {
resetModes()
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
digraphSequence.reset()
updateStatus()
}

fun toSimpleString(): String = modeStates.joinToString { it.toSimpleString() }
Expand Down Expand Up @@ -262,7 +282,7 @@ class CommandState private constructor() {
return if (modeStates.size > 0) modeStates.peek() else defaultModeState
}

private fun updateStatus() {
private fun doShowMode() {
val msg = StringBuilder()
if (showmode.isSet) {
msg.append(getStatusString(modeStates.size - 1))
Expand Down Expand Up @@ -319,10 +339,10 @@ class CommandState private constructor() {
}

enum class SubMode {
NONE, SINGLE_COMMAND, REGISTER_PENDING, VISUAL_CHARACTER, VISUAL_LINE, VISUAL_BLOCK
NONE, SINGLE_COMMAND, REGISTER_PENDING, REPLACE_CHARACTER, VISUAL_CHARACTER, VISUAL_LINE, VISUAL_BLOCK
}

private class ModeState(val mode: Mode, val subMode: SubMode) {
private data class ModeState(val mode: Mode, val subMode: SubMode) {
fun toSimpleString(): String = "$mode:$subMode"
}

Expand All @@ -334,7 +354,7 @@ class CommandState private constructor() {
fun getInstance(editor: Editor): CommandState {
var res = editor.vimCommandState
if (res == null) {
res = CommandState()
res = CommandState(editor)
editor.vimCommandState = res
}
return res
Expand Down
13 changes: 12 additions & 1 deletion src/com/maddyhome/idea/vim/ex/ExExceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@
*/
package com.maddyhome.idea.vim.ex

open class ExException(s: String? = null) : Exception(s)
import com.maddyhome.idea.vim.helper.MessageHelper
import org.jetbrains.annotations.PropertyKey

open class ExException(s: String? = null) : Exception(s) {
var code: String? = null
private set

companion object {
fun message(@PropertyKey(resourceBundle = MessageHelper.BUNDLE) code: String, vararg params: Any) =
ExException(MessageHelper.message(code, *params)).apply { this.code = code }
}
}

class InvalidCommandException(message: String, cmd: String?) : ExException(message + if (cmd != null) " | $cmd" else "")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import com.maddyhome.idea.vim.helper.endOffsetInclusive
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
import com.maddyhome.idea.vim.helper.userData
import com.maddyhome.idea.vim.option.OptionsManager
import org.jetbrains.annotations.NonNls
Expand Down Expand Up @@ -173,6 +174,7 @@ class VimMultipleCursorsExtension : VimExtension {
if (newPositions.size > 0) {
editor.exitVisualMode()
newPositions.forEach { editor.caretModel.addCaret(it, true) ?: return }
editor.updateCaretsVisualAttributes()
return
}

Expand Down Expand Up @@ -216,6 +218,7 @@ class VimMultipleCursorsExtension : VimExtension {
}

val caret = editor.caretModel.addCaret(editor.offsetToVisualPosition(nextOffset), true) ?: return
editor.updateCaretsVisualAttributes()
editor.vimMultipleCursorsLastSelection = selectText(caret, pattern, nextOffset)
} else {
VimPlugin.showMessage(MessageHelper.message("message.no.more.matches"))
Expand Down Expand Up @@ -254,6 +257,7 @@ class VimMultipleCursorsExtension : VimExtension {
selectText(caret, text, match.startOffset)
}
}
editor.updateCaretsVisualAttributes()
}
}

Expand Down
Loading

0 comments on commit 067af83

Please sign in to comment.