1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-08-17 16:31:45 +02:00

Compare commits

...

80 Commits

Author SHA1 Message Date
Alex Plate
ea342a8e4f Preparation for 0.55.1 EAP release 2020-02-04 18:55:31 +03:00
Alex Plate
0b67dd1d05 Merge pull request #218 from citizenmatt/feature/registers
Macros record input keystrokes, not mapped keystrokes

This PR fixes VIM-1835 by recording input keystrokes for macros instead of the mapped keystrokes.

This PR is also required as a stepping stone for showcmd support (VIM-434), as both issues require refactoring KeyHandler#handleKey, and I thought it best to separate the issues.

A few other things were fixed as part of this PR:

VIM-1899 - support an argument to the :registers command
VIM-1900 - improve output of :registers, :marks, :jumps and :ascii
2020-02-04 18:46:15 +03:00
Alex Plate
1519faef81 Fix compatibility with the IdeaVim-EasyMotion 2020-02-04 11:13:38 +03:00
Matt Ellis
24f023c8b3 Update changes 2020-02-03 23:35:53 +00:00
Matt Ellis
3eb46114f8 Remove Shortcut class 2020-02-03 23:35:04 +00:00
Matt Ellis
6a5fd30531 Remove unnecessary empty shortcut registration 2020-02-03 23:31:18 +00:00
Matt Ellis
96e83150e5 Ensure :jumps formats non-printable characters correctly
Also ensures long output lines are truncated
2020-02-03 22:50:39 +00:00
Matt Ellis
b2b65c65b9 Ensure :ascii formats non-printable characters correctly 2020-02-03 22:50:38 +00:00
Matt Ellis
5b028b4fa3 Ensure :marks formats non-printable characters correctly
Also adds a bunch of tests, and fixes offset for ^ and ] registers
2020-02-03 22:50:38 +00:00
Matt Ellis
8f4e1b3409 [VIM-1900] Ensure :reg formats non-printable characters correctly 2020-02-03 22:50:38 +00:00
Matt Ellis
3403cdf84b [VIM-1835] Macros record actual keystrokes not mapped 2020-02-01 11:36:40 +00:00
Alex Plate
4f9a6f3a7b Make vimExCommand EP dynamic 2020-01-31 19:14:11 +03:00
Alex Plate
c8d6d233e5 Revert [Make vimExCommand EP dynamic] 2020-01-31 18:15:55 +03:00
Alex Plate
0cfb65a19a Make vimExCommand EP dynamic 2020-01-31 17:59:07 +03:00
Alex Plate
384d917021 Make vimAction EP dynamic 2020-01-31 12:05:46 +03:00
Alex Plate
f1c8c67789 Use enumMap to store key roots 2020-01-31 10:17:56 +03:00
Alex Plate
75e8f4ec6d Deny vimAction extension point contributions from other plugins 2020-01-30 21:23:23 +03:00
Matt Ellis
d1d0323112 [VIM-1899] Add argument to :registers command
Also introduce testable clipboard handling
2020-01-27 10:47:37 +00:00
Alex Plate
ab31dae582 Add todo for VimLocalConfig 2020-01-27 12:25:45 +03:00
Alex Plate
64f176cedb Control dynamic loading of plugin via the application component 2020-01-27 11:45:26 +03:00
Alex Plate
9e921d6621 Move plugin.xml includes into separate folder 2020-01-27 11:40:42 +03:00
Alex Plate
a4b98f2848 Update CHANGES.md 2020-01-27 11:36:30 +03:00
Alex Plate
0d190e4a63 Update copyright 2020-01-27 11:35:00 +03:00
Alex Plate
13cdb7cc35 Merge pull request #215 from citizenmatt/refactor/command-state
Refactor key handler state
2020-01-27 11:34:48 +03:00
Alex Plate
ca60c467f3 Capability for tests in 2020.1 2020-01-27 11:11:05 +03:00
Alex Plate
01abba7d2c Use 201-EAP version for build 2020-01-27 11:11:05 +03:00
Alex Plate
80074177fc Make ascii doc a bit clearer 2020-01-27 11:11:05 +03:00
Alex Plate
bf67f8984a Add info about easymotion plugin 2020-01-25 16:32:43 +03:00
Alex Plate
b2267c4b6c Add information about non-released actions 2020-01-24 13:41:47 +03:00
Alex Plate
c80d69a31c Add note about VIM-987 into changelog 2020-01-24 13:41:47 +03:00
Alex Plate
1b7c3f0da3 Merge pull request #214 from sumoooru2/master
Implement c_CTRL-N/P
2020-01-22 10:56:37 +03:00
Alex Plate
c1ff6e1498 Prepare to the 0.55 release 2020-01-20 20:15:36 +03:00
Alex Plate
50c04ce71c Change LookupKeys implementation 2020-01-20 15:29:40 +03:00
Alex Plate
bc6ff6bc8e Convert characterHelper to kt 2020-01-19 17:55:15 +03:00
Alex Plate
93bcf2a7e8 Rename .java to .kt 2020-01-19 17:55:14 +03:00
Alex Plate
c3b503adff Set up a mechanism to define the KeyStrokes that should work with active lookup 2020-01-19 17:34:12 +03:00
Alex Plate
ecdcbdda10 Put all range files into the ranges directory 2020-01-16 15:13:56 +03:00
Alex Plate
b97c9a5ed0 Rename .java to .kt 2020-01-16 15:13:55 +03:00
Alex Plate
84a6843a7b Convert ExOutputModel to kt 2020-01-16 12:26:39 +03:00
Alex Plate
17eed7467c Rename .java to .kt 2020-01-16 12:26:39 +03:00
Alex Plate
310ffc849c Convert ExCommand to kt 2020-01-16 12:23:43 +03:00
Alex Plate
3e6756160a Rename .java to .kt 2020-01-16 12:23:43 +03:00
Alex Plate
563e809a2d Put all exceptions to single kt file 2020-01-16 12:18:20 +03:00
Alex Plate
86ec3f3bcd Rename .java to .kt 2020-01-16 12:17:54 +03:00
Matt Ellis
7b225cb824 Remove CHAR_OR_DIGRAPH state 2020-01-07 20:14:56 +00:00
Matt Ellis
562e0b06df Refactor expected argument type 2020-01-07 19:54:20 +00:00
Matt Ellis
51ce064507 Simplify and document handling of EX_STRING 2020-01-07 19:09:58 +00:00
Matt Ellis
ebaeff9b4d Merge branch 'master' into refactor/command-state 2019-12-30 16:31:24 +00:00
Matt Ellis
8889e799ca Refactor setting command argument 2019-12-30 16:26:32 +00:00
Matt Ellis
668705e475 Refactor handling of duplicate operator chars 2019-12-30 16:08:04 +00:00
Matt Ellis
e428e909bf Simplify handling of count editing characters 2019-12-30 16:08:00 +00:00
Matt Ellis
d755c751c2 Move fix up of command/motion count 2019-12-30 15:36:52 +00:00
Matt Ellis
312c547412 Rearrange methods 2019-12-30 15:30:33 +00:00
Matt Ellis
48d30f2a3c Extract CommandBuilder 2019-12-30 15:28:15 +00:00
Matt Ellis
d8ed30df14 Encapsulate command node state 2019-12-27 18:09:50 +00:00
Matt Ellis
50176cb267 Move mapping mode to mapping state 2019-12-27 16:19:57 +00:00
Matt Ellis
5898d21857 Remove unnecessary annotations 2019-12-27 12:44:13 +00:00
Matt Ellis
e3839bc0b2 Remove unused command flags override 2019-12-27 12:42:00 +00:00
Matt Ellis
f97555d4a8 Rename executing command 2019-12-27 12:34:13 +00:00
Matt Ellis
79bdca9769 Move command stack to per-editor state 2019-12-27 12:26:10 +00:00
sumoooru2
138c2956ac Implement c_CTRL-N/P 2019-12-27 19:37:01 +09:00
Matt Ellis
ced457dd94 Move command state to per editor state 2019-12-27 10:33:22 +00:00
Matt Ellis
784fc6c6fa Rename mode state class and make immutable 2019-12-27 10:10:39 +00:00
Alex Plate
b4e0ec282f Convert vim surround plugin to kt 2019-12-26 16:45:42 +03:00
Alex Plate
cbf7dfabcb Rename .java to .kt 2019-12-26 16:45:42 +03:00
Alex Plate
b8eb55d965 Update changes 2019-12-24 11:00:17 +03:00
Matt Ellis
f817e6cb7f Extract mapping state 2019-12-23 16:49:27 +00:00
Matt Ellis
6a622565ca Move mapping availability check 2019-12-19 17:00:38 +00:00
Matt Ellis
23126aeb6d Extract abandoned mapping sequence handling 2019-12-19 11:49:53 +00:00
Matt Ellis
61fd67472b Extract completed mapping sequence handling 2019-12-19 11:39:34 +00:00
Matt Ellis
105c073e1f Extract unfinished mapping sequence handling 2019-12-19 01:11:24 +00:00
Matt Ellis
200f3484b6 Move current arg type state to per-editor 2019-12-10 20:20:13 +00:00
Matt Ellis
6a40eb48fe Remove forward search state 2019-12-10 20:14:32 +00:00
Matt Ellis
fb3e9ce9f3 Move captured keys to per-editor state 2019-12-10 20:11:08 +00:00
Matt Ellis
91865460a2 Move DigraphResult to top level class 2019-12-10 20:05:12 +00:00
Matt Ellis
644afe541e Move <BS> digraph state to DigraphSequence 2019-12-10 20:01:42 +00:00
Matt Ellis
232303f06a Refactor to maintain digraph state at all times
Also allows <C-K> and <C-V>/<C-Q> to be remapped
2019-12-10 19:59:11 +00:00
Matt Ellis
280845610b Move digraph sequence state to per-editor 2019-12-10 19:32:25 +00:00
Matt Ellis
6108c9d6d2 [VIM-1284] Allow mapping numbers
Includes special case for 0 while entering counts. See :help :map-modes.
Also fixes issues when both operator and motion have a count - value should be multiplied, not appended (e.g. 3d2w is the same as 6dw, no 32dw!). See :help operator
2019-12-10 19:31:38 +00:00
Matt Ellis
ce04e995ee Move command count state per editor 2019-12-10 19:31:23 +00:00
629 changed files with 4509 additions and 3381 deletions

View File

@@ -16,13 +16,24 @@ It is important to distinguish EAP from traditional pre-release software.
Please note that the quality of EAP versions may at times be way below even
usual beta standards.
[To Be Released]
To Be Released
--------------
_Available since 0.54.1 EAP:_
_Available since 0.55.1 EAP:_
**Fixes:**
* [VIM-1284](https://youtrack.jetbrains.com/issue/VIM-1284) Fix mapping of digits
* Fix handling of counts on both operator and motion, e.g. `3d2w` deletes 6 words, instead of 32
* Allow mapping of `<C-K>` and `<C-V>`/`<C-Q>`
* [VIM-1899](https://youtrack.jetbrains.com/issue/VIM-1899) Add argument to `:registers` command
* [VIM-1835](https://youtrack.jetbrains.com/issue/VIM-1835) Macros record input keystrokes instead of mapped keystrokes
* [VIM-1900](https://youtrack.jetbrains.com/issue/VIM-1900) Ensure non-printable output for `:registers`, `:marks` and `:jumps` is encoded correctly
0.55, 2020-01-20
--------------
**Features:**
* Surround and Commentary extensions can be repeated with a dot command ([VIM-1118](https://youtrack.jetbrains.com/issue/VIM-1118))
* Surround and Commentary extensions support repeating with a dot command ([VIM-1118](https://youtrack.jetbrains.com/issue/VIM-1118))
* Support XDG settings standard ([VIM-664](https://youtrack.jetbrains.com/issue/VIM-664))
* Add option to remove the status bar icon ([VIM-1847](https://youtrack.jetbrains.com/issue/VIM-1847))
@@ -43,14 +54,11 @@ _Available since 0.54.1 EAP:_
* [VIM-1853](https://youtrack.jetbrains.com/issue/VIM-1853) Fix marks for disposed projects
* [VIM-1858](https://youtrack.jetbrains.com/issue/VIM-1858) Fix imap for autocomplete
* [VIM-1362](https://youtrack.jetbrains.com/issue/VIM-1362) Search with confirm doesn't scroll down far enough
_To Be Released:_
**Fixes:**
* [VIM-1875](https://youtrack.jetbrains.com/issue/VIM-1875) Fix `isk` in `~/.ideaivmrc`
* [VIM-1874](https://youtrack.jetbrains.com/issue/VIM-1874) Fix `set clipboard=unnamed` execution from `~/.ideavimrc`
* [VIM-1878](https://youtrack.jetbrains.com/issue/VIM-1878) Fix `c` command after extract method action
* [VIM-1884](https://youtrack.jetbrains.com/issue/VIM-1884) Show quickDoc during popup with `CTRL-J`
* [VIM-987](https://youtrack.jetbrains.com/issue/VIM-987) Fix arrow keys for the NEO keyboard
0.54, 2019-11-20
--------------

View File

@@ -93,6 +93,7 @@ Supported:
Emulated Vim plugins:
* vim-easymotion
* vim-surround
* vim-multiple-cursors
* vim-commentary
@@ -128,7 +129,7 @@ have `-Duser.home=/my/alternate/home` then IdeaVim will source
`/my/alternate/home/.ideavimrc` instead of `~/.ideavimrc`.
Alternatively, you can set up initialization commands using [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) standard.
Put your settings to `$XDG_CONFIG_HOME$/ideavim/ideavimrc` file. [To Be Released]
Put your settings to `$XDG_CONFIG_HOME$/ideavim/ideavimrc` file.
Emulated Vim Plugins

View File

@@ -103,10 +103,20 @@ The following `:set` commands can appear in `~/.ideavimrc` or be set manually in
If true, join command will be performed via IDE
See wiki/`ideajoin` examples
`ideastatusbar` `ideastatusbar` Boolean (default true) [To Be Released]
`ideastatusbar` `ideastatusbar` Boolean (default true)
If false, IdeaVim icon won't be shown in the status bar.
Works only from `~/.ideavimrc` after the IDE restart.
`lookupkeys` `lookupkeys` List of strings
List of keys that should be processed by the IDE during the active lookup (autocompletion).
For example, <Tab> and <Enter> are used by the IDE to finish the lookup,
but <C-W> should be passed to IdeaVim.
Default value:
"<Tab>", "<Down>", "<Up>", "<Enter>", "<Left>", "<Right>",
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
"<C-J>", "<C-Q>"
----------
[1] - cursor keys, <End>, <Home>, <PageUp> and <PageDown>

View File

@@ -1,6 +1,6 @@
# suppress inspection "UnusedProperty" for whole file
ideaVersion=2019.3
ideaVersion=201-EAP-SNAPSHOT
downloadIdeaSources=true
instrumentPluginCode=true
version=SNAPSHOT

View File

@@ -197,6 +197,8 @@
<vimAction implementation="com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction" mappingModes="I" keys="«C-O»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction" mappingModes="X" keys="I"/>
<vimAction implementation="com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction" mappingModes="X" keys="A"/>
<vimAction implementation="com.maddyhome.idea.vim.action.change.insert.StartInsertDigraphAction" mappingModes="IC" keys="«C-K»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.change.insert.StartInsertLiteralAction" mappingModes="IC" keys="«C-V»,«C-Q»"/>
<!-- Delete -->
<vimAction implementation="com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction" mappingModes="N" keys="«DEL»"/>

View File

@@ -3,8 +3,10 @@
<id>IdeaVIM</id>
<change-notes><![CDATA[
<ul>
<li>Fix `imap jk <ESC>` for the active autocompletion lookup</li>
<li>Surround and Commentary extensions can be repeated with a dot command</li>
<li>Support dot command for Surround and Commentary extensions</li>
<li>Support XDG settings standard</li>
<li>Add option to remove the status bar icon</li>
<li>Various bug fixes</li>
</ul>
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
]]></change-notes>
@@ -29,6 +31,9 @@
<resource-bundle xmlns="">messages</resource-bundle>
<application-components>
<component>
<implementation-class>com.maddyhome.idea.vim.DynamicLoaderStopper</implementation-class>
</component>
<component>
<implementation-class>com.maddyhome.idea.vim.VimPlugin</implementation-class>
</component>
@@ -45,10 +50,10 @@
<extensionPoints>
<extensionPoint name="vimExtension" interface="com.maddyhome.idea.vim.extension.VimExtension"/>
<extensionPoint name="vimExCommand" beanClass="com.maddyhome.idea.vim.ex.ExBeanClass">
<extensionPoint name="vimExCommand" beanClass="com.maddyhome.idea.vim.ex.ExBeanClass" dynamic="true">
<with attribute="implementation" implements="com.maddyhome.idea.vim.ex.CommandHandler"/>
</extensionPoint>
<extensionPoint name="vimAction" beanClass="com.maddyhome.idea.vim.handler.ActionBeanClass">
<extensionPoint name="vimAction" beanClass="com.maddyhome.idea.vim.handler.ActionBeanClass" dynamic="true">
<with attribute="implementation" implements="com.maddyhome.idea.vim.handler.EditorActionHandlerBase"/>
</extensionPoint>
</extensionPoints>
@@ -59,11 +64,11 @@
<statusBarWidgetProvider implementation="com.maddyhome.idea.vim.StatusBarIconProvider"/>
</extensions>
<xi:include href="/META-INF/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/VimActions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/VimExCommands.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/VimExtensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/includes/VimActions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/includes/VimExCommands.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/includes/VimExtensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<actions>
<action id="VimPluginToggle" class="com.maddyhome.idea.vim.action.VimPluginToggleAction" text="Vim Emulator" description="Toggle the vim plugin On/off">

View File

@@ -1,6 +1,6 @@
#
# IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
# Copyright (C) 2003-2019 The IdeaVim authors
# Copyright (C) 2003-2020 The IdeaVim authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,13 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.ex;
package com.maddyhome.idea.vim
/**
* Exception class
* This class prevents dynamic loading of IdeaVim plugin
*/
public class InvalidCommandException extends ExException {
public InvalidCommandException(String message, String cmd) {
super(message);
}
}
class DynamicLoaderStopper

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,11 +34,8 @@ import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.maddyhome.idea.vim.action.DuplicableOperatorAction;
import com.maddyhome.idea.vim.action.change.VimRepeater;
import com.maddyhome.idea.vim.action.macro.ToggleRecordingAction;
import com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction;
import com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.group.ChangeGroup;
@@ -66,10 +63,9 @@ import java.util.stream.Collectors;
import static com.intellij.openapi.actionSystem.CommonDataKeys.*;
import static com.intellij.openapi.actionSystem.PlatformDataKeys.PROJECT_FILE_DIRECTORY;
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
/**
* This handlers every keystroke that the user can argType except those that are still valid hotkeys for various Idea
* This handles every keystroke that the user can argType except those that are still valid hotkeys for various Idea
* actions. This is a singleton.
*/
public class KeyHandler {
@@ -131,7 +127,7 @@ public class KeyHandler {
ActionManager.getInstance(), 0);
if (action instanceof ActionGroup && !((ActionGroup)action).canBePerformed(context)) {
// Some of the AcitonGroups should not be performed, but shown as a popup
// Some ActionGroups should not be performed, but shown as a popup
ListPopup popup = JBPopupFactory.getInstance()
.createActionGroupPopup(event.getPresentation().getText(), (ActionGroup)action, context, false, null, -1);
@@ -147,8 +143,8 @@ public class KeyHandler {
return true;
}
else {
// beforeActionPerformedUpdate should be called to update the action. It fixes some rider-specific problems
// because rider use async update method. See VIM-1819
// beforeActionPerformedUpdate should be called to update the action. It fixes some rider-specific problems.
// because rider use async update method. See VIM-1819.
action.beforeActionPerformedUpdate(event);
if (event.getPresentation().isEnabled()) {
action.actionPerformed(event);
@@ -158,6 +154,16 @@ public class KeyHandler {
return false;
}
public void startDigraphSequence(@NotNull Editor editor) {
final CommandState editorState = CommandState.getInstance(editor);
editorState.startDigraphSequence();
}
public void startLiteralSequence(@NotNull Editor editor) {
final CommandState editorState = CommandState.getInstance(editor);
editorState.startLiteralSequence();
}
/**
* This is the main key handler for the Vim plugin. Every keystroke not handled directly by Idea is sent here for
* processing.
@@ -200,124 +206,90 @@ public class KeyHandler {
// All the editor actions should be performed with top level editor!!!
// Be careful: all the EditorActionHandler implementation should correctly process InjectedEditors
editor = HelperKt.getTopLevelEditor(editor);
final CommandState editorState = CommandState.getInstance(editor);
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
// If this is a "regular" character keystroke, get the character
char chKey = key.getKeyChar() == KeyEvent.CHAR_UNDEFINED ? 0 : key.getKeyChar();
final boolean isRecording = editorState.isRecording();
boolean shouldRecord = true;
// We only record unmapped keystrokes. If we've recursed to handle mapping, don't record anything.
boolean shouldRecord = handleKeyRecursionCount == 0 && editorState.isRecording();
handleKeyRecursionCount++;
// Check for command count before key mappings - otherwise e.g. ':map 0 ^' breaks command counts that contain a zero
if (isCommandCount(editorState, chKey)) {
// Update the count
count = count * 10 + (chKey - '0');
}
else if (!waitCommandFinish(editor) && allowKeyMappings && handleKeyMapping(editor, key, context)) {
if (editorState.getMappingMode() != MappingMode.OP_PENDING ||
currentCmd.isEmpty() ||
currentCmd.peek().getArgument() == null ||
Objects.requireNonNull(currentCmd.peek().getArgument()).getType() != Argument.Type.OFFSETS) {
return;
}
}
// Pressing delete while entering a count "removes" the last digit entered
// Unlike the digits, this must be checked *after* checking for key mappings
else if (isDeleteCommandCount(key, editorState)) {
// "Remove" the last digit sent to us
count /= 10;
}
else if (isEditorReset(key, editorState)) {
handleEditorReset(editor, key, context);
try {
if (!allowKeyMappings || !handleKeyMapping(editor, key, context)) {
if (isCommandCountKey(chKey, editorState)) {
commandBuilder.addCountCharacter(chKey);
} else if (isDeleteCommandCountKey(key, editorState)) {
commandBuilder.deleteCountCharacter();
} else if (isEditorReset(key, editorState)) {
handleEditorReset(editor, key, context, editorState);
}
// If we got this far the user is entering a command or supplying an argument to an entered command.
// First let's check to see if we are at the point of expecting a single character argument to a command.
else if (currentArg == Argument.Type.CHARACTER) {
handleCharArgument(key, chKey);
else if (isExpectingCharArgument(commandBuilder)) {
handleCharArgument(key, chKey, editorState);
}
// If we are this far, then the user must be entering a command or a non-single-character argument
// to an entered command. Let's figure out which it is
else {
// For debugging purposes we track the keys entered for this command
keys.add(key);
// to an entered command. Let's figure out which it is.
else if (!handleDigraph(editor, key, context, editorState)) {
commandBuilder.addKey(key);
// Ask the key/action tree if this is an appropriate key at this point in the command and if so,
// return the node matching this keystroke
Node node = editorState.getCurrentNode().get(key);
if (handleDigraph(editor, key, context, node)) return;
node = mapOpCommand(key, node, editorState);
final Node node = mapOpCommand(key, commandBuilder.getChildNode(key), editorState);
if (node instanceof CommandNode) {
handleCommandNode(editor, context, key, (CommandNode)node, editorState);
}
else if (node instanceof CommandPartNode) {
editorState.setCurrentNode((CommandPartNode)node);
}
else {
if (lastWasBS && lastChar != 0 && OptionsManager.INSTANCE.getDigraph().isSet()) {
char dig = VimPlugin.getDigraph().getDigraph(lastChar, key.getKeyChar());
key = KeyStroke.getKeyStroke(dig);
}
handleCommandNode(editor, context, key, (CommandNode) node, editorState);
} else if (node instanceof CommandPartNode) {
commandBuilder.setCurrentCommandPartNode((CommandPartNode) node);
} else {
// If we are in insert/replace mode send this key in for processing
if (editorState.getMode() == CommandState.Mode.INSERT || editorState.getMode() == CommandState.Mode.REPLACE) {
if (!VimPlugin.getChange().processKey(editor, context, key)) {
shouldRecord = false;
}
}
else if (editorState.getMode() == CommandState.Mode.SELECT) {
if (!VimPlugin.getChange().processKeyInSelectMode(editor, context, key)) {
shouldRecord = false;
}
}
else if (editorState.getMappingMode() == MappingMode.CMD_LINE) {
if (!VimPlugin.getProcess().processExKey(editor, key)) {
shouldRecord = false;
}
shouldRecord &= VimPlugin.getChange().processKey(editor, context, key);
} else if (editorState.getMode() == CommandState.Mode.SELECT) {
shouldRecord &= VimPlugin.getChange().processKeyInSelectMode(editor, context, key);
} else if (editorState.getMappingState().getMappingMode() == MappingMode.CMD_LINE) {
shouldRecord &= VimPlugin.getProcess().processExKey(editor, key);
}
// If we get here then the user has entered an unrecognized series of keystrokes
else {
state = State.BAD_COMMAND;
commandBuilder.setCommandState(CurrentCommandState.BAD_COMMAND);
}
lastChar = lastWasBS && lastChar != 0 ? 0 : key.getKeyChar();
lastWasBS = false;
partialReset(editor);
}
}
}
}
finally {
handleKeyRecursionCount--;
}
// Do we have a fully entered command at this point? If so, lets execute it
if (state == State.READY) {
// Do we have a fully entered command at this point? If so, let's execute it.
if (commandBuilder.isReady()) {
executeCommand(editor, key, context, editorState);
}
else if (state == State.BAD_COMMAND) {
if (editorState.getMappingMode() == MappingMode.OP_PENDING) {
editorState.popState();
}
else if (commandBuilder.isBad()) {
editorState.resetOpPending();
VimPlugin.indicateError();
reset(editor);
}
else if (isRecording && shouldRecord) {
// Don't record the keystroke that stops the recording (unmapped this is `q`)
if (shouldRecord && editorState.isRecording()) {
VimPlugin.getRegister().recordKeyStroke(key);
}
}
private boolean waitCommandFinish(@NotNull Editor editor) {
return !(CommandState.getInstance(editor).getCurrentNode() instanceof RootNode);
}
/**
* See the description for {@link com.maddyhome.idea.vim.action.DuplicableOperatorAction}
*/
private Node mapOpCommand(KeyStroke key, Node node, @NotNull CommandState editorState) {
if (editorState.getMappingMode() == MappingMode.OP_PENDING && !currentCmd.empty()) {
EditorActionHandlerBase action = currentCmd.peek().getAction();
if (action instanceof DuplicableOperatorAction &&
((DuplicableOperatorAction)action).getDuplicateWith() == key.getKeyChar()) {
return editorState.getCurrentNode().get(KeyStroke.getKeyStroke('_'));
}
if (editorState.isDuplicateOperatorKeyStroke(key)) {
return editorState.getCommandBuilder().getChildNode(KeyStroke.getKeyStroke('_'));
}
return node;
}
@@ -334,8 +306,8 @@ public class KeyHandler {
return true;
}
private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, @NotNull final DataContext context) {
if (count == 0 && currentArg == null && currentCmd.size() == 0) {
private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, @NotNull final DataContext context, @NotNull CommandState editorState) {
if (editorState.getCommandBuilder().isAtDefaultState()) {
RegisterGroup register = VimPlugin.getRegister();
if (register.getCurrentRegister() == register.getDefaultRegister()) {
if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
@@ -352,57 +324,116 @@ public class KeyHandler {
private boolean handleKeyMapping(@NotNull final Editor editor,
@NotNull final KeyStroke key,
@NotNull final DataContext context) {
if (state == State.CHAR_OR_DIGRAPH) return false;
final CommandState commandState = CommandState.getInstance(editor);
commandState.stopMappingTimer();
final MappingState mappingState = commandState.getMappingState();
final CommandBuilder commandBuilder = commandState.getCommandBuilder();
final MappingMode mappingMode = commandState.getMappingMode();
if (commandBuilder.isAwaitingCharOrDigraphArgument()
|| commandBuilder.isBuildingMultiKeyCommand()
|| isMappingDisabledForKey(key, commandState)) {
return false;
}
final List<KeyStroke> mappingKeys = commandState.getMappingKeys();
final List<KeyStroke> fromKeys = new ArrayList<>(mappingKeys);
fromKeys.add(key);
mappingState.stopMappingTimer();
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mappingMode);
final MappingInfo currentMappingInfo = mapping.get(fromKeys);
final MappingInfo prevMappingInfo = mapping.get(mappingKeys);
final MappingInfo mappingInfo = currentMappingInfo != null ? currentMappingInfo : prevMappingInfo;
// Save the unhandled key strokes until we either complete or abandon the sequence.
mappingState.addKey(key);
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mappingState.getMappingMode());
// Returns true if any of these methods handle the key. False means that the key is unrelated to mapping and should
// be processed as normal.
return handleUnfinishedMappingSequence(editor, mappingState, mapping)
|| handleCompleteMappingSequence(editor, context, commandState, mappingState, mapping, key)
|| handleAbandonedMappingSequence(editor, mappingState, context);
}
private boolean isMappingDisabledForKey(@NotNull KeyStroke key, @NotNull CommandState commandState) {
// "0" can be mapped, but the mapping isn't applied when entering a count. Other digits are always mapped, even when
// entering a count.
// See `:help :map-modes`
return key.getKeyChar() == '0' && commandState.getCommandBuilder().getCount() > 0;
}
private boolean handleUnfinishedMappingSequence(@NotNull Editor editor,
@NotNull MappingState mappingState,
@NotNull KeyMapping mapping) {
// Is there at least one mapping that starts with the current sequence? This does not include complete matches,
// unless a sequence is also a prefix for another mapping. We eagerly evaluate the shortest mapping, so even if a
// mapping is a prefix, it will get evaluated when the next character is entered.
// Note that currentlyUnhandledKeySequence is the same as the state after commandState.getMappingKeys().add(key). It
// would be nice to tidy ths up
if (!mapping.isPrefix(mappingState.getKeys())) {
return false;
}
// If the timeout option is set, set a timer that will abandon the sequence and replay the unhandled keys unmapped.
// Every time a key is pressed and handled, the timer is stopped. E.g. if there is a mapping for "dweri", and the
// user has typed "dw" wait for the timeout, and then replay "d" and "w" without any mapping (which will of course
// delete a word)
final Application application = ApplicationManager.getApplication();
if (mapping.isPrefix(fromKeys)) {
// Okay, there is some mapping that starts with inserted key sequence. So,
// either the user will continue to enter the mapping, or (if timeout option is set)
// the entered command should be executed. Here we set up the times that will execute
// typed keys after some delay.
// E.g. there is a map for "dweri". If the user types "d", "w" they mean either "dweri" or "dw" command.
// If the user will continue typing "e", "r" and "i", the timer will be cancelled. If the user will
// not type anything, the "dw" command will be executed.
mappingKeys.add(key);
if (!application.isUnitTestMode() && OptionsManager.INSTANCE.getTimeout().isSet()) {
commandState.startMappingTimer(actionEvent -> application.invokeLater(() -> {
final KeyStroke firstKey = mappingKeys.get(0);
mappingKeys.clear();
if (editor.isDisposed() || firstKey.equals(parseKeys("<Plug>").get(0))) {
mappingState.startMappingTimer(actionEvent -> application.invokeLater(() -> {
final List<KeyStroke> unhandledKeys = mappingState.detachKeys();
// TODO: I'm not sure why we abandon plugin commands here
// Would be useful to have a comment or a helpfully named helper method here
if (editor.isDisposed() || unhandledKeys.get(0).equals(StringHelper.PlugKeyStroke)) {
return;
}
for (KeyStroke keyStroke : fromKeys) {
for (KeyStroke keyStroke : unhandledKeys) {
handleKey(editor, keyStroke, new EditorDataContext(editor), false);
}
}, ModalityState.stateForComponent(editor.getComponent())));
}
return true;
}
else if (mappingInfo != null) {
// Okay, there is a mapping for the entered key sequence
// now the another key sequence should be executed, or the handler that attached to this command
mappingKeys.clear();
private boolean handleCompleteMappingSequence(@NotNull Editor editor,
@NotNull DataContext context,
@NotNull CommandState commandState,
@NotNull MappingState mappingState,
@NotNull KeyMapping mapping,
KeyStroke key) {
// The current sequence isn't a prefix, check to see if it's a completed sequence.
final MappingInfo currentMappingInfo = mapping.get(mappingState.getKeys());
MappingInfo mappingInfo = currentMappingInfo;
if (mappingInfo == null) {
// It's an abandoned sequence, check to see if the previous sequence was a complete sequence.
// TODO: This is incorrect behaviour
// What about sequences that were completed N keys ago?
// This should really be handled as part of an abandoned key sequence. We should also consolidate the replay
// of cached keys - this happens in timeout, here and also in abandoned sequences.
// Extract most of this method into handleMappingInfo. If we have a complete sequence, call it and we're done.
// If it's not a complete sequence, handleAbandonedMappingSequence should do something like call
// mappingState.detachKeys and look for the longest complete sequence in the returned list, evaluate it, and then
// replay any keys not yet handled. NB: The actual implementation should be compared to Vim behaviour to see what
// should actually happen.
final ArrayList<KeyStroke> previouslyUnhandledKeySequence = new ArrayList<>();
mappingState.getKeys().forEach(previouslyUnhandledKeySequence::add);
if (previouslyUnhandledKeySequence.size() > 1) {
previouslyUnhandledKeySequence.remove(previouslyUnhandledKeySequence.size() - 1);
mappingInfo = mapping.get(previouslyUnhandledKeySequence);
}
}
if (mappingInfo == null) {
return false;
}
mappingState.resetMappingSequence();
final EditorDataContext currentContext = new EditorDataContext(editor);
final List<KeyStroke> toKeys = mappingInfo.getToKeys();
final VimExtensionHandler extensionHandler = mappingInfo.getExtensionHandler();
final EditorDataContext currentContext = new EditorDataContext(editor);
if (toKeys != null) {
// Here is a mapping to another key sequence
final boolean fromIsPrefix = isPrefix(mappingInfo.getFromKeys(), toKeys);
boolean first = true;
for (KeyStroke keyStroke : toKeys) {
@@ -412,15 +443,20 @@ public class KeyHandler {
}
}
else if (extensionHandler != null) {
// Here is a mapping to some vim handler
final CommandProcessor processor = CommandProcessor.getInstance();
final boolean isPendingMode = CommandState.getInstance(editor).getMappingMode() == MappingMode.OP_PENDING;
// Cache isOperatorPending in case the extension changes the mode while moving the caret
// See CommonExtensionTest
// TODO: Is this legal? Should we assert in this case?
final boolean shouldCalculateOffsets = commandState.isOperatorPending();
Map<Caret, Integer> startOffsets =
editor.getCaretModel().getAllCarets().stream().collect(Collectors.toMap(Function.identity(), Caret::getOffset));
if (extensionHandler.isRepeatable()) {
VimRepeater.Extension.INSTANCE.clean();
}
processor.executeCommand(editor.getProject(), () -> extensionHandler.execute(editor, context),
"Vim " + extensionHandler.getClass().getSimpleName(), null);
@@ -429,9 +465,8 @@ public class KeyHandler {
VimRepeater.Extension.INSTANCE.setArgumentCaptured(null);
VimRepeater.INSTANCE.setRepeatHandler(true);
}
if (isPendingMode &&
!currentCmd.isEmpty() &&
currentCmd.peek().getArgument() == null) {
if (shouldCalculateOffsets && !commandState.getCommandBuilder().hasCurrentCommandPartArgument()) {
Map<Caret, VimSelection> offsets = new HashMap<>();
for (Caret caret : editor.getCaretModel().getAllCarets()) {
@@ -441,7 +476,7 @@ public class KeyHandler {
.create(UserDataManager.getVimSelectionStart(caret), caret.getOffset(),
SelectionType.fromSubMode(CommandStateHelper.getSubMode(editor)), editor);
offsets.put(caret, vimSelection);
commandState.popState();
commandState.popModes();
}
else if (startOffset != null && startOffset != caret.getOffset()) {
// Command line motions are always characterwise exclusive
@@ -464,76 +499,85 @@ public class KeyHandler {
}
if (!offsets.isEmpty()) {
currentCmd.peek().setArgument(new Argument(offsets));
state = State.READY;
commandState.getCommandBuilder().completeCommandPart(new Argument(offsets));
}
}
}
// NB: mappingInfo MUST be non-null here, so if equal
// then prevMappingInfo is also non-null; this also
// means that the prev mapping was a prefix, but the
// next key typed (`key`) was not part of that
if (prevMappingInfo == mappingInfo) {
handleKey(editor, key, currentContext);
// If we've just evaluated the previous key sequence, make sure to also handle the current key
if (mappingInfo != currentMappingInfo) {
handleKey(editor, key, currentContext, true);
}
return true;
}
else {
// If the user enters a command that starts with known mapping, but it is not exactly this mapping,
// mapping handler prevents further processing of there keys.
// E.g. if there is a mapping for "hello" and user enters command "help"
// the processing of "h", "e" and "l" will be prevented by this handler.
// However, these keys should be processed as usual when user enters "p"
// and the following for loop does exactly that.
//
private boolean handleAbandonedMappingSequence(@NotNull Editor editor,
@NotNull MappingState mappingState,
DataContext context) {
// The user has terminated a mapping sequence with an unexpected key
// E.g. if there is a mapping for "hello" and user enters command "help" the processing of "h", "e" and "l" will be
// prevented by this handler. Make sure the currently unhandled keys are processed as normal.
final List<KeyStroke> unhandledKeyStrokes = mappingState.detachKeys();
// If there is only the current key to handle, do nothing
if (unhandledKeyStrokes.size() == 1) {
return false;
}
// Okay, look at the code below. Why is the first key handled separately?
// Let's assume the next mappings:
// - map ds j
// - map I 2l
// If user enters `dI`, the first `d` will be caught be this handler because it's a prefix for `ds` command.
// After the user enters `I`, the caught `d` should be processed without mapping and the rest of keys
// After the user enters `I`, the caught `d` should be processed without mapping, and the rest of keys
// should be processed with mappings (to make I work)
//
// Additionally, the <Plug>mappings are not executed if the are failed to map to somethings.
// Additionally, the <Plug>mappings are not executed if the fail to map to something.
// E.g.
// - map <Plug>iA someAction
// - map I <Plug>i
// For `IA` someAction should be executed.
// But if the user types `Ib`, `<Plug>i` won't be executed again. Only `b` will be passed to keyHandler.
if (mappingKeys.isEmpty()) return false;
// Well, this will always be false, but just for protection
if (fromKeys.isEmpty()) return false;
final List<KeyStroke> unhandledKeys = new ArrayList<>(fromKeys);
mappingKeys.clear();
if (unhandledKeys.get(0).equals(parseKeys("<Plug>").get(0))) {
handleKey(editor, unhandledKeys.get(unhandledKeys.size() - 1), context);
if (unhandledKeyStrokes.get(0).equals(StringHelper.PlugKeyStroke)) {
handleKey(editor, unhandledKeyStrokes.get(unhandledKeyStrokes.size() - 1), context, true);
} else {
handleKey(editor, unhandledKeys.get(0), context, false);
for (KeyStroke keyStroke : unhandledKeys.subList(1, unhandledKeys.size())) {
handleKey(editor, unhandledKeyStrokes.get(0), context, false);
for (KeyStroke keyStroke : unhandledKeyStrokes.subList(1, unhandledKeyStrokes.size())) {
handleKey(editor, keyStroke, context, true);
}
}
return true;
}
private boolean isCommandCountKey(char chKey, @NotNull CommandState editorState) {
// Make sure to avoid handling '0' as the start of a count.
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
return (editorState.getMode() == CommandState.Mode.COMMAND || editorState.getMode() == CommandState.Mode.VISUAL)
&& commandBuilder.isExpectingCount() && Character.isDigit(chKey) && (commandBuilder.getCount() > 0 || chKey != '0');
}
private boolean isDeleteCommandCount(@NotNull KeyStroke key, @NotNull CommandState editorState) {
return (editorState.getMode() == CommandState.Mode.COMMAND || editorState.getMode() == CommandState.Mode.VISUAL) &&
state == State.NEW_COMMAND &&
currentArg != Argument.Type.CHARACTER &&
currentArg != Argument.Type.DIGRAPH &&
key.getKeyCode() == KeyEvent.VK_DELETE &&
count != 0;
private boolean isDeleteCommandCountKey(@NotNull KeyStroke key, @NotNull CommandState editorState) {
// See `:help N<Del>`
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
return (editorState.getMode() == CommandState.Mode.COMMAND || editorState.getMode() == CommandState.Mode.VISUAL)
&& commandBuilder.isExpectingCount() && commandBuilder.getCount() > 0 && key.getKeyCode() == KeyEvent.VK_DELETE;
}
private boolean isEditorReset(@NotNull KeyStroke key, @NotNull CommandState editorState) {
return (editorState.getMode() == CommandState.Mode.COMMAND) && StringHelper.isCloseKeyStroke(key);
}
private void handleCharArgument(@NotNull KeyStroke key, char chKey) {
private boolean isExpectingCharArgument(@NotNull CommandBuilder commandBuilder) {
return commandBuilder.getExpectedArgumentType() == Argument.Type.CHARACTER;
}
private void handleCharArgument(@NotNull KeyStroke key, char chKey, @NotNull CommandState commandState) {
// We are expecting a character argument - is this a regular character the user typed?
// Some special keys can be handled as character arguments - let's check for them here.
if (chKey == 0) {
@@ -547,57 +591,64 @@ public class KeyHandler {
}
}
final CommandBuilder commandBuilder = commandState.getCommandBuilder();
if (chKey != 0) {
// Create the character argument, add it to the current command, and signal we are ready to process
// the command
Argument arg = new Argument(chKey);
Command cmd = currentCmd.peek();
cmd.setArgument(arg);
state = State.READY;
// Create the character argument, add it to the current command, and signal we are ready to process the command
commandBuilder.completeCommandPart(new Argument(chKey));
}
else {
// Oops - this isn't a valid character argument
state = State.BAD_COMMAND;
commandBuilder.setCommandState(CurrentCommandState.BAD_COMMAND);
}
}
private boolean isCommandCount(@NotNull CommandState editorState, char chKey) {
return (editorState.getMode() == CommandState.Mode.COMMAND || editorState.getMode() == CommandState.Mode.VISUAL) &&
state == State.NEW_COMMAND &&
currentArg != Argument.Type.CHARACTER &&
currentArg != Argument.Type.DIGRAPH &&
Character.isDigit(chKey) &&
(count != 0 || chKey != '0');
}
private boolean handleDigraph(@NotNull Editor editor,
@NotNull KeyStroke key,
@NotNull DataContext context,
@Nullable Node node) {
if (digraph == null && !(node instanceof CommandNode) && DigraphSequence.isDigraphStart(key)) {
digraph = new DigraphSequence();
@NotNull CommandState editorState) {
// 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.
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
if (commandBuilder.getExpectedArgumentType() == Argument.Type.DIGRAPH) {
if (DigraphSequence.isDigraphStart(key)) {
editorState.startDigraphSequence();
return true;
}
if (digraph != null) {
DigraphSequence.DigraphResult res = digraph.processKey(key, editor);
if (DigraphSequence.isLiteralStart(key)) {
editorState.startLiteralSequence();
return true;
}
}
DigraphResult res = editorState.processDigraphKey(key, editor);
switch (res.getResult()) {
case DigraphSequence.DigraphResult.RES_OK:
case DigraphResult.RES_HANDLED:
case DigraphResult.RES_BAD:
return true;
case DigraphSequence.DigraphResult.RES_BAD:
digraph = null;
return true;
case DigraphSequence.DigraphResult.RES_DONE:
if (currentArg == Argument.Type.DIGRAPH) {
currentArg = Argument.Type.CHARACTER;
case DigraphResult.RES_DONE:
if (commandBuilder.getExpectedArgumentType() == Argument.Type.DIGRAPH) {
commandBuilder.fallbackToCharacterArgument();
}
digraph = null;
final KeyStroke stroke = res.getStroke();
if (stroke == null) {
return false;
}
handleKey(editor, stroke, context);
return true;
case DigraphResult.RES_UNHANDLED:
if (commandBuilder.getExpectedArgumentType() == Argument.Type.DIGRAPH) {
commandBuilder.fallbackToCharacterArgument();
handleKey(editor, key, context);
return true;
}
return false;
}
return false;
}
@@ -605,58 +656,28 @@ public class KeyHandler {
@NotNull KeyStroke key,
@NotNull DataContext context,
@NotNull CommandState editorState) {
// Let's go through the command stack and merge it all into one command. At this time there should never
// be more than two commands on the stack - one is the actual command and the other would be a motion
// command argument needed by the first command
Command cmd = currentCmd.pop();
while (currentCmd.size() > 0) {
Command top = currentCmd.pop();
top.setArgument(new Argument(cmd));
cmd = top;
}
// If we have a command and a motion command argument, both could possibly have their own counts. We
// need to adjust the counts so the motion gets the product of both counts and the count associated with
// the command gets reset. Example 3c2w (change 2 words, three times) becomes c6w (change 6 words)
final Argument arg = cmd.getArgument();
if (arg != null && arg.getType() == Argument.Type.MOTION) {
final Command mot = arg.getMotion();
// If no count was entered for either command then nothing changes. If either had a count then
// the motion gets the product of both.
int cnt = cmd.getRawCount() == 0 && mot.getRawCount() == 0 ? 0 : cmd.getCount() * mot.getCount();
mot.setCount(cnt);
cmd.setCount(0);
}
final Command command = editorState.getCommandBuilder().buildCommand();
// If we were in "operator pending" mode, reset back to normal mode.
if (editorState.getMappingMode() == MappingMode.OP_PENDING) {
editorState.popState();
}
editorState.resetOpPending();
// Save off the command we are about to execute
editorState.setCommand(cmd);
if (lastChar != 0 && !lastWasBS) {
lastWasBS = key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0));
}
else {
lastChar = 0;
}
editorState.setExecutingCommand(command);
Project project = editor.getProject();
final Command.Type type = cmd.getType();
final Command.Type type = command.getType();
if (type.isWrite() && !editor.getDocument().isWritable()) {
VimPlugin.indicateError();
reset(editor);
}
if (!cmd.getFlags().contains(CommandFlags.FLAG_TYPEAHEAD_SELF_MANAGE)) {
if (!command.getFlags().contains(CommandFlags.FLAG_TYPEAHEAD_SELF_MANAGE)) {
IdeEventQueue.getInstance().flushDelayedKeyEvents();
}
if (ApplicationManager.getApplication().isDispatchThread()) {
Runnable action = new ActionRunner(editor, context, cmd, key);
EditorActionHandlerBase cmdAction = cmd.getAction();
Runnable action = new ActionRunner(editor, context, command, key);
EditorActionHandlerBase cmdAction = command.getAction();
String name = cmdAction.getId();
if (type.isWrite()) {
@@ -676,40 +697,50 @@ public class KeyHandler {
KeyStroke key,
@NotNull CommandNode node,
CommandState editorState) {
// The user entered a valid command. Create the command and add it to the stack
final EditorActionHandlerBase myAction = node.getActionHolder().getAction();
Command cmd = new Command(count, myAction, myAction.getType(), myAction.getFlags(), keys);
currentCmd.push(cmd);
// The user entered a valid command. Create the command and add it to the stack.
final EditorActionHandlerBase action = node.getActionHolder().getAction();
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
final Argument.Type expectedArgumentType = commandBuilder.getExpectedArgumentType();
if (currentArg != null && !checkArgumentCompatibility(node)) return;
commandBuilder.pushCommandPart(action);
if (myAction.getArgumentType() == null || stopMacroRecord(node, editorState)) {
state = State.READY;
if (!checkArgumentCompatibility(expectedArgumentType, action)) {
commandBuilder.setCommandState(CurrentCommandState.BAD_COMMAND);
return;
}
if (action.getArgumentType() == null || stopMacroRecord(node, editorState)) {
commandBuilder.setCommandState(CurrentCommandState.READY);
}
else {
currentArg = myAction.getArgumentType();
startWaitingForArgument(editor, context, key.getKeyChar(), currentArg, editorState, myAction);
final Argument.Type argumentType = action.getArgumentType();
startWaitingForArgument(editor, context, key.getKeyChar(), argumentType, editorState);
partialReset(editor);
}
// TODO In the name of God, get rid of EX_STRING, FLAG_COMPLETE_EX and all the related staff
if (currentArg == Argument.Type.EX_STRING && myAction.getFlags().contains(CommandFlags.FLAG_COMPLETE_EX)) {
EditorActionHandlerBase action;
if (forwardSearch) {
action = new SearchEntryFwdAction();
}
else {
action = new SearchEntryRevAction();
}
if (expectedArgumentType == Argument.Type.EX_STRING && action.getFlags().contains(CommandFlags.FLAG_COMPLETE_EX)) {
/* The only action that implements FLAG_COMPLETE_EX is ProcessExEntryAction.
* When pressing ':', ExEntryAction is chosen as the command. Since it expects no arguments, it is invoked and
calls ProcessGroup#startExCommand, pushes CMD_LINE mode, and the action is popped. The ex handler will push
the final <CR> through handleKey, which chooses ProcessExEntryAction. Because we're not expecting EX_STRING,
this branch does NOT fire, and ProcessExEntryAction handles the ex cmd line entry.
* When pressing '/' or '?', SearchEntry(Fwd|Rev)Action is chosen as the command. This expects an argument of
EX_STRING, so startWaitingForArgument calls ProcessGroup#startSearchCommand. The ex handler pushes the final
<CR> through handleKey, which chooses ProcessExEntryAction, and we hit this branch. We don't invoke
ProcessExEntryAction, but pop it, set the search text as an argument on SearchEntry(Fwd|Rev)Action and invoke
that instead.
* When using '/' or '?' as part of a motion (e.g. "d/foo"), the above happens again, and all is good. Because
the text has been applied as an argument on the last command, '.' will correctly repeat it.
It's hard to see how to improve this. Removing EX_STRING means starting ex input has to happen in ExEntryAction
and SearchEntry(Fwd|Rev)Action, and the ex command invoked in ProcessExEntryAction, but that breaks any initial
operator, which would be invoked first (e.g. 'd' in "d/foo").
*/
String text = VimPlugin.getProcess().endSearchCommand(editor);
currentCmd.pop();
Argument arg = new Argument(text);
cmd = new Command(count, action, action.getType(), action.getFlags(), keys);
cmd.setArgument(arg);
currentCmd.push(cmd);
CommandState.getInstance(editor).popState();
commandBuilder.popCommandPart(); // Pop ProcessExEntryAction
commandBuilder.completeCommandPart(new Argument(text)); // Set search text on SearchEntry(Fwd|Rev)Action
editorState.popModes(); // Pop CMD_LINE
}
}
@@ -721,38 +752,27 @@ public class KeyHandler {
DataContext context,
char key,
@NotNull Argument.Type argument,
CommandState editorState,
EditorActionHandlerBase action) {
CommandState editorState) {
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
switch (argument) {
case CHARACTER:
case DIGRAPH:
digraph = new DigraphSequence();
state = State.CHAR_OR_DIGRAPH;
break;
case MOTION:
if (CommandState.getInstance(editor).isDotRepeatInProgress() && VimRepeater.Extension.INSTANCE.getArgumentCaptured() != null) {
currentCmd.peek().setArgument(VimRepeater.Extension.INSTANCE.getArgumentCaptured());
state = State.READY;
if (editorState.isDotRepeatInProgress() && VimRepeater.Extension.INSTANCE.getArgumentCaptured() != null) {
commandBuilder.completeCommandPart(VimRepeater.Extension.INSTANCE.getArgumentCaptured());
}
editorState.pushState(editorState.getMode(), editorState.getSubMode(), MappingMode.OP_PENDING);
editorState.pushModes(editorState.getMode(), CommandState.SubMode.OP_PENDING);
break;
case EX_STRING:
forwardSearch = !(action instanceof SearchEntryRevAction);
VimPlugin.getProcess().startSearchCommand(editor, context, count, key);
state = State.NEW_COMMAND;
editorState.pushState(CommandState.Mode.CMD_LINE, CommandState.SubMode.NONE, MappingMode.CMD_LINE);
currentCmd.pop();
// The current Command expects an EX_STRING argument. E.g. SearchEntry(Fwd|Rev)Action. This won't execute until
// state hits READY. Start the ex input field, push CMD_LINE mode and wait for the argument.
VimPlugin.getProcess().startSearchCommand(editor, context, commandBuilder.getCount(), key);
commandBuilder.setCommandState(CurrentCommandState.NEW_COMMAND);
editorState.pushModes(CommandState.Mode.CMD_LINE, CommandState.SubMode.NONE);
break;
}
}
private boolean checkArgumentCompatibility(@NotNull CommandNode node) {
if (currentArg == Argument.Type.MOTION &&
node.getActionHolder().getAction().getType() != Command.Type.MOTION) {
state = State.BAD_COMMAND;
return false;
}
return true;
private boolean checkArgumentCompatibility(@Nullable Argument.Type expectedArgumentType, @NotNull EditorActionHandlerBase action) {
return !(expectedArgumentType == Argument.Type.MOTION && action.getType() != Command.Type.MOTION);
}
/**
@@ -774,25 +794,25 @@ public class KeyHandler {
* @param editor The editor to reset.
*/
public void partialReset(@Nullable Editor editor) {
count = 0;
keys = new ArrayList<>();
CommandState editorState = CommandState.getInstance(editor);
editorState.stopMappingTimer();
editorState.getMappingKeys().clear();
editorState.setCurrentNode(VimPlugin.getKey().getKeyRoot(editorState.getMappingMode()));
editorState.getMappingState().resetMappingSequence();
editorState.getCommandBuilder().resetInProgressCommandPart(getKeyRoot(editorState.getMappingState().getMappingMode()));
}
/**
* Resets the state of this handler. Does a partial reset then resets the mode, the command, and the argument
* Resets the state of this handler. Does a partial reset then resets the mode, the command, and the argument.
*
* @param editor The editor to reset.
*/
public void reset(@Nullable Editor editor) {
partialReset(editor);
state = State.NEW_COMMAND;
currentCmd.clear();
currentArg = null;
digraph = null;
CommandState editorState = CommandState.getInstance(editor);
editorState.getCommandBuilder().resetAll(getKeyRoot(editorState.getMappingState().getMappingMode()));
}
@NotNull
private CommandPartNode getKeyRoot(MappingMode mappingMode) {
return VimPlugin.getKey().getKeyRoot(mappingMode);
}
/**
@@ -805,8 +825,6 @@ public class KeyHandler {
VimPlugin.clearError();
CommandState.getInstance(editor).reset();
reset(editor);
lastChar = 0;
lastWasBS = false;
VimPlugin.getRegister().resetRegister();
if (editor != null) {
VisualGroupKt.updateCaretState(editor);
@@ -836,10 +854,12 @@ public class KeyHandler {
// This class is copied from com.intellij.openapi.editor.actionSystem.DialogAwareDataContext.DialogAwareDataContext
private final static class DialogAwareDataContext implements DataContext {
@SuppressWarnings("rawtypes")
private static final DataKey[] keys = {PROJECT, PROJECT_FILE_DIRECTORY, EDITOR, VIRTUAL_FILE, PSI_FILE};
private final Map<String, Object> values = new HashMap<>();
DialogAwareDataContext(DataContext context) {
//noinspection rawtypes
for (DataKey key : keys) {
values.put(key.getName(), key.getData(context));
}
@@ -874,17 +894,17 @@ public class KeyHandler {
@Override
public void run() {
CommandState editorState = CommandState.getInstance(editor);
boolean wasRecording = editorState.isRecording();
KeyHandler.getInstance().state = State.NEW_COMMAND;
editorState.getCommandBuilder().setCommandState(CurrentCommandState.NEW_COMMAND);
executeVimAction(editor, cmd.getAction(), context);
if (editorState.getMode() == CommandState.Mode.INSERT || editorState.getMode() == CommandState.Mode.REPLACE) {
VimPlugin.getChange().processCommand(editor, cmd);
}
// Now that the command has been executed let's clean up a few things.
// Now the command has been executed let's clean up a few things.
// By default the "empty" register is used by all commands so we want to reset whatever the last register
// By default, the "empty" register is used by all commands, so we want to reset whatever the last register
// selected by the user was to the empty register - unless we just executed the "select register" command.
if (cmd.getType() != Command.Type.SELECT_REGISTER) {
VimPlugin.getRegister().resetRegister();
@@ -896,14 +916,10 @@ public class KeyHandler {
// "select register"
if (editorState.getSubMode() == CommandState.SubMode.SINGLE_COMMAND &&
(!cmd.getFlags().contains(CommandFlags.FLAG_EXPECT_MORE))) {
editorState.popState();
editorState.popModes();
}
KeyHandler.getInstance().reset(editor);
if (wasRecording && editorState.isRecording()) {
VimPlugin.getRegister().recordKeyStroke(key);
}
}
private final Editor editor;
@@ -912,27 +928,8 @@ public class KeyHandler {
private final KeyStroke key;
}
private enum State {
/** Awaiting a new command */
NEW_COMMAND,
// TODO This should be probably processed in some better way
/** Awaiting for char or digraph input. In this mode mappings doesn't work (even for <C-K>) */
CHAR_OR_DIGRAPH,
READY,
BAD_COMMAND
}
private int count;
private List<KeyStroke> keys = new ArrayList<>();
private State state = State.NEW_COMMAND;
@NotNull private final Stack<Command> currentCmd = new Stack<>();
@Nullable private Argument.Type currentArg;
private TypedActionHandler origHandler;
@Nullable private DigraphSequence digraph = null;
private char lastChar;
private boolean lastWasBS;
private boolean forwardSearch = true;
private int handleKeyRecursionCount = 0;
private static KeyHandler instance;
}

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,11 +17,12 @@
*/
package com.maddyhome.idea.vim;
import com.intellij.openapi.extensions.ExtensionPointListener;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.maddyhome.idea.vim.group.KeyGroup;
import com.maddyhome.idea.vim.handler.ActionBeanClass;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.key.Shortcut;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,17 +33,41 @@ public class RegisterActions {
public static final ExtensionPointName<ActionBeanClass> VIM_ACTIONS_EP =
ExtensionPointName.create("IdeaVIM.vimAction");
private static boolean actionsRegistered = false;
private static boolean initialRegistration = false;
static {
// IdeaVim doesn't support contribution to VIM_ACTIONS_EP extension point, so technically we can skip this update,
// but let's support dynamic plugins in a more classic way and reload actions on every EP change.
// TODO: [VERSION UPDATE] since 191 use
// ExtensionPoint.addExtensionPointListener(ExtensionPointListener<T>, boolean, Disposable)
// TODO: [VERSION UPDATE] since 201 use
// ExtensionPoint.addExtensionPointListener(ExtensionPointChangeListener, boolean, Disposable)
VIM_ACTIONS_EP.getPoint(null).addExtensionPointListener(new ExtensionPointListener<ActionBeanClass>() {
@Override
public void extensionAdded(@NotNull ActionBeanClass extension, @NotNull PluginDescriptor pluginDescriptor) {
// Suppress listener before the `VimPlugin.turnOn()` function execution. This logic should be rewritten after
// version update (or earlier).
if (!initialRegistration) return;
unregisterActions();
registerActions();
}
@Override
public void extensionRemoved(@NotNull ActionBeanClass extension, @NotNull PluginDescriptor pluginDescriptor) {
if (!initialRegistration) return;
unregisterActions();
registerActions();
}
});
}
/**
* Register all the key/action mappings for the plugin.
*/
static void registerActions() {
if (actionsRegistered) return;
actionsRegistered = true;
registerVimCommandActions();
registerEmptyShortcuts();
initialRegistration = true;
}
@Nullable
@@ -58,6 +83,10 @@ public class RegisterActions {
return action;
}
public static void unregisterActions() {
VimPlugin.getKey().unregisterCommandActions();
}
private static void registerVimCommandActions() {
KeyGroup parser = VimPlugin.getKey();
VIM_ACTIONS_EP.extensions().forEach(parser::registerCommandAction);
@@ -66,12 +95,8 @@ public class RegisterActions {
private static void registerEmptyShortcuts() {
final KeyGroup parser = VimPlugin.getKey();
// Digraph shortcuts are handled directly by KeyHandler#handleKey, so they don't have an action. But we still need to
// register the shortcuts or the editor will swallow them. Technically, the shortcuts will be registered as part of
// other commands, but it's best to be explicit
parser.registerShortcutWithoutAction(new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_MASK)));
parser.registerShortcutWithoutAction(new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK)));
parser.registerShortcutWithoutAction(new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK)));
parser.registerShortcutWithoutAction(new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)));
// The {char1} <BS> {char2} shortcut is handled directly by KeyHandler#handleKey, so doesn't have an action. But we
// still need to register the shortcut, to make sure the editor doesn't swallow it.
parser.registerShortcutWithoutAction(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0));
}
}

View File

@@ -1,3 +1,21 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim
import com.intellij.ide.BrowserUtil

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@ import org.jdom.Element
Storage("\$APP_CONFIG$$/vim_local_settings.xml", roamingType = RoamingType.DISABLED, deprecated = true),
Storage("\$APP_CONFIG$/vim_local_settings.xml", roamingType = RoamingType.DISABLED)
])
// TODO: 27.01.2020 [VERSION UPDATE] 2019.3 https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_services.html#light-services
class VimLocalConfig : PersistentStateComponent<Element> {
override fun getState(): Element {
val element = Element("ideavim-local")

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -84,6 +84,7 @@ public class VimPlugin implements BaseComponent, PersistentStateComponent<Elemen
private static long lastBeepTimeMillis;
private boolean error = false;
private String message = null;
private int previousStateVersion = 0;
private String previousKeyMap = "";
@@ -330,6 +331,8 @@ public class VimPlugin implements BaseComponent, PersistentStateComponent<Elemen
}
public static void setEnabled(final boolean enabled) {
if (isEnabled() == enabled) return;
if (!enabled) {
getInstance().turnOffPlugin();
}
@@ -347,6 +350,10 @@ public class VimPlugin implements BaseComponent, PersistentStateComponent<Elemen
return getInstance().error;
}
public static String getMessage() {
return getInstance().message;
}
/**
* Indicate to the user that an error has occurred. Just beep.
*/
@@ -375,6 +382,9 @@ public class VimPlugin implements BaseComponent, PersistentStateComponent<Elemen
}
public static void showMessage(@Nullable String msg) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
getInstance().message = msg;
}
ProjectManager pm = ProjectManager.getInstance();
Project[] projects = pm.getOpenProjects();
for (Project project : projects) {
@@ -418,6 +428,12 @@ public class VimPlugin implements BaseComponent, PersistentStateComponent<Elemen
private void turnOffPlugin() {
KeyHandler.getInstance().fullReset(null);
// Unregister vim actions in command mode
RegisterActions.unregisterActions();
// Unregister ex handlers
CommandParser.getInstance().unregisterHandlers();
getEditor().turnOff();
getSearch().turnOff();
VimListenerManager.INSTANCE.turnOff();

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,3 +1,21 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim
import org.jdom.Element

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,3 +1,21 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.action
import javax.swing.KeyStroke

View File

@@ -1,3 +1,21 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.action
/**

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@ import com.intellij.openapi.util.Key
import com.intellij.ui.KeyStrokeAdapter
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase.Companion.parseKeysSet
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.StringHelper
@@ -42,7 +41,7 @@ import com.maddyhome.idea.vim.helper.inInsertMode
import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.key.ShortcutOwner
import com.maddyhome.idea.vim.listener.IdeaSpecifics.aceJumpActive
import com.maddyhome.idea.vim.option.OptionsManager.lookupKeys
import com.maddyhome.idea.vim.option.OptionsManager
import java.awt.event.InputEvent
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
@@ -90,7 +89,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
if (aceJumpActive()) return false
val keyCode = keyStroke.keyCode
if (LookupManager.getActiveLookup(editor) != null) {
return isEnabledForLookup(keyStroke)
return LookupKeys.isEnabledForLookup(keyStroke)
}
if (keyCode == KeyEvent.VK_ESCAPE) {
return isEnabledForEscape(editor)
@@ -136,29 +135,6 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
return fileEditorManager.allEditors.any { fileEditor -> editor == EditorUtil.getEditorEx(fileEditor) }
}
private fun isEnabledForLookup(keyStroke: KeyStroke): Boolean {
val notAllowedKeys = parseKeysSet(
"<Tab>", "<Down>", "<Up>", "<Enter>", "<Left>", "<Right>",
// New line in vim, but QuickDoc on MacOs
"<C-J>"
)
for (keys in notAllowedKeys) {
if (keyStroke == keys[0]) {
return false
}
}
// We allow users to set custom keys that will work with lookup in case devs forgot something
val popupActions = lookupKeys
val values = popupActions.values()
for (value in values) {
val keys = StringHelper.parseKeys(value)
if (keys.size >= 1 && keyStroke == keys[0]) {
return false
}
}
return true
}
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {
return VimPlugin.getKey().getKeymapConflicts(keyStroke).isNotEmpty()
}
@@ -189,6 +165,29 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
private fun getEditor(e: AnActionEvent): Editor? = e.getData(PlatformDataKeys.EDITOR)
/**
* Every time the key pressed with an active lookup, there is a decision:
* should this key be processed by IdeaVim, or by IDE. For example, dot and enter should be processed by IDE, but
* <C-W> by IdeaVim.
*
* The list of keys that should be processed by IDE is stored in [OptionsManager.lookupKeys]. So, we should search
* if the pressed key is presented in this list. The caches are used to speedup the process.
*/
private object LookupKeys {
private var parsedLookupKeys: Set<KeyStroke> = parseLookupKeys()
init {
OptionsManager.lookupKeys.addOptionChangeListener { _, _ ->
parsedLookupKeys = parseLookupKeys()
}
}
fun isEnabledForLookup(keyStroke: KeyStroke): Boolean = keyStroke !in parsedLookupKeys
private fun parseLookupKeys() = OptionsManager.lookupKeys.values()
.map { StringHelper.parseKeys(it) }.filter { it.isNotEmpty() }.map { it.first() }.toSet()
}
companion object {
@JvmField
val VIM_ONLY_EDITOR_KEYS: Set<KeyStroke> = ImmutableSet.builder<KeyStroke>().addAll(getKeyStrokes(KeyEvent.VK_ENTER, 0)).addAll(getKeyStrokes(KeyEvent.VK_ESCAPE, 0))

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ class RepeatChangeAction : VimActionHandler.SingleExecution() {
if (lastCommand == null && VimRepeater.Extension.lastExtensionHandler == null) return false
// Save state
val save = state.command
val save = state.executingCommand
val lastFTCmd = VimPlugin.getMotion().lastFTCmd
val lastFTChar = VimPlugin.getMotion().lastFTChar
val reg = VimPlugin.getRegister().currentRegister
@@ -62,7 +62,7 @@ class RepeatChangeAction : VimActionHandler.SingleExecution() {
mot.count = 0
}
}
state.setCommand(lastCommand)
state.setExecutingCommand(lastCommand)
KeyHandler.executeVimAction(editor, lastCommand.action, context)
@@ -74,7 +74,7 @@ class RepeatChangeAction : VimActionHandler.SingleExecution() {
state.isDotRepeatInProgress = false
// Restore state
if (save != null) state.setCommand(save)
if (save != null) state.setExecutingCommand(save)
VimPlugin.getMotion().setLastFTCmd(lastFTCmd, lastFTChar)
if (lastHandler != null) VimRepeater.Extension.lastExtensionHandler = lastHandler
VimRepeater.repeatHandler = repeatHandler

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.ex.LineRange
import com.maddyhome.idea.vim.ex.ranges.LineRange
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.ex.LineRange
import com.maddyhome.idea.vim.ex.ranges.LineRange
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
class ChangeLastSearchReplaceAction : ChangeEditorActionHandler.SingleExecution() {

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -0,0 +1,16 @@
package com.maddyhome.idea.vim.action.change.insert
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.handler.VimActionHandler
class StartInsertDigraphAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.INSERT
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
KeyHandler.getInstance().startDigraphSequence(editor)
return true
}
}

View File

@@ -0,0 +1,16 @@
package com.maddyhome.idea.vim.action.change.insert
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.handler.VimActionHandler
class StartInsertLiteralAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.INSERT
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
KeyHandler.getInstance().startLiteralSequence(editor)
return true
}
}

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2019 The IdeaVim authors
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

Some files were not shown because too many files have changed in this diff Show More