1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2024-11-24 22:42:53 +01:00

Compare commits

..

74 Commits

Author SHA1 Message Date
cc9385f2a9
Set plugin version to chylex-40 2024-08-25 10:17:38 +02:00
32a2384a46
Revert "VIM-2074 Backspace behaviour is incorrect in Replace mode"
This reverts commit 9bbeab80
2024-08-25 10:17:38 +02:00
fdd850de5a
Fix(VIM-3615): Escape closes dialog while waiting for more keys 2024-08-25 10:10:21 +02:00
0f7116b136
Add action to run last macro in all opened files 2024-08-25 06:11:12 +02:00
db8f0251fb
Stop macro execution after a failed search 2024-08-25 06:11:12 +02:00
2ca2c1e774
Revert per-caret registers 2024-08-25 06:11:10 +02:00
f3c32da4d1
Revert "Factor disposable objects on editor opening"
This reverts commit 1fa78935
2024-08-25 06:10:58 +02:00
1a3b34d457
Fix(VIM-3364): Exception with mapped Generate action 2024-08-25 06:10:58 +02:00
1f9159996d
Apply scrolloff after executing native IDEA actions 2024-08-25 06:10:58 +02:00
65c3acd891
Stay on same line after reindenting 2024-08-25 06:10:58 +02:00
223f65c003
Update search register when using f/t 2024-08-25 06:10:58 +02:00
293b854620
Automatically add unambiguous imports after running a macro 2024-08-25 06:10:58 +02:00
9e7c5fd603
Fix(VIM-3179): Respect virtual space below editor (imperfectly) 2024-08-25 06:10:58 +02:00
00c799595f
Fix(VIM-3178): Workaround to support "Jump to Source" action mapping 2024-08-25 06:10:58 +02:00
8577b5ed20
Add support for count for visual and line motion surround 2024-08-25 06:10:58 +02:00
3af7a991a0
Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2024-08-25 06:10:57 +02:00
212af1798d
Fix(VIM-696) Restore visual mode after undo/redo, and disable incompatible actions 2024-08-25 06:10:57 +02:00
002ef8f72f
Respect count with <Action> mappings 2024-08-25 06:10:57 +02:00
9115af6b3d
Change matchit plugin to use HTML patterns in unrecognized files 2024-08-25 06:10:57 +02:00
25ca42d371
Reset insert mode when switching active editor 2024-08-25 06:10:57 +02:00
408687c9b3
Disable switching to insert mode for some editors 2024-08-25 06:10:54 +02:00
85e00bf8fc
Remove update checker 2024-08-25 06:10:31 +02:00
bd6f2d4b2f
Set custom plugin version 2024-08-25 06:10:31 +02:00
IdeaVim Bot
e406885ec6 Add Igor Babko to contributors list 2024-08-24 09:01:39 +00:00
filipp
9bbeab8062 VIM-2074 Backspace behaviour is incorrect in Replace mode 2024-08-23 14:22:48 +03:00
filipp
373bfc4eab Add endOffset to LiveRange 2024-08-23 14:22:48 +03:00
filipp
050f2f7b97 Respect emojis and don't assume that every character is a single offset 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
e30bc14843 Make closing command line safer 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
76d590be11 Support more flexible command line restrictions for Fleet 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
b005328b4a Exclude generated files from .gitignore
I've also added sorting to be more confident that the generated file will be persistent across different machines
2024-08-23 14:18:03 +03:00
Filipp Vakhitov
ad20021cee Remove currentAction and some unused code 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
126de5c218 Remove package-info.java 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
0f7aef3f15 Fix tests 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
f352b84922 Move some Executor logic to its base class 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
789faa7cb2 Add entry to history on <Esc> in COMMAND mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
a338f5768a Better reset 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
8205c74571 Remove some old bindings 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
def40eb409 Save last entry on every command line text update 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
010e8a7541 Support <C-U> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
46c6778b3a Support <Down>, <S-Down>, <C-N>, <PageDown> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
0977bd4400 Support <Up>, <S-Up>, <C-P>, <PageUp> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
db092e9b0a Support history in VimCommandLine 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
5cfb98e188 Remove some old bindings 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
3a95b62885 Support <Insert> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
93e6adf5a9 Support <C-W> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
37204398ff Support <C-Right>, <S-Right> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
b2f450d14d Support <C-Left>, <S-Left> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
61da888571 Fix failing tests 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
fcda97cfb8 Update methods to support searching in any text, not just Editor content 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
1dc7ea6363 Register all shortcuts without references on ExKeyBindings
All the shortcuts will be removed from ExKeyBindings, but they still need to be registered
2024-08-23 14:18:03 +03:00
Filipp Vakhitov
bb507db884 Remove swing bindings that are already implemented 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
7b0482ed94 Fix unwanted beep when can't perform an action 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
1c79b0d59a Support <Right> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
ff4eb31418 Support <Left> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
cb1078cf70 Support <C-H> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
da3e40eaf6 Support <C-E>, <End> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
17f77a9639 Support <C-B>, <Home> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
3d03494354 Support <DEL> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
642caddda7 Support <BS> in command mode 2024-08-23 14:18:03 +03:00
Filipp Vakhitov
1d97c43e30 Make ExEntryAction public
Fleet registers commands manually, so commands must be accessible
2024-08-23 14:18:03 +03:00
Igor Babko
7ed3e3b53c Update support-guide.md 2024-08-23 12:14:41 +03:00
IdeaVim Bot
aa39ca2006 Add shaun to contributors list 2024-08-19 09:01:43 +00:00
shaun
bb122903de remove Latest Fixes link 2024-08-19 10:23:23 +03:00
shaun
c84a3cf64d [changelog] add YouTrack link for version fixes 2024-08-19 10:23:23 +03:00
IdeaVim Bot
f4c9464b8a Add The1xDeveloper to contributors list 2024-08-17 09:01:38 +00:00
The1xDeveloper
3ba14d05b4 VIM-566: Add za motion support for toggling folds 2024-08-16 12:28:18 +03:00
Filipp Vakhitov
2189b70b87 Fix(VIM-3601): The escape characters in IdeaVim's configuration file are invalid 2024-08-14 18:18:55 +03:00
dependabot[bot]
ea2222f9d5 Bump org.junit.jupiter:junit-jupiter from 5.10.3 to 5.11.0
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.3 to 5.11.0.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.3...r5.11.0)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-14 18:53:54 +03:00
Filipp Vakhitov
7d68d41888 Fix(VIM-3580): New terminal switches editor to insert mode 2024-08-12 13:44:24 +03:00
Alex Pláte
44749b6d8c
Update IdeaVim Plugins.md 2024-08-12 12:16:19 +03:00
Alex Pláte
1ce4dbc569
Update Home.md 2024-08-12 12:14:44 +03:00
Alex Pláte
db59513505
Update Home.md 2024-08-12 12:13:36 +03:00
Filipp Vakhitov
8c9ff9465f Fix(VIM-3584): com.maddyhome.idea.vim.KeyHandler requests com.maddyhome.idea.vim.api.VimKeyGroup instance. Class initialization must not depend on services 2024-08-11 01:12:59 +03:00
Filipp Vakhitov
1a2322ddec OutputPanel no longer ignores key events 2024-08-10 23:55:57 +03:00
82 changed files with 3399 additions and 1398 deletions

3
.gitignore vendored
View File

@ -27,9 +27,6 @@
# Generated by gradle task "generateGrammarSource" # Generated by gradle task "generateGrammarSource"
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
# Generated JSONs for lazy classloading
/vim-engine/src/main/resources/ksp-generated
/src/main/resources/ksp-generated
# Created by github automation # Created by github automation
settings.xml settings.xml

View File

@ -523,6 +523,18 @@ Contributors:
[![icon][github]](https://github.com/LazyScaper) [![icon][github]](https://github.com/LazyScaper)
&nbsp; &nbsp;
Jake Jake
* [![icon][mail]](mailto:the1xdeveloper@gmail.com)
[![icon][github]](https://github.com/The1xDeveloper)
&nbsp;
The1xDeveloper
* [![icon][mail]](mailto:shaunewilliams@gmail.com)
[![icon][github]](https://github.com/shaunlebron)
&nbsp;
shaun
* [![icon][mail]](mailto:i.i.babko@gmail.com)
[![icon][github]](https://github.com/igorbabko)
&nbsp;
Igor Babko
Previous contributors: Previous contributors:

View File

@ -27,8 +27,8 @@ usual beta standards.
Since version 2.9.0, the changelog can be found on YouTrack Since version 2.9.0, the changelog can be found on YouTrack
To Be Released: https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20 * [To Be Released](https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20)
Latest Fixes: https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20updated%20 * [Version Fixes](https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20%7BFix%20versions%7D%20asc)
## 2.9.0, 2024-02-20 ## 2.9.0, 2024-02-20

View File

@ -62,12 +62,16 @@ for a few days or send it to a friend for testing.
If you are looking for: If you are looking for:
- Vim commands (`w`, `<C-O>`, `p`, etc.): - Vim commands (`w`, `<C-O>`, `p`, etc.):
- Any particular command: `package-info.java`. - Any particular command:
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_commands.json)
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_commands.json)
- How commands are executed in common: `EditorActionHandlerBase`. - How commands are executed in common: `EditorActionHandlerBase`.
- Key mapping: `KeyHandler.handleKey()`. - Key mapping: `KeyHandler.handleKey()`.
- Ex commands (`:set`, `:s`, `:nohlsearch`): - Ex commands (`:set`, `:s`, `:nohlsearch`):
- Any particular ex command: package `com.maddyhome.idea.vim.ex.handler`. - Any particular command:
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_ex_commands.json)
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_ex_commands.json)
- Vim script grammar: `Vimscript.g4`. - Vim script grammar: `Vimscript.g4`.
- Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`. - Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
- Vim script executor: `Executor`. - Vim script executor: `Executor`.

View File

@ -109,7 +109,6 @@ etc
See also: See also:
* [The list of all supported commands](src/main/java/com/maddyhome/idea/vim/package-info.java)
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes) * [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md) * [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD) * [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)

View File

@ -37,7 +37,8 @@ class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironme
Files.createDirectories(generatedDirPath) Files.createDirectories(generatedDirPath)
val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!) val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
val fileContent = json.encodeToString(commands) val sortedCommands = commands.sortedWith(compareBy({ it.keys }, { it.`class` }))
val fileContent = json.encodeToString(sortedCommands)
filePath.writeText(fileContent) filePath.writeText(fileContent)
return emptyList() return emptyList()

View File

@ -37,7 +37,8 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
Files.createDirectories(generatedDirPath) Files.createDirectories(generatedDirPath)
val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!) val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
val fileContent = json.encodeToString(commandToClass) val sortedCommandToClass = commandToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
val fileContent = json.encodeToString(sortedCommandToClass)
filePath.writeText(fileContent) filePath.writeText(fileContent)
return emptyList() return emptyList()

View File

@ -37,7 +37,8 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
Files.createDirectories(generatedDirPath) Files.createDirectories(generatedDirPath)
val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!) val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
val fileContent = json.encodeToString(nameToClass) val sortedNameToClass = nameToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
val fileContent = json.encodeToString(sortedNameToClass)
filePath.writeText(fileContent) filePath.writeText(fileContent)
return emptyList() return emptyList()

View File

@ -1,6 +1,6 @@
Welcome to the IdeaVim wiki! Welcome to the IdeaVim wiki!
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins.md) - List of IdeaVim plugins: [plugins](IdeaVim%20Plugins)
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples.md) - Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples)
- List of "set" commands: ["set" commands](set-commands.md) - List of "set" commands: ["set" commands](set-commands)
- Docs about "select" mode in vim: [select mode](Select-mode.md) - Docs about "select" mode in vim: [select mode](Select-mode)

View File

@ -82,7 +82,7 @@ Original plugin: [NERDTree](https://github.com/preservim/nerdtree).
### Instructions ### Instructions
[See here](NERDTree-support.md). [See here](NERDTree-support).
</details> </details>

View File

@ -1,7 +1,7 @@
# Support Guide # Support Guide
This document is created to help our support team. This document is created to help our support team.
It's not intended to be read by the users as it brings to value to them. It's not intended to be read by the users as it brings no value to them.
## Support channels ## Support channels

View File

@ -20,7 +20,7 @@ ideaVersion=2024.2
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type # Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
ideaType=IC ideaType=IC
instrumentPluginCode=true instrumentPluginCode=true
version=chylex-39 version=chylex-40
javaVersion=17 javaVersion=17
remoteRobotVersion=0.11.23 remoteRobotVersion=0.11.23
antlrVersion=4.10.1 antlrVersion=4.10.1

View File

@ -19,7 +19,6 @@ exclude:
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
- src/main/java/com/maddyhome/idea/vim/package-info.java
- vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated - vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
- vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated - vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
- src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java - src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java

View File

@ -11,11 +11,14 @@ package com.maddyhome.idea.vim.group;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.maddyhome.idea.vim.api.VimDigraphGroupBase; import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
import com.maddyhome.idea.vim.api.VimEditor; import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimOutputPanel;
import com.maddyhome.idea.vim.ex.ExOutputModel; import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.helper.EditorHelper; import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.newapi.IjVimEditor; import com.maddyhome.idea.vim.newapi.IjVimEditor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
public class DigraphGroup extends VimDigraphGroupBase { public class DigraphGroup extends VimDigraphGroupBase {
public void showDigraphs(@NotNull VimEditor editor) { public void showDigraphs(@NotNull VimEditor editor) {
@ -71,7 +74,9 @@ public class DigraphGroup extends VimDigraphGroupBase {
} }
} }
ExOutputModel.getInstance(((IjVimEditor) editor).getEditor()).output(res.toString()); VimOutputPanel output = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
output.addText(res.toString(), true );
output.show();
} }
private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName()); private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());

View File

@ -374,9 +374,9 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
if (activeCommandLine != null) { if (activeCommandLine != null) {
activeCommandLine.close(true, false); activeCommandLine.close(true, false);
} }
ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor); VimOutputPanel outputPanel = injector.getOutputPanel().getCurrentOutputPanel();
if (exOutputModel != null) { if (outputPanel != null) {
exOutputModel.close(); outputPanel.close();
} }
VimModalInput modalInput = injector.getModalInput().getCurrentModalInput(); VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
if (modalInput != null) { if (modalInput != null) {

View File

@ -14,9 +14,7 @@ import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.history.HistoryBlock; import com.maddyhome.idea.vim.history.*;
import com.maddyhome.idea.vim.history.HistoryEntry;
import com.maddyhome.idea.vim.history.VimHistoryBase;
import org.jdom.Element; import org.jdom.Element;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -35,21 +33,20 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
logger.debug("saveData"); logger.debug("saveData");
Element hist = new Element("history"); Element hist = new Element("history");
saveData(hist, SEARCH); for (Type type : getHistories().keySet()) {
saveData(hist, COMMAND); saveData(hist, type);
saveData(hist, EXPRESSION); }
saveData(hist, INPUT);
element.addContent(hist); element.addContent(hist);
} }
private void saveData(@NotNull Element element, String key) { private void saveData(@NotNull Element element, VimHistory.Type type) {
final HistoryBlock block = getHistories().get(key); final HistoryBlock block = getHistories().get(type);
if (block == null) { if (block == null) {
return; return;
} }
final Element root = new Element("history-" + key); final Element root = new Element("history-" + typeToKey(type));
for (HistoryEntry entry : block.getEntries()) { for (HistoryEntry entry : block.getEntries()) {
final Element entryElement = new Element("entry"); final Element entryElement = new Element("entry");
@ -67,10 +64,10 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
return; return;
} }
readData(hist, SEARCH); for (Element child : hist.getChildren()) {
readData(hist, COMMAND); String key = child.getName().replace("history-", "");
readData(hist, EXPRESSION); readData(hist, key);
readData(hist, INPUT); }
} }
private void readData(@NotNull Element element, String key) { private void readData(@NotNull Element element, String key) {
@ -80,7 +77,7 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
} }
block = new HistoryBlock(); block = new HistoryBlock();
getHistories().put(key, block); getHistories().put(getTypeForString(key), block);
final Element root = element.getChild("history-" + key); final Element root = element.getChild("history-" + key);
if (root != null) { if (root != null) {
@ -94,6 +91,25 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
} }
} }
private String typeToKey(VimHistory.Type type) {
if (type instanceof VimHistory.Type.Search) {
return SEARCH;
}
if (type instanceof VimHistory.Type.Command) {
return COMMAND;
}
if (type instanceof VimHistory.Type.Expression) {
return EXPRESSION;
}
if (type instanceof VimHistory.Type.Input) {
return INPUT;
}
if (type instanceof VimHistory.Type.Custom) {
return ((Type.Custom) type).getId();
}
return "unreachable";
}
@Nullable @Nullable
@Override @Override
public Element getState() { public Element getState() {

View File

@ -26,10 +26,7 @@ import com.maddyhome.idea.vim.EventFacade;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction; import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.action.change.LazyVimCommand; import com.maddyhome.idea.vim.action.change.LazyVimCommand;
import com.maddyhome.idea.vim.api.NativeAction; import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
import com.maddyhome.idea.vim.command.MappingMode; import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.ex.ExOutputModel; import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.key.*; import com.maddyhome.idea.vim.key.*;
@ -80,25 +77,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
((IjVimEditor)editor).getEditor().getComponent()); ((IjVimEditor)editor).getEditor().getComponent());
} }
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull Editor editor) {
List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
final StringBuilder builder = new StringBuilder();
for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
MappingInfo mappingInfo = row.getSecond();
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
builder.append(" ");
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
builder.append(" ");
builder.append(mappingInfo.isRecursive() ? " " : "*");
builder.append(" ");
builder.append(mappingInfo.getPresentableString());
builder.append("\n");
}
ExOutputModel.getInstance(editor).output(builder.toString());
return true;
}
@Override @Override
public void updateShortcutKeysRegistration() { public void updateShortcutKeysRegistration() {
for (VimEditor editor : injector.getEditorGroup().getEditors()) { for (VimEditor editor : injector.getEditorGroup().getEditors()) {
@ -358,6 +336,22 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
@Override @Override
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) { public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
return showKeyMappings(modes, ((IjVimEditor) editor).getEditor()); List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
final StringBuilder builder = new StringBuilder();
for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
MappingInfo mappingInfo = row.getSecond();
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
builder.append(" ");
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
builder.append(" ");
builder.append(mappingInfo.isRecursive() ? " " : "*");
builder.append(" ");
builder.append(mappingInfo.getPresentableString());
builder.append("\n");
}
VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
outputPanel.addText(builder.toString(), true);
outputPanel.show();
return true;
} }
} }

View File

@ -317,7 +317,7 @@ internal class MotionGroup : VimMotionGroupBase() {
is Mode.CMD_LINE -> { is Mode.CMD_LINE -> {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return val commandLine = injector.commandLine.getActiveCommandLine() ?: return
commandLine.close(refocusOwningEditor = false, resetCaret = false) commandLine.close(refocusOwningEditor = false, resetCaret = false)
ExOutputModel.tryGetInstance(editor)?.close() injector.outputPanel.getCurrentOutputPanel()?.close()
} }
else -> {} else -> {}
} }

View File

@ -218,13 +218,17 @@ internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandle
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) { internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
override val key: String = "<Esc>" override val key: String = "<Esc>"
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean { private val ideaVimSupportDialog
val ideaVimSupportDialog = get() = injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
return editor.isPrimaryEditor() || return editor.isPrimaryEditor() ||
EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode || EditorHelper.isFileEditor(editor) && vimStateNeedsToHandleEscape(editor) ||
ideaVimSupportDialog && !editor.vim.mode.inNormalMode ideaVimSupportDialog && vimStateNeedsToHandleEscape(editor)
}
private fun vimStateNeedsToHandleEscape(editor: Editor): Boolean {
return !editor.vim.mode.inNormalMode || KeyHandler.getInstance().keyHandlerState.mappingState.hasKeys
} }
} }

View File

@ -61,6 +61,8 @@ internal class IjActionExecutor : VimActionExecutor {
get() = IdeActions.ACTION_EXPAND_REGION get() = IdeActions.ACTION_EXPAND_REGION
override val ACTION_EXPAND_REGION_RECURSIVELY: String override val ACTION_EXPAND_REGION_RECURSIVELY: String
get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
override val ACTION_EXPAND_COLLAPSE_TOGGLE: String
get() = "ExpandCollapseToggleAction"
/** /**
* Execute an action * Execute an action

View File

@ -25,7 +25,6 @@ import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.visual.VisualChange import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.VimStateMachine
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.ui.ExOutputPanel import com.maddyhome.idea.vim.ui.ExOutputPanel

View File

@ -748,7 +748,7 @@ internal object VimListenerManager {
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false) injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false) injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
ExOutputModel.tryGetInstance(editor)?.close() injector.outputPanel.getCurrentOutputPanel()?.close()
val caretModel = editor.caretModel val caretModel = editor.caretModel
if (editor.vim.mode.selectionType != null) { if (editor.vim.mode.selectionType != null) {
@ -777,7 +777,7 @@ internal object VimListenerManager {
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false) injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false) injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
ExOutputModel.getInstance(event.editor).close() injector.outputPanel.getCurrentOutputPanel()?.close()
} }
} }
} }

View File

@ -14,6 +14,9 @@ import com.maddyhome.idea.vim.common.LiveRange
internal class IjLiveRange(val marker: RangeMarker) : LiveRange { internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
override val startOffset: Int override val startOffset: Int
get() = marker.startOffset get() = marker.startOffset
override val endOffset: Int
get() = marker.endOffset
} }
val RangeMarker.vim: LiveRange val RangeMarker.vim: LiveRange

View File

@ -1,718 +0,0 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
/**
* IdeaVim command index.
*
*
* 1. Insert mode
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |i_CTRL-@| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertExitAction}
* |i_CTRL-A| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertAction}
* |i_CTRL-C| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
* |i_CTRL-D| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftLinesAction}
* |i_CTRL-E| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterBelowCursorAction}
* |i_CTRL-G_j| TO BE IMPLEMENTED
* |i_CTRL-G_k| TO BE IMPLEMENTED
* |i_CTRL-G_u| TO BE IMPLEMENTED
* |i_<BS>| {@link com.maddyhome.idea.vim.action.editor.VimEditorBackSpace}
* |i_digraph| IdeaVim enter digraph
* |i_CTRL-H| IntelliJ editor backspace
* |i_<Tab>| {@link com.maddyhome.idea.vim.action.editor.VimEditorTab}
* |i_CTRL-I| IntelliJ editor tab
* |i_<NL>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
* |i_CTRL-J| TO BE IMPLEMENTED
* |i_CTRL-K| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction}
* |i_CTRL-L| TO BE IMPLEMENTED
* |i_<CR>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
* |i_CTRL-M| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
* |i_CTRL-N| {@link com.maddyhome.idea.vim.action.window.LookupDownAction}
* |i_CTRL-O| {@link com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction}
* |i_CTRL-P| {@link com.maddyhome.idea.vim.action.window.LookupUpAction}
* |i_CTRL-Q| TO BE IMPLEMENTED
* |i_CTRL-R| {@link com.maddyhome.idea.vim.action.change.insert.InsertRegisterAction}
* |i_CTRL-R_CTRL-R| TO BE IMPLEMENTED
* |i_CTRL-R_CTRL-O| TO BE IMPLEMENTED
* |i_CTRL-R_CTRL-P| TO BE IMPLEMENTED
* |i_CTRL-T| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightLinesAction}
* |i_CTRL-U| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeleteInsertedTextAction}
* |i_CTRL-V| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
* |i_CTRL-V_digit| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
* |i_CTRL-W| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeletePreviousWordAction}
* |i_CTRL-X| TO BE IMPLEMENTED
* |i_CTRL-Y| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterAboveCursorAction}
* |i_CTRL-Z| TO BE IMPLEMENTED
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
* |i_CTRL-]} TO BE IMPLEMENTED
* |i_CTRL-^| TO BE IMPLEMENTED
* |i_CTRL-_| TO BE IMPLEMENTED
* |i_0_CTRL-D| TO BE IMPLEMENTED
* |i_^_CTRL-D| TO BE IMPLEMENTED
* |i_<Del>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDelete}
* |i_<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction}
* |i_<S-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
* |i_<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
* |i_<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction}
* |i_<S-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
* |i_<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
* |i_<Up>| {@link com.maddyhome.idea.vim.action.editor.VimEditorUp}
* |i_<S-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
* |i_<Down>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDown}
* |i_<S-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
* |i_<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnInsertModeAction}
* |i_<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstInsertAction}
* |i_<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnInsertAction}
* |i_<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndInsertAction}
* |i_<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertInsertAction}
* |i_<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
* |i_<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
* |i_<F1>| IntelliJ help
* |i_<Insert>| IntelliJ editor toggle insert/replace
* |i_CTRL-X_index| TO BE IMPLEMENTED
*
*
* 2. Normal mode
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberIncAction}
* |CTRL-B| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
* |CTRL-C| TO BE IMPLEMENTED
* |CTRL-D| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageDownAction}
* |CTRL-E| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineDownAction}
* |CTRL-F| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
* |CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetFileInfoAction}
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
* |CTRL-H| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
* |<Tab>| TO BE IMPLEMENTED
* |CTRL-I| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpNextAction}
* |<NL>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownNotLineWiseAction}
* |CTRL-J| TO BE IMPLEMENTED
* |CTRL-L| not applicable
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.updown.EnterNormalAction}
* |CTRL-M| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
* |CTRL-N| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction}
* |CTRL-O| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpPreviousAction}
* |CTRL-P| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpCtrlPAction}
* |CTRL-R| {@link com.maddyhome.idea.vim.action.change.RedoAction}
* |CTRL-T| TO BE IMPLEMENTED
* |CTRL-U| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageUpAction}
* |CTRL-V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleBlockModeAction}
* |CTRL-W| see window commands
* |CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberDecAction}
* |CTRL-Y| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineUpAction}
* |CTRL-Z| TO BE IMPLEMENTED
* |CTRL-]| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
* |CTRL-6| {@link com.maddyhome.idea.vim.action.file.FilePreviousAction}
* |CTRL-\CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
* |<Space>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionSpaceAction}
* |!| {@link com.maddyhome.idea.vim.action.change.change.FilterMotionAction}
* |!!| translated to !_
* |quote| handled by command key parser
* |#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordBackwardAction}
* |$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction}
* |%| {@link com.maddyhome.idea.vim.action.motion.updown.MotionPercentOrMatchAction}
* |&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastSearchReplaceAction}
* |'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineAction}
* |''| ?
* ...
* |(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousStartAction}
* |)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextStartAction}
* |star| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction}
* |+| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
* |,| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharReverseAction}
* |-| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpFirstNonSpaceAction}
* |.| {@link com.maddyhome.idea.vim.action.change.RepeatChangeAction}
* |/| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction}
* |:| {@link com.maddyhome.idea.vim.action.ex.ExEntryAction}
* |;| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharAction}
* |<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftMotionAction}
* |<<| translated to <_
* |=| {@link com.maddyhome.idea.vim.action.change.shift.AutoIndentMotionAction}
* |==| translated to =_
* |>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightMotionAction}
* |>>| translated to >_
* |?| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction}
* |@| {@link com.maddyhome.idea.vim.action.macro.PlaybackRegisterAction}
* |A| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterLineEndAction}
* |B| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordLeftAction}
* |C| {@link com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction}
* |D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteEndOfLineAction}
* |E| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndRightAction}
* |F| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftMatchCharAction}
* |G| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastAction}
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionFirstScreenLineAction}
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingFirstScreenLineAction}
* |I| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeFirstNonBlankAction}
* |J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction}
* |K| {@link com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc}
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionLastScreenLineAction}
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingLastScreenLineAction}
* |M| {@link com.maddyhome.idea.vim.action.motion.screen.MotionMiddleScreenLineAction}
* |N| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainPreviousAction}
* |O| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineAboveAction}
* |P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorAction}
* |Q| TO BE IMPLEMENTED
* |R| {@link com.maddyhome.idea.vim.action.change.change.ChangeReplaceAction}
* |S| {@link com.maddyhome.idea.vim.action.change.change.ChangeLineAction}
* |T| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftTillMatchCharAction}
* |U| ?
* |V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleLineModeAction}
* |W| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordRightAction}
* |X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterLeftAction}
* |Y| {@link com.maddyhome.idea.vim.action.copy.YankLineAction}
* |ZZ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
* |ZQ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
* |[| see bracket commands
* |]| see bracket commands
* |^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstNonSpaceAction}
* |_| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction}
* |`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkAction}
* |``| ?
* ...
* |0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnAction}
* |a| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterCursorAction}
* |b| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
* |c| {@link com.maddyhome.idea.vim.action.change.change.ChangeMotionAction}
* |cc| translated to c_
* |d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteMotionAction}
* |dd| translated to d_
* |do| TO BE IMPLEMENTED
* |dp| TO BE IMPLEMENTED
* |e| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndRightAction}
* |f| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction}
* |g| see commands starting with 'g'
* |h| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction}
* |i| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
* |j| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownAction}
* |k| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpAction}
* |l| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction}
* |m| {@link com.maddyhome.idea.vim.action.motion.mark.MotionMarkAction}
* |n| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainNextAction}
* |o| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineBelowAction}
* |p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorAction}
* |q| {@link com.maddyhome.idea.vim.action.macro.ToggleRecordingAction}
* |r| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction}
* |s| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction}
* |t| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction}
* |u| {@link com.maddyhome.idea.vim.action.change.UndoAction}
* |v| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction}
* |w| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
* |x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterRightAction}
* |y| {@link com.maddyhome.idea.vim.action.copy.YankMotionAction}
* |yy| translated to y_
* |z| see commands starting with 'z'
* |{| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphPreviousAction}
* |bar| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionColumnAction}
* |}| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphNextAction}
* |~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction}
* |<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndAction}
* |<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
* |<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
* |<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
* |<C-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlDownAction}
* |<C-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlUpAction}
* |<Del>| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction}
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
* |<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction}
* |<F1>| IntelliJ help
* |<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction}
* |<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction}
* |<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
* |<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction}
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
* |<S-Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction}
* |<S-End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction}
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
*
*
* 2.1. Text objects
*
* Text object commands are listed in the visual mode section.
*
*
* 2.2. Window commands
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |CTRL-W_+| TO BE IMPLEMENTED
* |CTRL-W_-| TO BE IMPLEMENTED
* |CTRL-W_<| TO BE IMPLEMENTED
* |CTRL-W_=| TO BE IMPLEMENTED
* |CTRL-W_>| TO BE IMPLEMENTED
* |CTRL-W_H| TO BE IMPLEMENTED
* |CTRL-W_J| TO BE IMPLEMENTED
* |CTRL-W_K| TO BE IMPLEMENTED
* |CTRL-W_L| TO BE IMPLEMENTED
* |CTRL-W_P| TO BE IMPLEMENTED
* |CTRL-W_R| TO BE IMPLEMENTED
* |CTRL-W_S| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
* |CTRL-W_T| TO BE IMPLEMENTED
* |CTRL-W_W| {@link com.maddyhome.idea.vim.action.window.WindowPrevAction}
* |CTRL-W_]| TO BE IMPLEMENTED
* |CTRL-W_^| TO BE IMPLEMENTED
* |CTRL-W__| TO BE IMPLEMENTED
* |CTRL-W_b| TO BE IMPLEMENTED
* |CTRL-W_c| {@link com.maddyhome.idea.vim.action.window.CloseWindowAction}
* |CTRL-W_d| TO BE IMPLEMENTED
* |CTRL-W_f| TO BE IMPLEMENTED
* |CTRL-W-F| TO BE IMPLEMENTED
* |CTRL-W-g]| TO BE IMPLEMENTED
* |CTRL-W-g}| TO BE IMPLEMENTED
* |CTRL-W-gf| TO BE IMPLEMENTED
* |CTRL-W-gF| TO BE IMPLEMENTED
* |CTRL-W_h| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
* |CTRL-W_i| TO BE IMPLEMENTED
* |CTRL-W_j| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
* |CTRL-W_k| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
* |CTRL-W_l| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
* |CTRL-W_n| TO BE IMPLEMENTED
* |CTRL-W_o| {@link com.maddyhome.idea.vim.action.window.WindowOnlyAction}
* |CTRL-W_p| TO BE IMPLEMENTED
* |CTRL-W_q| TO BE IMPLEMENTED
* |CTRL-W_r| TO BE IMPLEMENTED
* |CTRL-W_s| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
* |CTRL-W_t| TO BE IMPLEMENTED
* |CTRL-W_v| {@link com.maddyhome.idea.vim.action.window.VerticalSplitAction}
* |CTRL-W_w| {@link com.maddyhome.idea.vim.action.window.WindowNextAction}
* |CTRL-W_x| TO BE IMPLEMENTED
* |CTRL-W_z| TO BE IMPLEMENTED
* |CTRL-W_bar| TO BE IMPLEMENTED
* |CTRL-W_}| TO BE IMPLEMENTED
* |CTRL-W_<Down>| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
* |CTRL-W_<Up>| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
* |CTRL-W_<Left>| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
* |CTRL-W_<Right>| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
* |CTRL-W_CTRL-H| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
* |CTRL-W_CTRL-J| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
* |CTRL-W_CTRL-K| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
* |CTRL-W_CTRL-L| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
*
*
* 2.3. Square bracket commands
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
* |[_CTRL-D| TO BE IMPLEMENTED
* |[_CTRL-I| TO BE IMPLEMENTED
* |[#| TO BE IMPLEMENTED
* |['| TO BE IMPLEMENTED
* |[(| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenOpenAction}
* |[star| TO BE IMPLEMENTED
* |[`| TO BE IMPLEMENTED
* |[/| TO BE IMPLEMENTED
* |[D| TO BE IMPLEMENTED
* |[I| TO BE IMPLEMENTED
* |[M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousEndAction}
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
* |[[| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardStartAction}
* |[]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardEndAction}
* |[c| TO BE IMPLEMENTED
* |[d| TO BE IMPLEMENTED
* |[f| TO BE IMPLEMENTED
* |[i| TO BE IMPLEMENTED
* |[m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
* |[s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
* |[z| TO BE IMPLEMENTED
* |[{| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
* |]_CTRL-D| TO BE IMPLEMENTED
* |]_CTRL-I| TO BE IMPLEMENTED
* |]#| TO BE IMPLEMENTED
* |]'| TO BE IMPLEMENTED
* |])| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenCloseAction}
* |]star| TO BE IMPLEMENTED
* |]`| TO BE IMPLEMENTED
* |]/| TO BE IMPLEMENTED
* |]D| TO BE IMPLEMENTED
* |]I| TO BE IMPLEMENTED
* |]M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction}
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
* |][| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardEndAction}
* |]]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardStartAction}
* |]c| TO BE IMPLEMENTED
* |]d| TO BE IMPLEMENTED
* |]f| TO BE IMPLEMENTED
* |]i| TO BE IMPLEMENTED
* |]m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
* |]s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
* |]z| TO BE IMPLEMENTED
* |]}| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
*
*
* 2.4. Commands starting with 'g'
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |g_CTRL-A| not applicable
* |g_CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetLocationInfoAction}
* |g_CTRL-H| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableBlockModeAction}
* |g_CTRL-]| TO BE IMPLEMENTED
* |g#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordBackwardAction}
* |g$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
* |g&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastGlobalSearchReplaceAction}
* |v_g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineNoSaveJumpAction}
* |g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineNoSaveJumpAction}
* |g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkNoSaveJumpAction}
* |gstar| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordForwardAction}
* |g+| TO BE IMPLEMENTED
* |g,| TO BE IMPLEMENTED
* |g-| TO BE IMPLEMENTED
* |g0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
* |g8| {@link com.maddyhome.idea.vim.action.file.FileGetHexAction}
* |g;| TO BE IMPLEMENTED
* |g<| TO BE IMPLEMENTED
* |g?| TO BE IMPLEMENTED
* |g?g?| TO BE IMPLEMENTED
* |gD| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
* |gE| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndLeftAction}
* |gF| TO BE IMPLEMENTED
* |gH| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableLineModeAction}
* |gI| {@link com.maddyhome.idea.vim.action.change.insert.InsertLineStartAction}
* |gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction}
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch}
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject}
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorMoveCursorAction}
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorActionMoveCursor}
* |gQ| TO BE IMPLEMENTED
* |gR| TO BE IMPLEMENTED
* |gT| {@link com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction}
* |gU| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction}
* |gV| TO BE IMPLEMENTED
* |g]| TO BE IMPLEMENTED
* |g^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenNonSpaceAction}
* |g_| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastNonSpaceAction}
* |ga| {@link com.maddyhome.idea.vim.action.file.FileGetAsciiAction}
* |gd| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
* |ge| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndLeftAction}
* |gf| TO BE IMPLEMENTED
* |gg| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
* |gh| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableCharacterModeAction}
* |gi| {@link com.maddyhome.idea.vim.action.change.insert.InsertAtPreviousInsertAction}
* |gj| TO BE IMPLEMENTED
* |gk| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch}
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject}
* |gm| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionMiddleColumnAction}
* |go| {@link com.maddyhome.idea.vim.action.motion.text.MotionNthCharacterAction}
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorMoveCursorAction}
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorActionMoveCursor}
* |gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeMotionAction}
* |gr| TO BE IMPLEMENTED
* |gs| TO BE IMPLEMENTED
* |gt| {@link com.maddyhome.idea.vim.action.window.tabs.NextTabAction}
* |gu| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction}
* |gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSelectPreviousAction}
* |gw| TO BE IMPLEMENTED
* |g@| {@link com.maddyhome.idea.vim.action.change.OperatorAction}
* |g~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction}
* |g<Down>| TO BE IMPLEMENTED
* |g<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
* |g<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
* |g<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
*
*
* 2.5. Commands starting with 'z'
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
* |z<CR>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineStartAction}
* |z+| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLinePageStartAction}
* |z-| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineStartAction}
* |z.| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineStartAction}
* |z=| TO BE IMPLEMENTED
* |zA| TO BE IMPLEMENTED
* |zC| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegionRecursively}
* |zD| TO BE IMPLEMENTED
* |zE| TO BE IMPLEMENTED
* |zF| TO BE IMPLEMENTED
* |zG| TO BE IMPLEMENTED
* |zH| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction}
* |zL| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction}
* |zM| {@link com.maddyhome.idea.vim.action.fold.VimCollapseAllRegions}
* |zN| TO BE IMPLEMENTED
* |zO| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegionRecursively}
* |zR| {@link com.maddyhome.idea.vim.action.fold.VimExpandAllRegions}
* |zW| TO BE IMPLEMENTED
* |zX| TO BE IMPLEMENTED
* |z^| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLinePageStartAction}
* |za| TO BE IMPLEMENTED
* |zb| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineAction}
* |zc| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegion}
* |zd| not applicable
* |ze| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenColumnAction}
* |zf| not applicable
* |zg| TO BE IMPLEMENTED
* |zh| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
* |zi| TO BE IMPLEMENTED
* |zj| TO BE IMPLEMENTED
* |zk| TO BE IMPLEMENTED
* |zl| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
* |zm| TO BE IMPLEMENTED
* |zn| TO BE IMPLEMENTED
* |zo| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegion}
* |zr| TO BE IMPLEMENTED
* |zs| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenColumnAction}
* |zt| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineAction}
* |zv| TO BE IMPLEMENTED
* |zw| TO BE IMPLEMENTED
* |zx| TO BE IMPLEMENTED
* |zz| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineAction}
* |z<Left>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
* |z<Right>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
*
*
* 3. Visual mode
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |v_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
* |v_CTRL-\_CTRL-G| TO BE IMPLEMENTED
* |v_CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberIncAction}
* |v_CTRL-C| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
* |v_CTRL-G| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
* |v_<BS>| NVO mapping
* |v_CTRL-H| NVO mapping
* |v_CTRL-O| TO BE IMPLEMENTED
* |v_CTRL-V| NVO mapping
* |v_<Esc>| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
* |v_CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberDecAction}
* |v_CTRL-]| TO BE IMPLEMENTED
* |v_!| {@link com.maddyhome.idea.vim.action.change.change.FilterVisualLinesAction}
* |v_:| NVO mapping
* |v_<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftVisualAction}
* |v_=| {@link com.maddyhome.idea.vim.action.change.change.AutoIndentLinesVisualAction}
* |v_>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightVisualAction}
* |v_b_A| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction}
* |v_C| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesEndAction}
* |v_D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesEndAction}
* |v_b_I| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction}
* |v_J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction}
* |v_K| TO BE IMPLEMENTED
* |v_O| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsBlockAction}
* |v_P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorAction}
* |v_R| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
* |v_S| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
* |v_U| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction}
* |v_V| NV mapping
* |v_X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesAction}
* |v_Y| {@link com.maddyhome.idea.vim.action.copy.YankVisualLinesAction}
* |v_aquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockDoubleQuoteAction}
* |v_a'| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockSingleQuoteAction}
* |v_a(| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
* |v_a)| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
* |v_a<| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
* |v_a>| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
* |v_aB| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
* |v_aW| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction}
* |v_a[| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
* |v_a]| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
* |v_a`| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBackQuoteAction}
* |v_ab| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
* |v_ap| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterParagraphAction}
* |v_as| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterSentenceAction}
* |v_at| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockTagAction}
* |v_aw| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction}
* |v_a{| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
* |v_a}| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
* |v_c| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
* |v_d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
* |v_gCTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheIncAction}
* |v_gCTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheDecAction}
* |v_gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction}
* |v_gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeVisualAction}
* |v_gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapSelectionsAction}
* |v_g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkNoSaveJumpAction}
* |v_g@| {@link com.maddyhome.idea.vim.action.change.VisualOperatorAction}
* |v_iquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockDoubleQuoteAction}
* |v_i'| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockSingleQuoteAction}
* |v_i(| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
* |v_i)| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
* |v_i<| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
* |v_i>| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
* |v_iB| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
* |v_iW| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBigWordAction}
* |v_i[| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
* |v_i]| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
* |v_i`| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBackQuoteAction}
* |v_ib| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
* |v_ip| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerParagraphAction}
* |v_is| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerSentenceAction}
* |v_it| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockTagAction}
* |v_iw| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerWordAction}
* |v_i{| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
* |v_i}| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
* |v_o| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsAction}
* |v_p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorAction}
* |v_r| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction}
* |v_s| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
* |v_u| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction}
* |v_v| NV mapping
* |v_x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
* |v_y| {@link com.maddyhome.idea.vim.action.copy.YankVisualAction}
* |v_~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction}
* |v_`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkAction}
* |v_'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineAction}
*
*
* 4. Select mode
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnterAction}
* |<DEL>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
* |<ESC>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEscapeAction}
* |<C-G>| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction}
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction}
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
*
* 5. Command line editing
*
* tag action
* -------------------------------------------------------------------------------------------------------------------
*
* |c_CTRL-A| TO BE IMPLEMENTED
* |c_CTRL-B| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
* |c_CTRL-C| {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
* |c_CTRL-D| TO BE IMPLEMENTED
* |c_CTRL-E| {@link javax.swing.text.DefaultEditorKit#endLineAction}
* |c_CTRL-G| TO BE IMPLEMENTED
* |c_CTRL-H| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
* |c_CTRL-I| TO BE IMPLEMENTED
* |c_CTRL-J| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_CTRL-K| Handled by KeyHandler
* |c_CTRL-L| TO BE IMPLEMENTED
* |c_CTRL-M| {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
* |c_CTRL-N| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_CTRL-P| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_CTRL-Q| Handled by KeyHandler
* |c_CTRL-R_CTRL-A| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-F| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-L| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-O| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-P| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-R| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-W| TO BE IMPLEMENTED
* |c_CTRL-T| TO BE IMPLEMENTED
* |c_CTRL-U| {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
* |c_CTRL-V| Handled by KeyHandler
* |c_CTRL-W| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
* |c_CTRL-Y| TO BE IMPLEMENTED
* |c_CTRL-\_e| TO BE IMPLEMENTED
* |c_CTRL-\_CTRL-G| TO BE IMPLEMENTED
* |c_CTRL-\_CTRL-N| TO BE IMPLEMENTED
* |c_CTRL-_| not applicable
* |c_CTRL-^| not applicable
* |c_CTRL-]| TO BE IMPLEMENTED
* |c_CTRL-[| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
* |c_<BS>| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
* |c_<CR>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_<C-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
* |c_<C-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
* |c_<Del>| {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
* |c_<Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
* |c_<End>| {@link javax.swing.text.DefaultEditorKit#endLineAction}
* |c_<Esc>| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
* |c_<Home>| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
* |c_<Insert>| {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
* |c_<Left>| {@link javax.swing.text.DefaultEditorKit#backwardAction}
* |c_<LeftMouse>| not applicable
* |c_<MiddleMouse>| TO BE IMPLEMENTED
* |c_<NL>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_<PageUp>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_<PageDown>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_<Right>| {@link javax.swing.text.DefaultEditorKit#forwardAction}
* |c_<S-Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_<S-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
* |c_<S-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
* |c_<S-Tab>| TO BE IMPLEMENTED
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_<Tab>| TO BE IMPLEMENTED
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
* |c_digraph| {char1} <BS> {char2}
* |c_wildchar| TO BE IMPLEMENTED
* |'cedit'| TO BE IMPLEMENTED
*
*
* 6. Ex commands
*
* tag handler
* -------------------------------------------------------------------------------------------------------------------
*
* |:map| {@link com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand}
* |:nmap| ...
* |:vmap| ...
* |:omap| ...
* |:imap| ...
* |:cmap| ...
* |:noremap| ...
* |:nnoremap| ...
* |:vnoremap| ...
* |:onoremap| ...
* |:inoremap| ...
* |:cnoremap| ...
* |:shell| {@link com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand}
* |:sort| {@link com.maddyhome.idea.vim.vimscript.model.commands.SortCommand}
* |:source| {@link com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand}
* |:qall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
* |:wqall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
* |:xall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
* |:command| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand}
* |:delcommand| {@link com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand}
* |:comclear| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand}
* ...
*
* The list of supported Ex commands is incomplete.
*
*
* A. Misc commands
*
* tag handler
* -------------------------------------------------------------------------------------------------------------------
* |]b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndLeftAction}
* |]w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndRightAction}
* |[b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelLeftAction}
* |[w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelRightAction}
* |g(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousEndAction}
* |g)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextEndAction}
*
*
* See also :help index.
*
* @author vlan
*/
package com.maddyhome.idea.vim;

View File

@ -1,263 +0,0 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.ui.ex
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.api.LocalOptionInitialisationScenario
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import java.awt.event.ActionEvent
import java.awt.event.KeyEvent
import javax.swing.Action
import javax.swing.KeyStroke
import javax.swing.text.BadLocationException
import javax.swing.text.DefaultEditorKit
import javax.swing.text.Document
import javax.swing.text.TextAction
import kotlin.math.abs
import kotlin.math.min
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal interface MultiStepAction : Action {
fun reset()
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class HistoryUpAction : TextAction(ExEditorKit.HistoryUp) {
override fun actionPerformed(actionEvent: ActionEvent) {
val target = getTextComponent(actionEvent) as ExTextField
target.selectHistory(true, false)
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class HistoryDownAction : TextAction(ExEditorKit.HistoryDown) {
override fun actionPerformed(actionEvent: ActionEvent) {
val target = getTextComponent(actionEvent) as ExTextField
target.selectHistory(false, false)
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class HistoryUpFilterAction : TextAction(ExEditorKit.HistoryUpFilter) {
override fun actionPerformed(actionEvent: ActionEvent) {
val target = getTextComponent(actionEvent) as ExTextField
target.selectHistory(true, true)
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class HistoryDownFilterAction : TextAction(ExEditorKit.HistoryDownFilter) {
override fun actionPerformed(actionEvent: ActionEvent) {
val target = getTextComponent(actionEvent) as ExTextField
target.selectHistory(false, true)
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class CompleteEntryAction : TextAction(ExEditorKit.CompleteEntry) {
override fun actionPerformed(actionEvent: ActionEvent) {
logger.debug("complete entry")
val stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
// We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
// We do this for a couple of reasons:
// * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
// write action
// * The key handler routines get the chance to clean up and reset state
val entry = ExEntryPanel.getInstance().entry
val keyHandler = KeyHandler.getInstance()
keyHandler.handleKey(entry.editor!!.vim, stroke, entry.context.vim, keyHandler.keyHandlerState)
}
companion object {
private val logger = logger<CompleteEntryAction>()
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class CancelEntryAction : TextAction(ExEditorKit.CancelEntry) {
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.cancel()
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class EscapeCharAction : TextAction(ExEditorKit.EscapeChar) {
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.escape()
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal abstract class DeleteCharAction internal constructor(name: String?) : TextAction(name) {
@kotlin.jvm.Throws(BadLocationException::class)
fun deleteSelection(doc: Document, dot: Int, mark: Int): Boolean {
if (dot != mark) {
doc.remove(min(dot, mark), abs(dot - mark))
return true
}
return false
}
@kotlin.jvm.Throws(BadLocationException::class)
fun deleteNextChar(doc: Document, dot: Int): Boolean {
if (dot < doc.length) {
var delChars = 1
if (dot < doc.length - 1) {
val dotChars = doc.getText(dot, 2)
val c0 = dotChars[0]
val c1 = dotChars[1]
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
delChars = 2
}
}
doc.remove(dot, delChars)
return true
}
return false
}
@kotlin.jvm.Throws(BadLocationException::class)
fun deletePrevChar(doc: Document, dot: Int): Boolean {
if (dot > 0) {
var delChars = 1
if (dot > 1) {
val dotChars = doc.getText(dot - 2, 2)
val c0 = dotChars[0]
val c1 = dotChars[1]
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
delChars = 2
}
}
doc.remove(dot - delChars, delChars)
return true
}
return false
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class DeleteNextCharAction : DeleteCharAction(DefaultEditorKit.deleteNextCharAction) {
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.saveLastEntry()
try {
val doc = target.document
val caret = target.caret
val dot = caret.dot
val mark = caret.mark
if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
target.cancel()
}
} catch (ex: BadLocationException) {
// ignore
}
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class DeletePreviousCharAction : DeleteCharAction(DefaultEditorKit.deletePrevCharAction) {
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.saveLastEntry()
try {
val doc = target.document
val caret = target.caret
val dot = caret.dot
val mark = caret.mark
if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
if (dot == 0 && doc.length == 0) {
target.cancel()
}
}
} catch (bl: BadLocationException) {
// ignore
}
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class DeletePreviousWordAction : TextAction(DefaultEditorKit.deletePrevWordAction) {
/**
* Invoked when an action occurs.
*/
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.saveLastEntry()
val doc = target.document
val caret = target.caret
val project = target.editor!!.project
// Create a VimEditor instance on the Swing text field which we can pass to the search helpers. We need an editor
// rather than just working on a buffer because the search helpers need local options (specifically the local to
// buffer 'iskeyword'). We use the CMD_LINE scenario to initialise local options from the main editor. The options
// service will copy all local-to-buffer and local-to-window options, effectively cloning the options.
// TODO: Over time, we should migrate all ex actions to be based on VimEditor
// This will mean we always have an editor that has been initialised for options, etc. But also means that we can
// share the command line entry actions between IdeaVim implementations
val editor = TextComponentEditorImpl(project, target).vim
injector.optionGroup.initialiseLocalOptions(editor, target.editor!!.vim, LocalOptionInitialisationScenario.CMD_LINE)
val offset = injector.searchHelper.findNextWord(editor, caret.dot, -1, bigWord = false, spaceWords = false)
if (logger.isDebugEnabled) logger.debug("offset=$offset")
try {
val pos = caret.dot
doc.remove(offset, pos - offset)
} catch (ex: BadLocationException) {
// ignore
}
}
companion object {
private val logger = logger<DeletePreviousWordAction>()
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class DeleteToCursorAction : TextAction(ExEditorKit.DeleteToCursor) {
/**
* Invoked when an action occurs.
*/
override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField
target.saveLastEntry()
val doc = target.document
val caret = target.caret
try {
doc.remove(0, caret.dot)
} catch (ex: BadLocationException) {
// ignore
}
}
}
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal class ToggleInsertReplaceAction : TextAction(ExEditorKit.ToggleInsertReplace) {
/**
* Invoked when an action occurs.
*/
override fun actionPerformed(e: ActionEvent) {
logger.debug("actionPerformed")
val target = getTextComponent(e) as ExTextField
target.toggleInsertReplace()
}
init {
logger.debug("ToggleInsertReplaceAction()")
}
companion object {
private val logger = logger<ToggleInsertReplaceAction>()
}
}

View File

@ -34,7 +34,7 @@ public class ExDocument extends PlainDocument {
void toggleInsertReplace() { void toggleInsertReplace() {
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine(); VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
if (commandLine != null) { if (commandLine != null) {
commandLine.toggleReplaceMode(); ((ExEntryPanel) commandLine).isReplaceMode = !((ExEntryPanel)commandLine).isReplaceMode;
} }
overwrite = !overwrite; overwrite = !overwrite;
} }

View File

@ -7,7 +7,6 @@
*/ */
package com.maddyhome.idea.vim.ui.ex package com.maddyhome.idea.vim.ui.ex
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
@ -15,50 +14,12 @@ import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import java.awt.event.ActionEvent import java.awt.event.ActionEvent
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import javax.swing.Action
import javax.swing.KeyStroke import javax.swing.KeyStroke
import javax.swing.text.DefaultEditorKit import javax.swing.text.DefaultEditorKit
import javax.swing.text.Document import javax.swing.text.Document
import javax.swing.text.TextAction
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes") @Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
internal object ExEditorKit : DefaultEditorKit() { internal object ExEditorKit : DefaultEditorKit() {
@NonNls
val CancelEntry: String = "cancel-entry"
@NonNls
val CompleteEntry: String = "complete-entry"
@NonNls
val EscapeChar: String = "escape"
@NonNls
val DeleteToCursor: String = "delete-to-cursor"
@NonNls
val ToggleInsertReplace: String = "toggle-insert"
@NonNls
val HistoryUp: String = "history-up"
@NonNls
val HistoryDown: String = "history-down"
@NonNls
val HistoryUpFilter: String = "history-up-filter"
@NonNls
val HistoryDownFilter: String = "history-down-filter"
@NonNls
val StartDigraph: String = "start-digraph"
@NonNls
val StartLiteral: String = "start-literal"
private val logger = logger<ExEditorKit>()
/** /**
* Gets the MIME type of the data that this * Gets the MIME type of the data that this
* kit represents support for. * kit represents support for.
@ -70,19 +31,6 @@ internal object ExEditorKit : DefaultEditorKit() {
return "text/ideavim" return "text/ideavim"
} }
/**
* Fetches the set of commands that can be used
* on a text component that is using a model and
* view produced by this kit.
*
* @return the set of actions
*/
override fun getActions(): Array<Action> {
val res = TextAction.augmentList(super.getActions(), exActions)
logger.debug { "res.length=${res.size}" }
return res
}
/** /**
* Creates an uninitialized text storage model * Creates an uninitialized text storage model
* that is appropriate for this type of editor. * that is appropriate for this type of editor.
@ -93,28 +41,10 @@ internal object ExEditorKit : DefaultEditorKit() {
return ExDocument() return ExDocument()
} }
private val exActions = arrayOf<Action>(
CancelEntryAction(),
CompleteEntryAction(),
EscapeCharAction(),
DeleteNextCharAction(),
DeletePreviousCharAction(),
DeletePreviousWordAction(),
DeleteToCursorAction(),
HistoryUpAction(),
HistoryDownAction(),
HistoryUpFilterAction(),
HistoryDownFilterAction(),
ToggleInsertReplaceAction(),
)
class DefaultExKeyHandler : DefaultKeyTypedAction() { class DefaultExKeyHandler : DefaultKeyTypedAction() {
override fun actionPerformed(e: ActionEvent) { override fun actionPerformed(e: ActionEvent) {
val target = getTextComponent(e) as ExTextField val target = getTextComponent(e) as ExTextField
val currentAction = target.currentAction
if (currentAction != null) {
currentAction.actionPerformed(e)
} else {
val key = convert(e) val key = convert(e)
if (key != null) { if (key != null) {
val c = key.keyChar val c = key.keyChar
@ -137,7 +67,6 @@ internal object ExEditorKit : DefaultEditorKit() {
} }
} }
} }
}
fun convert(event: ActionEvent): KeyStroke? { fun convert(event: ActionEvent): KeyStroke? {
val cmd = event.actionCommand val cmd = event.actionCommand

View File

@ -63,7 +63,7 @@ import static com.maddyhome.idea.vim.group.KeyGroup.toShortcutSet;
public class ExEntryPanel extends JPanel implements VimCommandLine { public class ExEntryPanel extends JPanel implements VimCommandLine {
public static ExEntryPanel instance; public static ExEntryPanel instance;
public static ExEntryPanel instanceWithoutShortcuts; public static ExEntryPanel instanceWithoutShortcuts;
private boolean isReplaceMode = false; public boolean isReplaceMode = false;
private WeakReference<Editor> weakEditor = null; private WeakReference<Editor> weakEditor = null;
private VimInputInterceptor myInputInterceptor = null; private VimInputInterceptor myInputInterceptor = null;
@ -405,7 +405,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
@Override @Override
public void toggleReplaceMode() { public void toggleReplaceMode() {
isReplaceMode = !isReplaceMode; entry.toggleInsertReplace();
} }
/** /**
@ -538,10 +538,11 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
} }
@Override @Override
public void setText(@NotNull String string) { public void setText(@NotNull String string, boolean updateLastEntry) {
// It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this // It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
int offset = getCaret().getOffset(); int offset = getCaret().getOffset();
entry.updateText(string); entry.updateText(string);
if (updateLastEntry) entry.saveLastEntry();
getCaret().setOffset(Math.min(offset, getVisibleText().length())); getCaret().setOffset(Math.min(offset, getVisibleText().length()));
} }
@ -598,6 +599,27 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
return finishOn; return finishOn;
} }
@Override
public int getHistIndex() {
return entry.histIndex;
}
@Override
public void setHistIndex(int i) {
entry.histIndex = i;
}
@NotNull
@Override
public String getLastEntry() {
return entry.lastEntry;
}
@Override
public void setLastEntry(@NotNull String s) {
entry.lastEntry = s;
}
public static class LafListener implements LafManagerListener { public static class LafListener implements LafManagerListener {
@Override @Override
public void lookAndFeelChanged(@NotNull LafManager source) { public void lookAndFeelChanged(@NotNull LafManager source) {

View File

@ -21,57 +21,6 @@ internal object ExKeyBindings {
val bindings: Array<KeyBinding> by lazy { val bindings: Array<KeyBinding> by lazy {
arrayOf( arrayOf(
// Escape will cancel a pending insert digraph/register before cancelling
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ExEditorKit.EscapeChar),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.EscapeChar),
// Cancel entry, ignoring any pending actions such as digraph/registry entry
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CancelEntry),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ExEditorKit.CompleteEntry),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
KeyBinding(KeyStroke.getKeyStroke(0x02.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), DefaultEditorKit.beginLineAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
KeyBinding(KeyStroke.getKeyStroke(0x05.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), DefaultEditorKit.endLineAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.deletePrevCharAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
KeyBinding(KeyStroke.getKeyStroke(0x08.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DefaultEditorKit.deleteNextCharAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevWordAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.DeleteToCursor),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ExEditorKit.HistoryUpFilter),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryUp),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ExEditorKit.HistoryUp),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryUp),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ExEditorKit.HistoryDownFilter),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryDown),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ExEditorKit.HistoryDown),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryDown),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), ExEditorKit.ToggleInsertReplace),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.previousWordAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.previousWordAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), DefaultEditorKit.forwardAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.nextWordAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.nextWordAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartDigraph),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
// These appear to be non-Vim shortcuts // These appear to be non-Vim shortcuts
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction), KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction), KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),

View File

@ -59,9 +59,45 @@ internal class ExShortcutKeyAction(private val exEntryPanel: ExEntryPanel) : Dum
} }
fun registerCustomShortcutSet() { fun registerCustomShortcutSet() {
val shortcuts = ExKeyBindings.bindings.map { val shortcuts = listOf(
KeyboardShortcut(it.key, null) KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
}.toTypedArray() KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK),
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK),
)
.map { KeyboardShortcut(it, null) }
.toTypedArray()
registerCustomShortcutSet({ shortcuts }, exEntryPanel) registerCustomShortcutSet({ shortcuts }, exEntryPanel)
} }

View File

@ -16,11 +16,9 @@ import com.intellij.util.ui.JBUI;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.VimCommandLine; import com.maddyhome.idea.vim.api.VimCommandLine;
import com.maddyhome.idea.vim.api.VimCommandLineCaret; import com.maddyhome.idea.vim.api.VimCommandLineCaret;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.helper.UiHelper; import com.maddyhome.idea.vim.helper.UiHelper;
import com.maddyhome.idea.vim.history.HistoryConstants; import com.maddyhome.idea.vim.history.HistoryConstants;
import com.maddyhome.idea.vim.history.HistoryEntry; import com.maddyhome.idea.vim.history.HistoryEntry;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.helpers.GuiCursorAttributes; import com.maddyhome.idea.vim.options.helpers.GuiCursorAttributes;
import com.maddyhome.idea.vim.options.helpers.GuiCursorMode; import com.maddyhome.idea.vim.options.helpers.GuiCursorMode;
import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper; import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper;
@ -67,9 +65,6 @@ public class ExTextField extends JTextField {
// If we're in the middle of an action (e.g. entering a register to paste, or inserting a digraph), cancel it if // If we're in the middle of an action (e.g. entering a register to paste, or inserting a digraph), cancel it if
// the mouse is clicked anywhere. Vim's behavior is to use the mouse click as an event, which can lead to // the mouse is clicked anywhere. Vim's behavior is to use the mouse click as an event, which can lead to
// something like : !%!C, which I don't believe is documented, or useful // something like : !%!C, which I don't believe is documented, or useful
if (currentAction != null) {
clearCurrentAction();
}
super.mouseClicked(e); super.mouseClicked(e);
} }
}); });
@ -240,10 +235,6 @@ public class ExTextField extends JTextField {
// This gets called for ALL events, before the IDE starts to process key events for the action system. We can add a // This gets called for ALL events, before the IDE starts to process key events for the action system. We can add a
// dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField, // dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField,
// dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed. // dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed.
if (currentAction != null) {
currentAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, String.valueOf(c), modifiers));
}
else {
KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED : KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :
(stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED), (stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED),
(new Date()).getTime(), modifiers, keyCode, c); (new Date()).getTime(), modifiers, keyCode, c);
@ -251,11 +242,10 @@ public class ExTextField extends JTextField {
useHandleKeyFromEx = false; useHandleKeyFromEx = false;
try { try {
super.processKeyEvent(event); super.processKeyEvent(event);
}finally { } finally {
useHandleKeyFromEx = true; useHandleKeyFromEx = true;
} }
} }
}
@Override @Override
protected void processKeyEvent(KeyEvent e) { protected void processKeyEvent(KeyEvent e) {
@ -279,13 +269,8 @@ public class ExTextField extends JTextField {
* Cancels current action, if there is one. If not, cancels entry. * Cancels current action, if there is one. If not, cancels entry.
*/ */
void escape() { void escape() {
if (currentAction != null) {
clearCurrentAction();
}
else {
cancel(); cancel();
} }
}
/** /**
* Cancels entry, including any current action. * Cancels entry, including any current action.
@ -299,19 +284,10 @@ public class ExTextField extends JTextField {
} }
public void clearCurrentAction() { public void clearCurrentAction() {
if (currentAction != null) {
currentAction.reset();
}
currentAction = null;
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine(); VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
if (commandLine != null) commandLine.clearPromptCharacter(); if (commandLine != null) commandLine.clearPromptCharacter();
} }
@Nullable
Action getCurrentAction() {
return currentAction;
}
private void setInsertMode() { private void setInsertMode() {
ExDocument doc = (ExDocument)getDocument(); ExDocument doc = (ExDocument)getDocument();
if (doc.isOverwrite()) { if (doc.isOverwrite()) {
@ -542,10 +518,9 @@ public class ExTextField extends JTextField {
private DataContext context; private DataContext context;
private final CommandLineCaret caret; private final CommandLineCaret caret;
private String lastEntry; String lastEntry;
private List<HistoryEntry> history; private List<HistoryEntry> history;
private int histIndex = 0; int histIndex = 0;
private @Nullable MultiStepAction currentAction;
int currentActionPromptCharacterOffset = -1; int currentActionPromptCharacterOffset = -1;
private static final Logger logger = Logger.getInstance(ExTextField.class.getName()); private static final Logger logger = Logger.getInstance(ExTextField.class.getName());

View File

@ -8,114 +8,20 @@
package com.maddyhome.idea.vim.vimscript package com.maddyhome.idea.vim.vimscript
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.VirtualFileManager
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimScriptExecutorBase import com.maddyhome.idea.vim.api.VimScriptExecutorBase
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.FinishException
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
import com.maddyhome.idea.vim.history.HistoryConstants
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.commands.Command
import com.maddyhome.idea.vim.vimscript.model.commands.RepeatCommand
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
import java.io.File import java.io.File
import java.io.IOException
@Service @Service
internal class Executor : VimScriptExecutorBase() { internal class Executor : VimScriptExecutorBase() {
private val logger = logger<Executor>() override fun enableDelayedExtensions() {
override var executingVimscript = false
override var executingIdeaVimRcConfiguration = false
@Throws(ExException::class)
override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
try {
injector.vimscriptExecutor.executingVimscript = true
var finalResult: ExecutionResult = ExecutionResult.Success
val myScript = VimscriptParser.parse(script)
myScript.units.forEach { it.vimContext = vimContext ?: myScript }
for (unit in myScript.units) {
try {
val result = unit.execute(editor, context)
if (result is ExecutionResult.Error) {
finalResult = ExecutionResult.Error
if (indicateErrors) {
VimPlugin.indicateError()
}
}
} catch (e: ExException) {
if (e is FinishException) {
break
}
finalResult = ExecutionResult.Error
if (indicateErrors) {
VimPlugin.showMessage(e.message)
VimPlugin.indicateError()
} else {
logger.warn("Failed while executing $unit. " + e.message)
}
} catch (e: NotImplementedError) {
if (indicateErrors) {
VimPlugin.showMessage("Not implemented yet :(")
VimPlugin.indicateError()
}
} catch (e: Exception) {
logger.warn(e)
if (injector.application.isUnitTest()) {
throw e
}
}
}
if (!skipHistory) {
VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, script)
}
}
return finalResult
} finally {
injector.vimscriptExecutor.executingVimscript = false
// Initialize any extensions that were enabled during execution of this vimscript
// See the doc of this function for details
VimExtensionRegistrar.enableDelayedExtensions() VimExtensionRegistrar.enableDelayedExtensions()
} }
}
override fun executeFile(file: File, editor: VimEditor, fileIsIdeaVimRcConfig: Boolean, indicateErrors: Boolean) { override fun ensureFileIsSaved(file: File) {
val context = DataContext.EMPTY_CONTEXT.vim
try {
if (fileIsIdeaVimRcConfig) {
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
}
ensureFileIsSaved(file)
execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
} catch (ignored: IOException) {
LOG.error(ignored)
} finally {
if (fileIsIdeaVimRcConfig) {
injector.vimrcFileState.saveFileState(file.absolutePath)
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
}
}
}
private fun ensureFileIsSaved(file: File) {
val documentManager = FileDocumentManager.getInstance() val documentManager = FileDocumentManager.getInstance()
VirtualFileManager.getInstance().findFileByNioPath(file.toPath()) VirtualFileManager.getInstance().findFileByNioPath(file.toPath())
@ -123,16 +29,4 @@ internal class Executor : VimScriptExecutorBase() {
?.takeIf(documentManager::isDocumentUnsaved) ?.takeIf(documentManager::isDocumentUnsaved)
?.let(documentManager::saveDocumentAsIs) ?.let(documentManager::saveDocumentAsIs)
} }
@Throws(ExException::class)
override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
val reg = VimPlugin.getRegister().getRegister(':') ?: return false
val text = reg.text ?: return false
execute(text, editor, context, skipHistory = false, indicateErrors = true, CommandLineVimLContext)
return true
}
companion object {
val LOG = logger<Executor>()
}
} }

View File

@ -45,7 +45,9 @@ internal data class ActionListCommand(val range: Range, val argument: String) :
.filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } } .filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } }
.joinToString(lineSeparator) .joinToString(lineSeparator)
ExOutputModel.getInstance(editor.ij).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions)) val outputPanel = injector.outputPanel.getOrCreate(editor, context)
outputPanel.addText(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
outputPanel.show()
return ExecutionResult.Success return ExecutionResult.Success
} }
} }

View File

@ -17,8 +17,8 @@ import com.intellij.vim.annotations.ExCommand
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.ranges.Range import com.maddyhome.idea.vim.ex.ranges.Range
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.vimLine import com.maddyhome.idea.vim.helper.vimLine
@ -45,7 +45,9 @@ internal data class BufferListCommand(val range: Range, val argument: String) :
val filter = pruneUnsupportedFilters(arg) val filter = pruneUnsupportedFilters(arg)
val bufferList = getBufferList(context, filter) val bufferList = getBufferList(context, filter)
ExOutputModel.getInstance(editor.ij).output(bufferList.joinToString(separator = "\n")) val outputPanel = injector.outputPanel.getOrCreate(editor, context)
outputPanel.addText(bufferList.joinToString(separator = "\n"))
outputPanel.show()
return ExecutionResult.Success return ExecutionResult.Success
} }

View File

@ -15,6 +15,7 @@ import com.intellij.vim.annotations.ExCommand
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ExOutputModel
@ -74,7 +75,9 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
if (range.size() == 0) { if (range.size() == 0) {
// Show command output in a window // Show command output in a window
VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let { VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
ExOutputModel.getInstance(editor.ij).output(it) val outputPanel = injector.outputPanel.getOrCreate(editor, context)
outputPanel.addText(it)
outputPanel.show()
} }
lastCommand = command lastCommand = command
ExecutionResult.Success ExecutionResult.Success

View File

@ -0,0 +1,92 @@
[
{
"keys": ".",
"class": "com.maddyhome.idea.vim.action.change.RepeatChangeAction",
"modes": "N"
},
{
"keys": "<BS>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorBackSpace",
"modes": "I"
},
{
"keys": "<C-H>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorBackSpace",
"modes": "I"
},
{
"keys": "<C-I>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
"modes": "I"
},
{
"keys": "<C-L>",
"class": "com.maddyhome.idea.vim.action.RedrawAction",
"modes": "N"
},
{
"keys": "<Del>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDelete",
"modes": "I"
},
{
"keys": "<Down>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
"modes": "I"
},
{
"keys": "<Tab>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
"modes": "I"
},
{
"keys": "<Up>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
"modes": "I"
},
{
"keys": "<kDown>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
"modes": "I"
},
{
"keys": "<kUp>",
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
"modes": "I"
},
{
"keys": "J",
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction",
"modes": "N"
},
{
"keys": "J",
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction",
"modes": "X"
},
{
"keys": "K",
"class": "com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc",
"modes": "N"
},
{
"keys": "g@",
"class": "com.maddyhome.idea.vim.action.change.OperatorAction",
"modes": "N"
},
{
"keys": "g@",
"class": "com.maddyhome.idea.vim.action.change.VisualOperatorAction",
"modes": "X"
},
{
"keys": "gJ",
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction",
"modes": "N"
},
{
"keys": "gJ",
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction",
"modes": "X"
}
]

View File

@ -0,0 +1,9 @@
{
"!": "com.maddyhome.idea.vim.vimscript.model.commands.CmdFilterCommand",
"actionl[ist]": "com.maddyhome.idea.vim.vimscript.model.commands.ActionListCommand",
"b[uffer]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCommand",
"buffers": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
"files": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
"h[elp]": "com.maddyhome.idea.vim.vimscript.model.commands.HelpCommand",
"ls": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand"
}

View File

@ -0,0 +1,6 @@
{
"col": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ColFunctionHandler",
"has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
"line": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LineFunctionHandler",
"submatch": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler"
}

View File

@ -294,20 +294,20 @@ class ExEntryTest : VimTestCase() {
// assertExText("set incsearch") // assertExText("set incsearch")
typeExInput(":<S-Up>") typeExInput(":<S-Up>")
assertExText("set digraph")
typeText("<Up>")
assertExText("set incsearch") assertExText("set incsearch")
typeText("<Up>") typeText("<Up>")
assertExText("digraph") assertExText("digraph")
typeText("<Up>")
assertExText("set digraph")
deactivateExEntry() deactivateExEntry()
typeExInput(":<PageUp>") typeExInput(":<PageUp>")
assertExText("set incsearch")
typeText("<PageUp>")
assertExText("digraph") assertExText("digraph")
typeText("<PageUp>") typeText("<PageUp>")
assertExText("set digraph") assertExText("set digraph")
typeText("<PageUp>")
assertExText("set incsearch")
} }
@TestWithoutNeovim(SkipNeovimReason.CMD) @TestWithoutNeovim(SkipNeovimReason.CMD)
@ -325,20 +325,20 @@ class ExEntryTest : VimTestCase() {
deactivateExEntry() deactivateExEntry()
typeExInput(":set<S-Up>") typeExInput(":set<S-Up>")
assertExText("set digraph")
typeText("<S-Up>")
assertExText("set incsearch") assertExText("set incsearch")
typeText("<S-Up>") typeText("<S-Up>")
assertExText("digraph") assertExText("digraph")
typeText("<S-Up>")
assertExText("set digraph")
deactivateExEntry() deactivateExEntry()
typeExInput(":set<PageUp>") typeExInput(":set<PageUp>")
assertExText("set incsearch")
typeText("<PageUp>")
assertExText("digraph") assertExText("digraph")
typeText("<PageUp>") typeText("<PageUp>")
assertExText("set digraph") assertExText("set digraph")
typeText("<PageUp>")
assertExText("set incsearch")
} }
@Test @Test
@ -357,20 +357,20 @@ class ExEntryTest : VimTestCase() {
deactivateExEntry() deactivateExEntry()
typeExInput("/<S-Up>") typeExInput("/<S-Up>")
assertExText("something cool")
typeText("<S-Up>")
assertExText("so cool") assertExText("so cool")
typeText("<S-Up>") typeText("<S-Up>")
assertExText("not cool") assertExText("not cool")
typeText("<S-Up>")
assertExText("something cool")
deactivateExEntry() deactivateExEntry()
typeExInput("/<PageUp>") typeExInput("/<PageUp>")
assertExText("so cool")
typeText("<PageUp>")
assertExText("not cool") assertExText("not cool")
typeText("<PageUp>") typeText("<PageUp>")
assertExText("something cool") assertExText("something cool")
typeText("<PageUp>")
assertExText("so cool")
} }
@VimBehaviorDiffers(description = "Vim reorders history even when cancelling entry") @VimBehaviorDiffers(description = "Vim reorders history even when cancelling entry")
@ -394,20 +394,20 @@ class ExEntryTest : VimTestCase() {
// assertEquals("set incsearch", exEntryPanel.text) // assertEquals("set incsearch", exEntryPanel.text)
typeExInput("/so<S-Up>") typeExInput("/so<S-Up>")
assertExText("something cool")
typeText("<S-Up>")
assertExText("so cool") assertExText("so cool")
typeText("<S-Up>") typeText("<S-Up>")
assertExText("not cool") assertExText("not cool")
typeText("<S-Up>")
assertExText("something cool")
deactivateExEntry() deactivateExEntry()
typeExInput("/so<PageUp>") typeExInput("/so<PageUp>")
assertExText("so cool")
typeText("<PageUp>")
assertExText("not cool") assertExText("not cool")
typeText("<PageUp>") typeText("<PageUp>")
assertExText("something cool") assertExText("something cool")
typeText("<PageUp>")
assertExText("so cool")
} }
@Test @Test

View File

@ -26,6 +26,7 @@ import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue import kotlin.test.assertTrue
/** /**
@ -267,7 +268,7 @@ class MapCommandTest : VimTestCase() {
configureByText("${c}foo\n") configureByText("${c}foo\n")
typeText(commandToKeys("imap a b \\| c")) typeText(commandToKeys("imap a b \\| c"))
typeText(injector.parser.parseKeys("ia")) typeText(injector.parser.parseKeys("ia"))
assertState("b \\| cfoo\n") assertState("b | cfoo\n")
} }
// VIM-666 |:imap| // VIM-666 |:imap|
@ -277,7 +278,7 @@ class MapCommandTest : VimTestCase() {
configureByText("${c}foo\n") configureByText("${c}foo\n")
typeText(commandToKeys("imap a b \\| c |")) typeText(commandToKeys("imap a b \\| c |"))
typeText(injector.parser.parseKeys("ia")) typeText(injector.parser.parseKeys("ia"))
assertState("b \\| c foo\n") assertState("b | c foo\n")
} }
// VIM-670 |:map| // VIM-670 |:map|
@ -754,4 +755,23 @@ class MapCommandTest : VimTestCase() {
assertTrue(KeyHandler.getInstance().keyStack.isEmpty()) assertTrue(KeyHandler.getInstance().keyStack.isEmpty())
} }
@TestFor(issues = ["VIM-3601"])
@Test
fun `mapping to something with bars`() {
configureByText(
"""
Lorem Ipsum
Lorem ipsum dolor sit amet,
${c}consectetur adipiscing elit
Sed in orci mauris.
Cras id tellus in ex imperdiet egestas.
""".trimIndent()
)
typeText(commandToKeys("map k :echo 4<CR> \\| :echo 42<CR>"))
assertNull(injector.outputPanel.getCurrentOutputPanel())
typeText("k")
assertEquals("4\n42", injector.outputPanel.getCurrentOutputPanel()!!.text)
}
} }

View File

@ -32,7 +32,7 @@ class PrintCommandTest : VimTestCase() {
// We should be waiting for a keypress now, such as <Enter> or <Esc> to close the output panel. But that's handled // We should be waiting for a keypress now, such as <Enter> or <Esc> to close the output panel. But that's handled
// by a separate key event loop which doesn't operate in tests. // by a separate key event loop which doesn't operate in tests.
// Simulate closing the output panel in the same way as if we'd entered the right key // Simulate closing the output panel in the same way as if we'd entered the right key
ExOutputModel.getInstance(fixture.editor).close() injector.outputPanel.getCurrentOutputPanel()?.close()
typeText(commandToKeys("p")) typeText(commandToKeys("p"))
assertExOutput(" Lorem Ipsum") assertExOutput(" Lorem Ipsum")
} }

View File

@ -660,7 +660,7 @@ abstract class VimTestCase {
} }
fun assertExOutput(expected: String, clear: Boolean = true) { fun assertExOutput(expected: String, clear: Boolean = true) {
val actual = ExOutputModel.getInstance(fixture.editor).text val actual = injector.outputPanel.getCurrentOutputPanel()?.text
assertNotNull(actual, "No Ex output") assertNotNull(actual, "No Ex output")
assertEquals(expected, actual) assertEquals(expected, actual)
NeovimTesting.typeCommand("<esc>", testInfo, fixture.editor) NeovimTesting.typeCommand("<esc>", testInfo, fixture.editor)

View File

@ -16,6 +16,7 @@ import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimJavaTestCase import org.jetbrains.plugins.ideavim.VimJavaTestCase
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class ChangeActionJavaTest : VimJavaTestCase() { class ChangeActionJavaTest : VimJavaTestCase() {
// VIM-511 |.| // VIM-511 |.|
@ -120,6 +121,28 @@ and some text after""",
) )
} }
// VIM-566
@TestWithoutNeovim(SkipNeovimReason.FOLDING)
@Test
fun testInsertAfterToggleFold() {
configureByJavaText(
"""
$c/**
* I should be fold
* a little more text
* and final fold
*/
and some text after
""".trimIndent(),
)
CodeFoldingManager.getInstance(fixture.project).updateFoldRegions(fixture.editor)
assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, true)
typeText(injector.parser.parseKeys("za"))
assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, false)
typeText(injector.parser.parseKeys("za"))
assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, true)
}
// VIM-287 |zc| |o| // VIM-287 |zc| |o|
@TestWithoutNeovim(SkipNeovimReason.FOLDING) @TestWithoutNeovim(SkipNeovimReason.FOLDING)
@Test @Test

View File

@ -15,7 +15,7 @@ val javaVersion: String by project
val remoteRobotVersion: String by project val remoteRobotVersion: String by project
dependencies { dependencies {
testFixturesImplementation("org.junit.jupiter:junit-jupiter:5.10.3") testFixturesImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
testFixturesImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion") testFixturesImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
testFixturesImplementation(testFixtures(project(":"))) // The root project testFixturesImplementation(testFixtures(project(":"))) // The root project

View File

@ -55,8 +55,15 @@ class KeyHandler {
private val keyConsumers: List<KeyConsumer> = listOf(ModalInputConsumer(), MappingProcessor, CommandCountConsumer(), DeleteCommandConsumer(), EditorResetConsumer(), CharArgumentConsumer(), RegisterConsumer(), DigraphConsumer(), CommandConsumer(), SelectRegisterConsumer(), ModeInputConsumer()) private val keyConsumers: List<KeyConsumer> = listOf(ModalInputConsumer(), MappingProcessor, CommandCountConsumer(), DeleteCommandConsumer(), EditorResetConsumer(), CharArgumentConsumer(), RegisterConsumer(), DigraphConsumer(), CommandConsumer(), SelectRegisterConsumer(), ModeInputConsumer())
private var handleKeyRecursionCount = 0 private var handleKeyRecursionCount = 0
var keyHandlerState: KeyHandlerState = KeyHandlerState() // KeyHandlerState requires injector.keyGroup to be initialized and that's why we don't create it immediately and have this here
private set // TODO figure out a better solution
private val defaultKeyHandlerState by lazy { KeyHandlerState() }
private var mutableKeyHandlerState: KeyHandlerState? = null
var keyHandlerState: KeyHandlerState
get() = mutableKeyHandlerState ?: defaultKeyHandlerState
private set(value) {
mutableKeyHandlerState = value
}
val keyStack: KeyStack = KeyStack() val keyStack: KeyStack = KeyStack()
val modalEntryKeys: MutableList<KeyStroke> = ArrayList() val modalEntryKeys: MutableList<KeyStroke> = ArrayList()
@ -283,6 +290,7 @@ class KeyHandler {
// TODO we should have a single reset method // TODO we should have a single reset method
fun reset(keyState: KeyHandlerState, mode: Mode) { fun reset(keyState: KeyHandlerState, mode: Mode) {
logger.trace { "Reset is executed" } logger.trace { "Reset is executed" }
injector.commandLine.getActiveCommandLine()?.clearCurrentAction()
keyHandlerState.partialReset(mode) keyHandlerState.partialReset(mode)
keyState.commandBuilder.resetAll(getKeyRoot(mode.toMappingMode())) keyState.commandBuilder.resetAll(getKeyRoot(mode.toMappingMode()))
} }

View File

@ -0,0 +1,46 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Graphemes
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<DEL>"], modes = [Mode.CMD_LINE])
class DeleteNextCharAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val caretOffset = commandLine.caret.offset
val oldText = commandLine.actualText
if (oldText.isEmpty()) {
commandLine.close(refocusOwningEditor = true, resetCaret = false)
return true
}
val newText = if (caretOffset == oldText.length) {
val preEndOffset = Graphemes.prev(oldText, oldText.length) ?: return true
oldText.substring(0, preEndOffset)
} else {
val nextOffset = Graphemes.next(oldText, caretOffset) ?: return true
oldText.substring(0, caretOffset) + oldText.substring(nextOffset)
}
commandLine.setText(newText)
return true
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-W>"], modes = [Mode.CMD_LINE])
class DeletePrevWordAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val caretOffset = commandLine.caret.offset
if (caretOffset == 0) return true
val oldText = commandLine.actualText
val motion = injector.motion.findOffsetOfNextWord(oldText, oldText.length, commandLine.caret.offset, -1, true, editor)
when (motion) {
is Motion.AbsoluteOffset -> {
val newText = oldText.substring(0, motion.offset) + oldText.substring(caretOffset)
commandLine.caret.offset = motion.offset
commandLine.setText(newText)
}
else -> {}
}
return true
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Graphemes
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<BS>", "<C-H>"], modes = [Mode.CMD_LINE])
class DeletePreviousCharAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val oldText = commandLine.actualText
if (oldText.isEmpty()) {
commandLine.close(refocusOwningEditor = true, resetCaret = false)
return true
}
val caretOffset = commandLine.caret.offset
if (caretOffset == 0) return true
val prevOffset = Graphemes.prev(oldText, caretOffset) ?: 0
commandLine.caret.offset = prevOffset
val newText = oldText.substring(0, prevOffset) + oldText.substring(caretOffset)
commandLine.setText(newText)
return true
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-U>"], modes = [Mode.CMD_LINE])
class DeleteToCaretAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val oldText = commandLine.actualText
val newText = oldText.substring(commandLine.caret.offset)
commandLine.setText(newText)
commandLine.caret.offset = 0
return true
}
}

View File

@ -20,7 +20,7 @@ import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
@CommandOrMotion(keys = [":"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING]) @CommandOrMotion(keys = [":"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
internal class ExEntryAction : VimActionHandler.SingleExecution() { class ExEntryAction : VimActionHandler.SingleExecution() {
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_START_EX) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_START_EX)
override val type: Command.Type = Command.Type.OTHER_READONLY override val type: Command.Type = Command.Type.OTHER_READONLY

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<S-Down>", "<C-N>", "<PageDown>"], modes = [Mode.CMD_LINE])
class HistoryDownAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.selectHistory(isUp = false, filter = false)
return true
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<Down>"], modes = [Mode.CMD_LINE])
class HistoryDownFilterAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.selectHistory(isUp = false, filter = true)
return true
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<S-Up>", "<C-P>", "<PageUp>"], modes = [Mode.CMD_LINE])
class HistoryUpAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.selectHistory(isUp = true, filter = false)
return true
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<Up>"], modes = [Mode.CMD_LINE])
class HistoryUpFilterAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.selectHistory(isUp = true, filter = true)
return true
}
}

View File

@ -12,11 +12,13 @@ import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.history.VimHistory
import java.util.* import java.util.*
@CommandOrMotion(keys = ["<Esc>", "<C-[>", "<C-C>"], modes = [Mode.CMD_LINE]) @CommandOrMotion(keys = ["<Esc>", "<C-[>", "<C-C>"], modes = [Mode.CMD_LINE])
@ -25,6 +27,9 @@ class LeaveCommandLineAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_READONLY override val type: Command.Type = Command.Type.OTHER_READONLY
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean { override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val argument = cmd.argument ?: return true
val historyType = VimHistory.Type.getTypeByLabel(argument.character.toString())
injector.historyGroup.addEntry(historyType, argument.string)
return true return true
} }
} }

View File

@ -0,0 +1,34 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Graphemes
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<Left>"], modes = [Mode.CMD_LINE])
class MoveCaretLeftAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val caret = commandLine.caret
val prevOffset = Graphemes.prev(commandLine.actualText, caret.offset) ?: return true
caret.offset = prevOffset
return true
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Graphemes
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<Right>"], modes = [Mode.CMD_LINE])
class MoveCaretRightAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val caret = commandLine.caret
val nextOffset = Graphemes.next(commandLine.actualText, caret.offset) ?: return true
caret.offset = nextOffset
return true
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-E>", "<End>"], modes = [Mode.CMD_LINE])
class MoveCaretToLineEnd : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.caret.offset = commandLine.actualText.length
return true
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-B>", "<Home>"], modes = [Mode.CMD_LINE])
class MoveCaretToLineStart : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.caret.offset = 0
return true
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-Right>", "<S-Right>"], modes = [Mode.CMD_LINE])
class MoveToNextWordAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val text = commandLine.actualText
val motion = injector.motion.findOffsetOfNextWord(text, text.length, commandLine.caret.offset, 1, true, editor)
when (motion) {
is Motion.AbsoluteOffset -> {
commandLine.caret.offset = motion.offset
}
else -> {}
}
return true
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<C-Left>", "<S-Left>"], modes = [Mode.CMD_LINE])
class MoveToPreviousWordAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
val text = commandLine.actualText
val motion = injector.motion.findOffsetOfNextWord(text, text.length, commandLine.caret.offset, -1, true, editor)
when (motion) {
is Motion.AbsoluteOffset -> {
commandLine.caret.offset = motion.offset
}
else -> {}
}
return true
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.action.ex
import com.intellij.vim.annotations.CommandOrMotion
import com.intellij.vim.annotations.Mode
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
@CommandOrMotion(keys = ["<Insert>"], modes = [Mode.CMD_LINE])
class ToggleInsertModeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val commandLine = injector.commandLine.getActiveCommandLine() ?: return false
commandLine.toggleReplaceMode()
return true
}
}

View File

@ -33,6 +33,22 @@ class VimCollapseAllRegions : VimActionHandler.SingleExecution() {
} }
} }
@CommandOrMotion(keys = ["za"], modes = [Mode.NORMAL, Mode.VISUAL])
class VimExpandCollapseToggleRegion : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_READONLY
override fun execute(
editor: VimEditor,
context: ExecutionContext,
cmd: Command,
operatorArguments: OperatorArguments,
): Boolean {
injector.actionExecutor.executeAction(editor, name = injector.actionExecutor.ACTION_EXPAND_COLLAPSE_TOGGLE, context = context)
return true
}
}
@CommandOrMotion(keys = ["zc"], modes = [Mode.NORMAL, Mode.VISUAL]) @CommandOrMotion(keys = ["zc"], modes = [Mode.NORMAL, Mode.VISUAL])
class VimCollapseRegion : VimActionHandler.SingleExecution() { class VimCollapseRegion : VimActionHandler.SingleExecution() {

View File

@ -20,6 +20,7 @@ interface VimActionExecutor {
val ACTION_EXPAND_ALL_REGIONS: String val ACTION_EXPAND_ALL_REGIONS: String
val ACTION_EXPAND_REGION: String val ACTION_EXPAND_REGION: String
val ACTION_EXPAND_REGION_RECURSIVELY: String val ACTION_EXPAND_REGION_RECURSIVELY: String
val ACTION_EXPAND_COLLAPSE_TOGGLE: String
/** /**
* Execute an action * Execute an action

View File

@ -8,8 +8,11 @@
package com.maddyhome.idea.vim.api package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.state.mode.returnTo import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.history.HistoryEntry
import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.state.mode.returnTo
import javax.swing.KeyStroke import javax.swing.KeyStroke
import kotlin.math.min import kotlin.math.min
@ -35,6 +38,11 @@ interface VimCommandLine {
val label: String val label: String
val isReplaceMode: Boolean val isReplaceMode: Boolean
var histIndex: Int
var lastEntry: String
val historyType: VimHistory.Type
get() = VimHistory.Type.getTypeByLabel(label)
fun toggleReplaceMode() fun toggleReplaceMode()
/** /**
@ -54,7 +62,7 @@ interface VimCommandLine {
val visibleText: String val visibleText: String
var promptCharacterOffset: Int? var promptCharacterOffset: Int?
fun setText(string: String) fun setText(string: String, updateLastEntry: Boolean = true)
fun insertText(offset: Int, string: String) { fun insertText(offset: Int, string: String) {
val newText = if (isReplaceMode) { val newText = if (isReplaceMode) {
val endOffset = min(offset + string.length, actualText.length) val endOffset = min(offset + string.length, actualText.length)
@ -87,6 +95,8 @@ interface VimCommandLine {
caret.offset = offset caret.offset = offset
} }
fun clearPromptCharacter() { fun clearPromptCharacter() {
if (promptCharacterOffset == null) return
setText(actualText) setText(actualText)
caret.offset = min(caret.offset, visibleText.length) caret.offset = min(caret.offset, visibleText.length)
promptCharacterOffset = null promptCharacterOffset = null
@ -102,9 +112,57 @@ interface VimCommandLine {
// If 'cpoptions' contains 'x', then Escape should execute the command line. This is the default for Vi but not Vim. // If 'cpoptions' contains 'x', then Escape should execute the command line. This is the default for Vi but not Vim.
// IdeaVim does not (currently?) support 'cpoptions', so sticks with Vim's default behaviour. Escape cancels. // IdeaVim does not (currently?) support 'cpoptions', so sticks with Vim's default behaviour. Escape cancels.
editor.mode = editor.mode.returnTo() editor.mode = editor.mode.returnTo()
KeyHandler.getInstance().keyHandlerState.leaveCommandLine()
deactivate(refocusOwningEditor, resetCaret) deactivate(refocusOwningEditor, resetCaret)
} }
// FIXME I don't want it to conflict with Swings `requestFocus` and can suggest a better name // FIXME I don't want it to conflict with Swings `requestFocus` and can suggest a better name
fun focus() fun focus()
fun selectHistory(isUp: Boolean, filter: Boolean) {
val history = injector.historyGroup.getEntries(historyType, 0, 0)
val dir = if (isUp) -1 else 1
if (histIndex + dir < 0 || histIndex + dir > history.size) {
injector.messages.indicateError()
return
}
if (filter) {
var i: Int = histIndex + dir
while (i >= 0 && i <= history.size) {
var txt: String
if (i == history.size) {
txt = lastEntry
} else {
val entry: HistoryEntry = history[i]
txt = entry.entry
}
if (txt.startsWith(lastEntry)) {
setText(txt, updateLastEntry = false)
caret.offset = txt.length
histIndex = i
return
}
i += dir
}
injector.messages.indicateError()
} else {
histIndex += dir
val txt: String
if (histIndex == history.size) {
txt = lastEntry
} else {
val entry: HistoryEntry = history[histIndex]
txt = entry.entry
}
setText(txt, updateLastEntry = false)
caret.offset = txt.length
}
}
} }

View File

@ -11,6 +11,8 @@ package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
interface VimCommandLineService { interface VimCommandLineService {
fun isCommandLineSupported(editor: VimEditor): Boolean
fun getActiveCommandLine(): VimCommandLine? fun getActiveCommandLine(): VimCommandLine?
fun readInputAndProcess(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?, processing: (String) -> Unit) fun readInputAndProcess(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?, processing: (String) -> Unit)

View File

@ -15,10 +15,14 @@ import com.maddyhome.idea.vim.state.mode.ReturnableFromCmd
import com.maddyhome.idea.vim.state.mode.inVisualMode import com.maddyhome.idea.vim.state.mode.inVisualMode
abstract class VimCommandLineServiceBase : VimCommandLineService { abstract class VimCommandLineServiceBase : VimCommandLineService {
override fun isCommandLineSupported(editor: VimEditor): Boolean {
return !editor.isOneLineMode()
}
abstract fun createPanel(editor: VimEditor, context: ExecutionContext, label: String, initText: String): VimCommandLine abstract fun createPanel(editor: VimEditor, context: ExecutionContext, label: String, initText: String): VimCommandLine
private fun createCommandLinePrompt(editor: VimEditor, context: ExecutionContext, removeSelections: Boolean, label: String, initialText: String): VimCommandLine { private fun createCommandLinePrompt(editor: VimEditor, context: ExecutionContext, removeSelections: Boolean, label: String, initialText: String): VimCommandLine {
if (editor.isOneLineMode()) throw ExException("Command line is not allowed in one line editors") if (!isCommandLineSupported(editor)) throw ExException("Command line is not allowed in one line editors")
val currentMode = editor.mode val currentMode = editor.mode
check(currentMode is ReturnableFromCmd) { check(currentMode is ReturnableFromCmd) {

View File

@ -11,12 +11,10 @@ package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.LiveRange import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.ReturnTo import com.maddyhome.idea.vim.state.mode.ReturnTo
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.returnTo import com.maddyhome.idea.vim.state.mode.returnTo
import org.jetbrains.annotations.ApiStatus.Internal
/** /**
* Every line in [VimEditor] ends with a new line TODO <- this is probably not true already * Every line in [VimEditor] ends with a new line TODO <- this is probably not true already

View File

@ -73,6 +73,19 @@ interface VimMotionGroup {
*/ */
fun findOffsetOfNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Motion fun findOffsetOfNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Motion
/**
* Find the offset of the start of the next/previous word/WORD in some text outside the editor (e.g., command line)
*
* @param text The text to search in
* @param textLength The text length (there is no guarantee that calling [text.length] will be a constant time operation)
* @param searchFrom The buffer offset to start searching from
* @param count The number of words to skip
* @param bigWord If true then find WORD, if false then find word
* @param editor The editor that provides local to buffer option values
* @return a [Motion] representing the offset to move to, or [Motion.Error] if not found
*/
fun findOffsetOfNextWord(text: CharSequence, textLength: Int = text.length, searchFrom: Int, count: Int, bigWord: Boolean, editor: VimEditor): Motion
// Next/previous matching character - f/F and t/T motions // Next/previous matching character - f/F and t/T motions
val lastFTCmd: TillCharacterMotionType val lastFTCmd: TillCharacterMotionType
val lastFTChar: Char val lastFTChar: Char

View File

@ -96,11 +96,14 @@ abstract class VimMotionGroupBase : VimMotionGroup {
* @return position * @return position
*/ */
override fun findOffsetOfNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Motion { override fun findOffsetOfNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Motion {
val size = editor.fileSize().toInt() return findOffsetOfNextWord(editor.text(), editor.fileSize().toInt(), searchFrom, count, bigWord, editor)
if ((searchFrom == 0 && count < 0) || (searchFrom >= size - 1 && count > 0)) { }
override fun findOffsetOfNextWord(text: CharSequence, textLength: Int, searchFrom: Int, count: Int, bigWord: Boolean, editor: VimEditor): Motion {
if ((searchFrom == 0 && count < 0) || (searchFrom >= textLength - 1 && count > 0)) {
return Motion.Error return Motion.Error
} }
return (injector.searchHelper.findNextWord(editor, searchFrom, count, bigWord, false)).toMotionOrError() return (injector.searchHelper.findNextWord(text, textLength, editor, searchFrom, count, bigWord, false)).toMotionOrError()
} }
override fun getHorizontalMotion( override fun getHorizontalMotion(

View File

@ -8,4 +8,110 @@
package com.maddyhome.idea.vim.api package com.maddyhome.idea.vim.api
abstract class VimScriptExecutorBase : VimscriptExecutor import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.FinishException
import com.maddyhome.idea.vim.history.HistoryConstants
import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.commands.Command
import com.maddyhome.idea.vim.vimscript.model.commands.RepeatCommand
import java.io.File
import java.io.IOException
abstract class VimScriptExecutorBase : VimscriptExecutor {
private val logger = vimLogger<VimScriptExecutorBase>()
override var executingVimscript = false
override var executingIdeaVimRcConfiguration = false
@Throws(ExException::class)
override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
try {
injector.vimscriptExecutor.executingVimscript = true
var finalResult: ExecutionResult = ExecutionResult.Success
val myScript = injector.vimscriptParser.parse(script)
myScript.units.forEach { it.vimContext = vimContext ?: myScript }
for (unit in myScript.units) {
try {
val result = unit.execute(editor, context)
if (result is ExecutionResult.Error) {
finalResult = ExecutionResult.Error
if (indicateErrors) {
injector.messages.indicateError()
}
}
} catch (e: ExException) {
if (e is FinishException) {
break
}
finalResult = ExecutionResult.Error
if (indicateErrors) {
injector.messages.showStatusBarMessage(editor, e.message)
injector.messages.indicateError()
} else {
logger.warn("Failed while executing $unit. " + e.message)
}
} catch (e: NotImplementedError) {
if (indicateErrors) {
injector.messages.showStatusBarMessage(editor, "Not implemented yet :(")
injector.messages.indicateError()
}
} catch (e: Exception) {
logger.warn(e.toString())
if (injector.application.isUnitTest()) {
throw e
}
}
}
if (!skipHistory) {
injector.historyGroup.addEntry(VimHistory.Type.Command, script)
if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
injector.registerGroup.storeTextSpecial(LAST_COMMAND_REGISTER, script)
}
}
return finalResult
} finally {
injector.vimscriptExecutor.executingVimscript = false
// Initialize any extensions that were enabled during execution of this vimscript
// See the doc of this function for details
enableDelayedExtensions()
}
}
protected abstract fun enableDelayedExtensions()
override fun executeFile(file: File, editor: VimEditor, fileIsIdeaVimRcConfig: Boolean, indicateErrors: Boolean) {
val context = injector.executionContextManager.getEditorExecutionContext(editor)
try {
if (fileIsIdeaVimRcConfig) {
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
}
ensureFileIsSaved(file)
execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
} catch (ignored: IOException) {
logger.error(ignored.toString())
} finally {
if (fileIsIdeaVimRcConfig) {
injector.vimrcFileState.saveFileState(file.absolutePath)
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
}
}
}
protected abstract fun ensureFileIsSaved(file: File)
@Throws(ExException::class)
override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
val reg = injector.registerGroup.getRegister(':') ?: return false
val text = reg.text ?: return false
execute(text, editor, context, skipHistory = false, indicateErrors = true, CommandLineVimLContext)
return true
}
}

View File

@ -109,6 +109,20 @@ fun findNextCamelEnd(chars: CharSequence, startIndex: Int, count: Int): Int?
*/ */
fun findNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int fun findNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int
/**
* Find the next word in some text outside the editor (e.g., command line), from the given starting point
*
* @param text The text to search in
* @param textLength The text length
* @param editor Required because word boundaries depend on local-to-buffer options
* @param searchFrom The offset in the document to search from
* @param count Return an offset to the [count] word from the starting position. Will search backwards if negative
* @param bigWord Use WORD instead of word boundaries
* @param spaceWords Include whitespace as part of a word, e.g. the difference between `iw` and `aw` motions
* @return The offset of the [count] next word, or `0` or the offset of the end of file if not found
*/
fun findNextWord(text: CharSequence, textLength: Int, editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int
/** /**
* Find the end offset of the next word in the editor's document, from the given starting point * Find the end offset of the next word in the editor's document, from the given starting point
* *
@ -122,6 +136,20 @@ fun findNextCamelEnd(chars: CharSequence, startIndex: Int, count: Int): Int?
*/ */
fun findNextWordEnd(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int fun findNextWordEnd(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int
/**
* Find the end offset in some text outside the editor (e.g., command line), from the given starting point
*
* @param text The text to search in
* @param textLength The text length
* @param editor Required because word boundaries depend on local-to-buffer options
* @param searchFrom The offset in the document to search from
* @param count Return an offset to the [count] word from the starting position. Will search backwards if negative
* @param bigWord Use WORD instead of word boundaries
* @param spaceWords Include whitespace as part of a word, e.g. the difference between `iw` and `aw` motions
* @return The offset of the [count] next word, or `0` or the offset of the end of file if not found
*/
fun findNextWordEnd(text: CharSequence, textLength: Int, editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean, spaceWords: Boolean): Int
/** /**
* Find text matching the given pattern. * Find text matching the given pattern.
* *

View File

@ -100,7 +100,19 @@ abstract class VimSearchHelperBase : VimSearchHelper {
bigWord: Boolean, bigWord: Boolean,
spaceWords: Boolean, spaceWords: Boolean,
): Int { ): Int {
return doFindNext(editor, searchFrom, count, bigWord, spaceWords, ::findNextWordOne) return findNextWord(editor.text(), editor.fileSize().toInt(), editor, searchFrom, count, bigWord, spaceWords)
}
override fun findNextWord(
text: CharSequence,
textLength: Int,
editor: VimEditor,
searchFrom: Int,
count: Int,
bigWord: Boolean,
spaceWords: Boolean,
): Int {
return doFindNext(text, textLength, editor, searchFrom, count, bigWord, spaceWords, ::findNextWordOne)
} }
override fun findNextWordEnd( override fun findNextWordEnd(
@ -110,7 +122,19 @@ abstract class VimSearchHelperBase : VimSearchHelper {
bigWord: Boolean, bigWord: Boolean,
spaceWords: Boolean, spaceWords: Boolean,
): Int { ): Int {
return doFindNext(editor, searchFrom, count, bigWord, spaceWords, ::findNextWordEndOne) return findNextWordEnd(editor.text(), editor.fileSize().toInt(), editor, searchFrom, count, bigWord, spaceWords)
}
override fun findNextWordEnd(
text: CharSequence,
textLength: Int,
editor: VimEditor,
searchFrom: Int,
count: Int,
bigWord: Boolean,
spaceWords: Boolean,
): Int {
return doFindNext(text, textLength, editor, searchFrom, count, bigWord, spaceWords, ::findNextWordEndOne)
} }
override fun findPattern( override fun findPattern(
@ -260,21 +284,22 @@ abstract class VimSearchHelperBase : VimSearchHelper {
} }
private fun doFindNext( private fun doFindNext(
text: CharSequence,
textLength: Int,
editor: VimEditor, editor: VimEditor,
searchFrom: Int, searchFrom: Int,
countDirection: Int, countDirection: Int,
bigWord: Boolean, bigWord: Boolean,
spaceWords: Boolean, spaceWords: Boolean,
action: (VimEditor, pos: Int, size: Int, step: Int, bigWord: Boolean, spaceWords: Boolean) -> Int, action: (text: CharSequence, editor: VimEditor, pos: Int, size: Int, step: Int, bigWord: Boolean, spaceWords: Boolean) -> Int,
): Int { ): Int {
var count = countDirection var count = countDirection
val step = if (count >= 0) 1 else -1 val step = if (count >= 0) 1 else -1
count = abs(count) count = abs(count)
val size = editor.fileSize().toInt() // editor.text() returns CharSequence, which only supports Int indexing
var pos = searchFrom var pos = searchFrom
for (i in 0 until count) { for (i in 0 until count) {
pos = action(editor, pos, size, step, bigWord, spaceWords) pos = action(text, editor, pos, textLength, step, bigWord, spaceWords)
if (pos == searchFrom || pos == 0 || pos == size - 1) { if (pos == searchFrom || pos == 0 || pos == textLength - 1) {
break break
} }
} }
@ -282,6 +307,7 @@ abstract class VimSearchHelperBase : VimSearchHelper {
} }
private fun findNextWordOne( private fun findNextWordOne(
chars: CharSequence,
editor: VimEditor, editor: VimEditor,
pos: Int, pos: Int,
size: Int, size: Int,
@ -289,7 +315,6 @@ abstract class VimSearchHelperBase : VimSearchHelper {
bigWord: Boolean, bigWord: Boolean,
spaceWords: Boolean, spaceWords: Boolean,
): Int { ): Int {
val chars = editor.text()
var found = false var found = false
var _pos = if (pos < size) pos else min(size, (chars.length - 1)) var _pos = if (pos < size) pos else min(size, (chars.length - 1))
// For back searches, skip any current whitespace so we start at the end of a word // For back searches, skip any current whitespace so we start at the end of a word
@ -341,6 +366,7 @@ abstract class VimSearchHelperBase : VimSearchHelper {
} }
private fun findNextWordEndOne( private fun findNextWordEndOne(
chars: CharSequence,
editor: VimEditor, editor: VimEditor,
pos: Int, pos: Int,
size: Int, size: Int,
@ -348,7 +374,6 @@ abstract class VimSearchHelperBase : VimSearchHelper {
bigWord: Boolean, bigWord: Boolean,
spaceWords: Boolean, spaceWords: Boolean,
): Int { ): Int {
val chars = editor.text()
var pos = pos var pos = pos
var found = false var found = false
// For forward searches, skip any current whitespace so we start at the start of a word // For forward searches, skip any current whitespace so we start at the start of a word

View File

@ -38,6 +38,9 @@ class MappingState: Cloneable {
val keys: Iterable<KeyStroke> val keys: Iterable<KeyStroke>
get() = keyList get() = keyList
val hasKeys
get() = keyList.isNotEmpty()
private var timer = VimTimer(injector.globalOptions().timeoutlen) private var timer = VimTimer(injector.globalOptions().timeoutlen)
private var keyList = mutableListOf<KeyStroke>() private var keyList = mutableListOf<KeyStroke>()

View File

@ -10,4 +10,5 @@ package com.maddyhome.idea.vim.common
interface LiveRange { interface LiveRange {
val startOffset: Int val startOffset: Int
val endOffset: Int
} }

View File

@ -8,6 +8,7 @@
package com.maddyhome.idea.vim.history package com.maddyhome.idea.vim.history
@Deprecated("Please use VimHistory.Type")
object HistoryConstants { object HistoryConstants {
@JvmField @JvmField
val SEARCH: String = "search" val SEARCH: String = "search"

View File

@ -9,6 +9,30 @@
package com.maddyhome.idea.vim.history package com.maddyhome.idea.vim.history
interface VimHistory { interface VimHistory {
@Deprecated("Please use fun addEntry(type: Type, text: String)")
fun addEntry(key: String, text: String) fun addEntry(key: String, text: String)
@Deprecated("Please use fun getEntries(type: Type, text: String)")
fun getEntries(key: String, first: Int, last: Int): List<HistoryEntry> fun getEntries(key: String, first: Int, last: Int): List<HistoryEntry>
fun addEntry(type: Type, text: String)
fun getEntries(type: Type, first: Int, last: Int): List<HistoryEntry>
sealed class Type {
data object Search : Type()
data object Command : Type()
data object Expression : Type()
data object Input : Type()
data class Custom(val id: String) : Type()
companion object {
fun getTypeByLabel(label: String): Type {
return when (label) {
":" -> Command
"/", "?" -> Search
"=" -> Expression
else -> Custom(label)
}
}
}
}
} }

View File

@ -13,19 +13,30 @@ import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
open class VimHistoryBase : VimHistory { open class VimHistoryBase : VimHistory {
val histories: MutableMap<String, HistoryBlock> = HashMap() val histories: MutableMap<VimHistory.Type, HistoryBlock> = mutableMapOf()
@Deprecated("Please use fun addEntry(type: Type, text: String)")
override fun addEntry(key: String, text: String) { override fun addEntry(key: String, text: String) {
logger.debug { "Add entry '$text' to $key" } val type = getTypeForString(key)
addEntry(type, text)
val block = blocks(key) }
override fun addEntry(type: VimHistory.Type, text: String) {
val block = blocks(type)
block.addEntry(text) block.addEntry(text)
} }
@Deprecated("Please use fun getEntries(type: Type, text: String)")
override fun getEntries(key: String, first: Int, last: Int): List<HistoryEntry> { override fun getEntries(key: String, first: Int, last: Int): List<HistoryEntry> {
val type = getTypeForString(key)
return getEntries(type, first, last)
}
override fun getEntries(type: VimHistory.Type, first: Int, last: Int): List<HistoryEntry> {
var myFirst = first var myFirst = first
var myLast = last var myLast = last
val block = blocks(key) val block = blocks(type)
val entries = block.getEntries() val entries = block.getEntries()
val res = ArrayList<HistoryEntry>() val res = ArrayList<HistoryEntry>()
@ -59,8 +70,18 @@ open class VimHistoryBase : VimHistory {
return res return res
} }
private fun blocks(key: String): HistoryBlock { private fun blocks(type: VimHistory.Type): HistoryBlock {
return histories.getOrPut(key) { HistoryBlock() } return histories.getOrPut(type) { HistoryBlock() }
}
protected fun getTypeForString(key: String): VimHistory.Type {
return when (key) {
HistoryConstants.SEARCH -> VimHistory.Type.Search
HistoryConstants.COMMAND -> VimHistory.Type.Command
HistoryConstants.EXPRESSION -> VimHistory.Type.Expression
HistoryConstants.INPUT -> VimHistory.Type.Input
else -> VimHistory.Type.Custom(key)
}
} }
companion object { companion object {

View File

@ -160,7 +160,9 @@ data class MapCommand(val range: Range, val argument: String, val cmd: String) :
val specialArguments = HashSet<SpecialArgument>() val specialArguments = HashSet<SpecialArgument>()
val toKeysBuilder = StringBuilder() val toKeysBuilder = StringBuilder()
var fromKeys: List<KeyStroke>? = null var fromKeys: List<KeyStroke>? = null
input.split(" ").dropLastWhile { it.isEmpty() }.forEach { part ->
val preprocessedInput = processBars(input)
preprocessedInput.split(" ").dropLastWhile { it.isEmpty() }.forEach { part ->
if (fromKeys != null) { if (fromKeys != null) {
toKeysBuilder.append(" ") toKeysBuilder.append(" ")
toKeysBuilder.append(part) toKeysBuilder.append(part)
@ -173,8 +175,8 @@ data class MapCommand(val range: Range, val argument: String, val cmd: String) :
} }
} }
} }
for (i in input.length - 1 downTo 0) { for (i in preprocessedInput.length - 1 downTo 0) {
val c = input[i] val c = preprocessedInput[i]
if (c == ' ') { if (c == ' ') {
toKeysBuilder.append(c) toKeysBuilder.append(c)
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
{
"&": "com.maddyhome.idea.vim.vimscript.model.commands.SubstituteCommand",
"<": "com.maddyhome.idea.vim.vimscript.model.commands.ShiftLeftCommand",
">": "com.maddyhome.idea.vim.vimscript.model.commands.ShiftRightCommand",
"@": "com.maddyhome.idea.vim.vimscript.model.commands.RepeatCommand",
"N[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.PreviousFileCommand",
"P[rint]": "com.maddyhome.idea.vim.vimscript.model.commands.PrintCommand",
"Plug[in]": "com.maddyhome.idea.vim.vimscript.model.commands.PlugCommand",
"action": "com.maddyhome.idea.vim.vimscript.model.commands.ActionCommand",
"argu[ment]": "com.maddyhome.idea.vim.vimscript.model.commands.SelectFileCommand",
"as[cii]": "com.maddyhome.idea.vim.vimscript.model.commands.AsciiCommand",
"bd[elete]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCloseCommand",
"bn[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.NextFileCommand",
"bp[revious]": "com.maddyhome.idea.vim.vimscript.model.commands.PreviousFileCommand",
"bro[wse]": "com.maddyhome.idea.vim.vimscript.model.commands.EditFileCommand",
"cal[l]": "com.maddyhome.idea.vim.vimscript.model.commands.CallCommand",
"cle[arjumps]": "com.maddyhome.idea.vim.vimscript.model.commands.ClearJumpsCommand",
"clo[se]": "com.maddyhome.idea.vim.vimscript.model.commands.QuitCommand",
"cm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"cmapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"cno[remap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"co[py]": "com.maddyhome.idea.vim.vimscript.model.commands.CopyTextCommand",
"com[mand]": "com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand",
"comc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand",
"cu[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"d[elete]": "com.maddyhome.idea.vim.vimscript.model.commands.DeleteLinesCommand",
"delc[ommand]": "com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand",
"delf[unction]": "com.maddyhome.idea.vim.vimscript.model.commands.DelfunctionCommand",
"delm[arks]": "com.maddyhome.idea.vim.vimscript.model.commands.DeleteMarksCommand",
"dig[raphs]": "com.maddyhome.idea.vim.vimscript.model.commands.DigraphCommand",
"dis[play]": "com.maddyhome.idea.vim.vimscript.model.commands.RegistersCommand",
"e[dit]": "com.maddyhome.idea.vim.vimscript.model.commands.EditFileCommand",
"ec[ho]": "com.maddyhome.idea.vim.vimscript.model.commands.EchoCommand",
"exe[cute]": "com.maddyhome.idea.vim.vimscript.model.commands.ExecuteCommand",
"exi[t]": "com.maddyhome.idea.vim.vimscript.model.commands.WriteQuitCommand",
"f[ile]": "com.maddyhome.idea.vim.vimscript.model.commands.FileCommand",
"fin[d]": "com.maddyhome.idea.vim.vimscript.model.commands.FindFileCommand",
"fir[st]": "com.maddyhome.idea.vim.vimscript.model.commands.SelectFirstFileCommand",
"g[lobal]": "com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand",
"go[to]": "com.maddyhome.idea.vim.vimscript.model.commands.GotoCharacterCommand",
"hi[de]": "com.maddyhome.idea.vim.vimscript.model.commands.QuitCommand",
"his[tory]": "com.maddyhome.idea.vim.vimscript.model.commands.HistoryCommand",
"im[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"imapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"ino[remap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"iu[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"j[oin]": "com.maddyhome.idea.vim.vimscript.model.commands.JoinLinesCommand",
"ju[mps]": "com.maddyhome.idea.vim.vimscript.model.commands.JumpsCommand",
"k": "com.maddyhome.idea.vim.vimscript.model.commands.MarkCommand",
"la[st]": "com.maddyhome.idea.vim.vimscript.model.commands.SelectLastFileCommand",
"let": "com.maddyhome.idea.vim.vimscript.model.commands.LetCommand",
"lm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"lmapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"ln[oremap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"lockv[ar]": "com.maddyhome.idea.vim.vimscript.model.commands.LockVarCommand",
"lu[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"m[ove]": "com.maddyhome.idea.vim.vimscript.model.commands.MoveTextCommand",
"ma[rk]": "com.maddyhome.idea.vim.vimscript.model.commands.MarkCommand",
"map": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"mapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"marks": "com.maddyhome.idea.vim.vimscript.model.commands.MarksCommand",
"n[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.NextFileCommand",
"nm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"nmapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"nn[oremap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"no[map]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"no[remap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"noh[lsearch]": "com.maddyhome.idea.vim.vimscript.model.commands.NoHLSearchCommand",
"norm[al]": "com.maddyhome.idea.vim.vimscript.model.commands.NormalCommand",
"nun[map]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"om[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"omapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"on[ly]": "com.maddyhome.idea.vim.vimscript.model.commands.OnlyCommand",
"ono[remap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"ou[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"p[rint]": "com.maddyhome.idea.vim.vimscript.model.commands.PrintCommand",
"pa[ckadd]": "com.maddyhome.idea.vim.vimscript.model.commands.PackaddCommand",
"prev[ious]": "com.maddyhome.idea.vim.vimscript.model.commands.PreviousFileCommand",
"pu[t]": "com.maddyhome.idea.vim.vimscript.model.commands.PutLinesCommand",
"q[uit]": "com.maddyhome.idea.vim.vimscript.model.commands.QuitCommand",
"qa[ll]": "com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand",
"quita[ll]": "com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand",
"red[o]": "com.maddyhome.idea.vim.vimscript.model.commands.RedoCommand",
"reg[isters]": "com.maddyhome.idea.vim.vimscript.model.commands.RegistersCommand",
"s[ubstitute]": "com.maddyhome.idea.vim.vimscript.model.commands.SubstituteCommand",
"se[t]": "com.maddyhome.idea.vim.vimscript.model.commands.SetCommand",
"setg[lobal]": "com.maddyhome.idea.vim.vimscript.model.commands.SetglobalCommand",
"sethandler": "com.maddyhome.idea.vim.vimscript.model.commands.SetHandlerCommand",
"setl[ocal]": "com.maddyhome.idea.vim.vimscript.model.commands.SetlocalCommand",
"sh[ell]": "com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand",
"smap": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"smapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"snor[emap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"so[urce]": "com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand",
"sor[t]": "com.maddyhome.idea.vim.vimscript.model.commands.SortCommand",
"sp[lit]": "com.maddyhome.idea.vim.vimscript.model.commands.SplitCommand",
"sunm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"t": "com.maddyhome.idea.vim.vimscript.model.commands.CopyTextCommand",
"tabN[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.PreviousTabCommand",
"tabc[lose]": "com.maddyhome.idea.vim.vimscript.model.commands.TabCloseCommand",
"tabm[ove]": "com.maddyhome.idea.vim.vimscript.model.commands.TabMoveCommand",
"tabn[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.NextTabCommand",
"tabo[nly]": "com.maddyhome.idea.vim.vimscript.model.commands.TabOnlyCommand",
"tabp[revious]": "com.maddyhome.idea.vim.vimscript.model.commands.PreviousTabCommand",
"u[ndo]": "com.maddyhome.idea.vim.vimscript.model.commands.UndoCommand",
"unlo[ckvar]": "com.maddyhome.idea.vim.vimscript.model.commands.UnlockVarCommand",
"unm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"v[global]": "com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand",
"vm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"vmapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"vn[oremap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"vs[plit]": "com.maddyhome.idea.vim.vimscript.model.commands.SplitCommand",
"vu[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"wN[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.WritePreviousFileCommand",
"w[rite]": "com.maddyhome.idea.vim.vimscript.model.commands.WriteCommand",
"wa[ll]": "com.maddyhome.idea.vim.vimscript.model.commands.WriteAllCommand",
"wn[ext]": "com.maddyhome.idea.vim.vimscript.model.commands.WriteNextFileCommand",
"wp[revious]": "com.maddyhome.idea.vim.vimscript.model.commands.WritePreviousFileCommand",
"wq": "com.maddyhome.idea.vim.vimscript.model.commands.WriteQuitCommand",
"wqa[ll]": "com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand",
"x[it]": "com.maddyhome.idea.vim.vimscript.model.commands.WriteQuitCommand",
"xa[ll]": "com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand",
"xm[ap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"xmapc[lear]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapClearCommand",
"xn[oremap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand",
"xu[nmap]": "com.maddyhome.idea.vim.vimscript.model.commands.mapping.UnMapCommand",
"y[ank]": "com.maddyhome.idea.vim.vimscript.model.commands.YankLinesCommand",
"~": "com.maddyhome.idea.vim.vimscript.model.commands.SubstituteCommand"
}

View File

@ -0,0 +1,14 @@
{
"abs": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.AbsFunctionHandler",
"empty": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.EmptyFunctionHandler",
"exists": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ExistsFunctionHandler",
"funcref": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.FuncrefFunctionHandler",
"function": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.FunctionFunctionHandler",
"get": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.GetFunctionHandler",
"join": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler",
"len": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LenFunctionHandler",
"sin": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SinFunctionHandler",
"split": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SplitFunctionHandler",
"tolower": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler",
"toupper": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler"
}