mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
93 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
69f4611552 | ||
![]() |
31a25449a8 | ||
![]() |
26a247c0bf | ||
![]() |
1c7cd23475 | ||
![]() |
296ef1bdf9 | ||
![]() |
642659bc9b | ||
![]() |
f0e8d065b7 | ||
![]() |
520d852c04 | ||
![]() |
8d4d7a421a | ||
![]() |
802b83b0fe | ||
![]() |
31f598d1e1 | ||
![]() |
46e6fd0847 | ||
![]() |
1441a60f4b | ||
![]() |
ebdf107946 | ||
![]() |
38d672c9f9 | ||
![]() |
75d34abd45 | ||
![]() |
1d98738e4d | ||
![]() |
3cfa0e1844 | ||
![]() |
82211a4373 | ||
![]() |
e324b04a94 | ||
![]() |
49d0c51d97 | ||
![]() |
fe4bc3b4a9 | ||
![]() |
58d964063c | ||
![]() |
17d3e37e1d | ||
![]() |
54f6a16bd6 | ||
![]() |
f4ffc5d198 | ||
![]() |
3d8010bf88 | ||
![]() |
ec2cc3a7f9 | ||
![]() |
52b7b9bcd8 | ||
![]() |
8ad0fcf42d | ||
![]() |
aa6cc45988 | ||
![]() |
da22b8297b | ||
![]() |
798d82e941 | ||
![]() |
ac8ac302ca | ||
![]() |
22c3a73102 | ||
![]() |
1222fdb043 | ||
![]() |
78a50c2f53 | ||
![]() |
6d261a7afa | ||
![]() |
2e37292478 | ||
![]() |
a4907ec9c8 | ||
![]() |
992bfe73b6 | ||
![]() |
c186254a7e | ||
![]() |
1dc739f32c | ||
![]() |
9804cd83a6 | ||
![]() |
aa5b99c47a | ||
![]() |
f95f5e8901 | ||
![]() |
206b303407 | ||
![]() |
751bff53ee | ||
![]() |
b6ef0c509d | ||
![]() |
30304d6836 | ||
![]() |
f5df49b139 | ||
![]() |
bf8ba1a49b | ||
![]() |
9f2697658b | ||
![]() |
36fd59b92c | ||
![]() |
88d946546a | ||
![]() |
6036c0c262 | ||
![]() |
20e831b56a | ||
![]() |
72b74e075c | ||
![]() |
3c6ede2f8f | ||
![]() |
5434edbd54 | ||
![]() |
6a8c7e4b17 | ||
![]() |
0ac659f2d1 | ||
![]() |
7eae40ca9a | ||
![]() |
b3d12c8b58 | ||
![]() |
3f92dba1b7 | ||
![]() |
0aedc08cfa | ||
![]() |
8312f5cffd | ||
![]() |
9f6338441e | ||
![]() |
27efe0c9d6 | ||
![]() |
b5bf6c08d8 | ||
![]() |
e3fce51ea1 | ||
![]() |
13b4e93bf4 | ||
![]() |
4ec0ab281f | ||
![]() |
39c96019b6 | ||
![]() |
21f2f60355 | ||
![]() |
0de654dcaf | ||
![]() |
d59e472814 | ||
![]() |
cc2ed452f0 | ||
![]() |
d4d3843725 | ||
![]() |
dee16da1c2 | ||
![]() |
e09b85870f | ||
![]() |
8596911a0e | ||
![]() |
6c2de9f151 | ||
![]() |
d3a6b1e39e | ||
![]() |
3cb9b19aea | ||
![]() |
86aa59bb29 | ||
![]() |
c6eeaed7da | ||
![]() |
edba90f188 | ||
![]() |
7943e34bde | ||
![]() |
74970c74b4 | ||
![]() |
722431f5b2 | ||
![]() |
df8e455a6d | ||
![]() |
b35bec2839 |
@@ -28,6 +28,11 @@ Contributors:
|
|||||||
* [salaam](mailto:kphayen@gmail.com)
|
* [salaam](mailto:kphayen@gmail.com)
|
||||||
* [Alexey Shmalko](mailto:rasen.dubi@gmail.com)
|
* [Alexey Shmalko](mailto:rasen.dubi@gmail.com)
|
||||||
* [Andrew Brookins](mailto:a.m.brookins@gmail.com)
|
* [Andrew Brookins](mailto:a.m.brookins@gmail.com)
|
||||||
|
* [Chang Wang](mailto:changwang83@gmail.com)
|
||||||
|
* [Jaime Sanchez](mailto:josejaime.sanchez@gmail.com)
|
||||||
|
* [Thomas B Homburg](mailto:thomas@homburg.dk)
|
||||||
|
* [smartbomb](mailto:smartbomb@server.fake)
|
||||||
|
* [Tuomas Tynkkynen](mailto:tuomas.tynkkynen@iki.fi)
|
||||||
|
|
||||||
If you are a contributor and your name is not listed here, feel free to
|
If you are a contributor and your name is not listed here, feel free to
|
||||||
contact the maintainer.
|
contact the maintainer.
|
||||||
|
34
CHANGES.md
34
CHANGES.md
@@ -4,12 +4,44 @@ The Changelog
|
|||||||
History of changes in IdeaVim for the IntelliJ platform.
|
History of changes in IdeaVim for the IntelliJ platform.
|
||||||
|
|
||||||
|
|
||||||
|
0.38, 2014-12-01
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Added support for `number` and `relativenumber` options, `clipboard=unnamed`
|
||||||
|
option. Added `:action` and `:actionlist` commands for executing arbitrary
|
||||||
|
IDE actions. Various bug fixes.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* VIM-476 Added support for `clipboard=unnamed` option
|
||||||
|
* VIM-410 Added support for `relativenumber` option
|
||||||
|
* VIM-483 Added support for `number` option
|
||||||
|
* VIM-652 Added `:action` and `:actionlist` commands for executing arbitrary
|
||||||
|
IDE actions
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* VIM-818 Enable key repeat on Mac OS X every time it gets reset by the OS
|
||||||
|
* VIM-624 Deselect visual selection range on opening the Ex entry field
|
||||||
|
* VIM-511 Fixed editing offset after `<BS>` for `.` command
|
||||||
|
* VIM-792 Fixed line-wise and block-wise paste commands for `*` and `+`
|
||||||
|
registers
|
||||||
|
* VIM-501 Fixed off-by-1 error in visual block-wise selection
|
||||||
|
* VIM-613 Fixed repeat after `d$`
|
||||||
|
* VIM-705 Fixed repeated multiline indent
|
||||||
|
* VIM-567 Fixed `:!` to allow running non-filter commands
|
||||||
|
* VIM-536 Fixed `cc` on the second-to-last line
|
||||||
|
* VIM-515 Fixed `cW` command detecting end-of-word incorrectly
|
||||||
|
* VIM-794 Fixed NCDFE related to 'number' in IDEs other than IntelliJ
|
||||||
|
* VIM-771 Fix semicolon repeat for 'till char' motion
|
||||||
|
* VIM-723 Fix pasting to an empty line
|
||||||
|
|
||||||
|
|
||||||
0.37, 2014-10-15
|
0.37, 2014-10-15
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
A bugfix release.
|
A bugfix release.
|
||||||
|
|
||||||
|
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
|
|
||||||
* VIM-784 Fixed visual line selection where the start of the selection range
|
* VIM-784 Fixed visual line selection where the start of the selection range
|
||||||
|
12
README.md
12
README.md
@@ -36,7 +36,7 @@ Start the IDE normally and enable the Vim emulation using "Tools | Vim
|
|||||||
Emulator" menu item. At this point you must use Vim keystrokes in all editors.
|
Emulator" menu item. At this point you must use Vim keystrokes in all editors.
|
||||||
|
|
||||||
If you wish to disable the plugin, select the "Tools | Vim Emulator" menu so
|
If you wish to disable the plugin, select the "Tools | Vim Emulator" menu so
|
||||||
it is unchecked. At this point IDE will work with it's regular keyboard
|
it is unchecked. At this point IDE will work with its regular keyboard
|
||||||
shortcuts.
|
shortcuts.
|
||||||
|
|
||||||
Keyboard shortcut conflicts between the Vim emulation and the IDE can be
|
Keyboard shortcut conflicts between the Vim emulation and the IDE can be
|
||||||
@@ -112,6 +112,16 @@ usage of the Vim emulator in dialog windows is an area for improvements.
|
|||||||
|
|
||||||
See also [unresolved escape issues](http://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+i_Esc).
|
See also [unresolved escape issues](http://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+i_Esc).
|
||||||
|
|
||||||
|
### Executing IDE Actions
|
||||||
|
|
||||||
|
IdeaVim adds two commands for listing and executing arbitrary IDE actions as
|
||||||
|
Ex commands or via `:map` command mappings:
|
||||||
|
|
||||||
|
* `:actionlist [pattern]`
|
||||||
|
* Find IDE actions by name pattern
|
||||||
|
* `:action {name}`
|
||||||
|
* Execute an action named `NAME`
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
version-id:0.37
|
version-id:0.38
|
||||||
platform-version:135.0
|
platform-version:135.0
|
||||||
idea.download.url=http://download.jetbrains.com/idea/ideaIU-13.1.zip
|
idea.download.url=http://download.jetbrains.com/idea/ideaIU-14.0.1.zip
|
||||||
build.number=dev
|
build.number=dev
|
||||||
|
@@ -3,22 +3,26 @@ List of Supported Set Commands
|
|||||||
|
|
||||||
The following `:set` commands can appear in `~/.ideavimrc` or set manually in the command mode:
|
The following `:set` commands can appear in `~/.ideavimrc` or set manually in the command mode:
|
||||||
|
|
||||||
'digraph' 'dg' enable the entering of digraphs in Insert mode
|
'clipboard' 'cb' clipboard options
|
||||||
'gdefault' 'gd' the ":substitute" flag 'g' is default on
|
'digraph' 'dg' enable the entering of digraphs in Insert mode
|
||||||
'history' 'hi' number of command-lines that are remembered
|
'gdefault' 'gd' the ":substitute" flag 'g' is default on
|
||||||
'hlsearch' 'hls' highlight matches with last search pattern
|
'history' 'hi' number of command-lines that are remembered
|
||||||
'ignorecase' 'ic' ignore case in search patterns
|
'hlsearch' 'hls' highlight matches with last search pattern
|
||||||
'matchpairs' 'mps' pairs of characters that "%" can match
|
'ignorecase' 'ic' ignore case in search patterns
|
||||||
'nrformats' 'nf' number formats recognized for CTRL-A command
|
'matchpairs' 'mps' pairs of characters that "%" can match
|
||||||
'scroll' 'scr' lines to scroll with CTRL-U and CTRL-D
|
'nrformats' 'nf' number formats recognized for CTRL-A command
|
||||||
'scrolljump' 'sj' minimum number of lines to scroll
|
'number' 'nu' print the line number in front of each line
|
||||||
'scrolloff' 'so' minimum nr. of lines above and below cursor
|
'relativenumber' 'rnu' show the line number relative to the line with
|
||||||
'selection' 'sel' what type of selection to use
|
the cursor
|
||||||
'showmode' 'smd' message on status line to show current mode
|
'scroll' 'scr' lines to scroll with CTRL-U and CTRL-D
|
||||||
'sidescroll' 'ss' minimum number of columns to scroll horizontal
|
'scrolljump' 'sj' minimum number of lines to scroll
|
||||||
'sidescrolloff' 'siso' min. nr. of columns to left and right of cursor
|
'scrolloff' 'so' minimum nr. of lines above and below cursor
|
||||||
'smartcase' 'scs' no ignore case when pattern has uppercase
|
'selection' 'sel' what type of selection to use
|
||||||
'timeoutlen' 'tm' time that is waited for a mapped key sequence
|
'showmode' 'smd' message on status line to show current mode
|
||||||
'undolevels' 'ul' maximum number of changes that can be undone
|
'sidescroll' 'ss' minimum number of columns to scroll horizontal
|
||||||
'visualbell' 'vb' use visual bell instead of beeping
|
'sidescrolloff' 'siso' min. nr. of columns to left and right of cursor
|
||||||
'wrapscan' 'ws' searches wrap around the end of the file
|
'smartcase' 'scs' no ignore case when pattern has uppercase
|
||||||
|
'timeoutlen' 'tm' time that is waited for a mapped key sequence
|
||||||
|
'undolevels' 'ul' maximum number of changes that can be undone
|
||||||
|
'visualbell' 'vb' use visual bell instead of beeping
|
||||||
|
'wrapscan' 'ws' searches wrap around the end of the file
|
||||||
|
@@ -3,6 +3,13 @@
|
|||||||
<id>IdeaVIM</id>
|
<id>IdeaVIM</id>
|
||||||
<change-notes>
|
<change-notes>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
|
<p>0.38:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Support for <code>:action</code> and <code>:actionlist</code> for executing arbitrary IDE actions</li>
|
||||||
|
<li>Support for <code>number</code> and <code>relativenumber</code> options</li>
|
||||||
|
<li>Support for <code>clipboard=unnamed</code> option</li>
|
||||||
|
<li>Various bug fixes</li>
|
||||||
|
</ul>
|
||||||
<p>0.37:</p>
|
<p>0.37:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Various bug fixes</li>
|
<li>Various bug fixes</li>
|
||||||
@@ -41,9 +48,13 @@
|
|||||||
<description>
|
<description>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
<p>Build @VERSION@-@BUILD-NUMBER@</p>
|
<p>Build @VERSION@-@BUILD-NUMBER@</p>
|
||||||
<p>Vim emulation plug-in for IDEs based on the IntelliJ platform. IdeaVim can be used with IntelliJ IDEA, RubyMine, PyCharm, PhpStorm, WebStorm, AppCode, CLion and Android Studio.</p>
|
<p>Vim emulation plug-in for IDEs based on the IntelliJ platform.</p>
|
||||||
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing, marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, window commands, etc.</p>
|
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing, marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, window commands, etc.</p>
|
||||||
<p>See the <a href="https://github.com/JetBrains/ideavim">JetBrains/ideavim</a> on GitHub for more details.</p>
|
<p>See also:</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a> for documentation and contributing</li>
|
||||||
|
<li><a href="http://youtrack.jetbrains.com/issues/VIM">Issue tracker</a> for feature requests and bug reports</li>
|
||||||
|
</ul>
|
||||||
]]>
|
]]>
|
||||||
</description>
|
</description>
|
||||||
<version>@VERSION@</version>
|
<version>@VERSION@</version>
|
||||||
|
@@ -292,17 +292,19 @@ public class KeyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, @NotNull final DataContext context) {
|
private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, @NotNull final DataContext context) {
|
||||||
if (state != State.COMMAND && count == 0 && currentArg == Argument.Type.NONE && currentCmd.size() == 0 &&
|
if (state != State.COMMAND && count == 0 && currentArg == Argument.Type.NONE && currentCmd.size() == 0) {
|
||||||
VimPlugin.getRegister().getCurrentRegister() == RegisterGroup.REGISTER_DEFAULT) {
|
RegisterGroup register = VimPlugin.getRegister();
|
||||||
if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
if (register.getCurrentRegister() == register.getDefaultRegister()) {
|
||||||
CommandProcessor.getInstance().executeCommand(editor.getProject(), new Runnable() {
|
if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
@Override
|
CommandProcessor.getInstance().executeCommand(editor.getProject(), new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
KeyHandler.executeAction("EditorEscape", context);
|
public void run() {
|
||||||
}
|
KeyHandler.executeAction("EditorEscape", context);
|
||||||
}, "", null);
|
}
|
||||||
|
}, "", null);
|
||||||
|
}
|
||||||
|
VimPlugin.indicateError();
|
||||||
}
|
}
|
||||||
VimPlugin.indicateError();
|
|
||||||
}
|
}
|
||||||
reset(editor);
|
reset(editor);
|
||||||
}
|
}
|
||||||
@@ -560,12 +562,10 @@ public class KeyHandler {
|
|||||||
* @param name The name of the action to execute
|
* @param name The name of the action to execute
|
||||||
* @param context The context to run it in
|
* @param context The context to run it in
|
||||||
*/
|
*/
|
||||||
public static void executeAction(@NotNull String name, @NotNull DataContext context) {
|
public static boolean executeAction(@NotNull String name, @NotNull DataContext context) {
|
||||||
ActionManager aMgr = ActionManager.getInstance();
|
ActionManager aMgr = ActionManager.getInstance();
|
||||||
AnAction action = aMgr.getAction(name);
|
AnAction action = aMgr.getAction(name);
|
||||||
if (action != null) {
|
return action != null && executeAction(action, context);
|
||||||
executeAction(action, context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -574,16 +574,20 @@ public class KeyHandler {
|
|||||||
* @param action The action to execute
|
* @param action The action to execute
|
||||||
* @param context The context to run it in
|
* @param context The context to run it in
|
||||||
*/
|
*/
|
||||||
public static void executeAction(@NotNull AnAction action, @NotNull DataContext context) {
|
public static boolean executeAction(@NotNull AnAction action, @NotNull DataContext context) {
|
||||||
// Hopefully all the arguments are sufficient. So far they all seem to work OK.
|
// Hopefully all the arguments are sufficient. So far they all seem to work OK.
|
||||||
// We don't have a specific InputEvent so that is null
|
// We don't have a specific InputEvent so that is null
|
||||||
// What is "place"? Leave it the empty string for now.
|
// What is "place"? Leave it the empty string for now.
|
||||||
// Is the template presentation sufficient?
|
// Is the template presentation sufficient?
|
||||||
// What are the modifiers? Is zero OK?
|
// What are the modifiers? Is zero OK?
|
||||||
action.actionPerformed(
|
final AnActionEvent event = new AnActionEvent(null, context, "", action.getTemplatePresentation(),
|
||||||
new AnActionEvent(null, context, "", action.getTemplatePresentation(), ActionManager.getInstance(),
|
ActionManager.getInstance(), 0);
|
||||||
// API change - don't merge
|
action.update(event);
|
||||||
0));
|
if (event.getPresentation().isEnabled()) {
|
||||||
|
action.actionPerformed(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -630,11 +630,11 @@ public class RegisterActions {
|
|||||||
new Shortcut("=="));
|
new Shortcut("=="));
|
||||||
parser.registerAction(MappingMode.N, "VimShiftLeftLines", Command.Type.CHANGE,
|
parser.registerAction(MappingMode.N, "VimShiftLeftLines", Command.Type.CHANGE,
|
||||||
new Shortcut("<<"));
|
new Shortcut("<<"));
|
||||||
parser.registerAction(MappingMode.N, "VimShiftLeftMotion", Command.Type.CHANGE,
|
parser.registerAction(MappingMode.N, "VimShiftLeftMotion", Command.Type.CHANGE, Command.FLAG_OP_PEND,
|
||||||
new Shortcut('<'), Argument.Type.MOTION);
|
new Shortcut('<'), Argument.Type.MOTION);
|
||||||
parser.registerAction(MappingMode.N, "VimShiftRightLines", Command.Type.CHANGE,
|
parser.registerAction(MappingMode.N, "VimShiftRightLines", Command.Type.CHANGE,
|
||||||
new Shortcut(">>"));
|
new Shortcut(">>"));
|
||||||
parser.registerAction(MappingMode.N, "VimShiftRightMotion", Command.Type.CHANGE,
|
parser.registerAction(MappingMode.N, "VimShiftRightMotion", Command.Type.CHANGE, Command.FLAG_OP_PEND,
|
||||||
new Shortcut('>'), Argument.Type.MOTION);
|
new Shortcut('>'), Argument.Type.MOTION);
|
||||||
|
|
||||||
// Jump Actions
|
// Jump Actions
|
||||||
@@ -722,11 +722,11 @@ public class RegisterActions {
|
|||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK)));
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK)));
|
||||||
parser.registerAction(MappingMode.I, "VimMotionLastColumn", Command.Type.INSERT, Command.FLAG_SAVE_STROKE,
|
parser.registerAction(MappingMode.I, "VimMotionLastColumn", Command.Type.INSERT, Command.FLAG_SAVE_STROKE,
|
||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0)));
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0)));
|
||||||
parser.registerAction(MappingMode.I, "VimMotionLeft", Command.Type.INSERT, Command.FLAG_SAVE_STROKE, new Shortcut[]{
|
parser.registerAction(MappingMode.I, "VimMotionLeft", Command.Type.INSERT, new Shortcut[]{
|
||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
|
||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, 0))
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, 0))
|
||||||
});
|
});
|
||||||
parser.registerAction(MappingMode.I, "VimMotionRight", Command.Type.INSERT, Command.FLAG_SAVE_STROKE, new Shortcut[]{
|
parser.registerAction(MappingMode.I, "VimMotionRight", Command.Type.INSERT, new Shortcut[]{
|
||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)),
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)),
|
||||||
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, 0))
|
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, 0))
|
||||||
});
|
});
|
||||||
|
@@ -18,7 +18,6 @@
|
|||||||
package com.maddyhome.idea.vim;
|
package com.maddyhome.idea.vim;
|
||||||
|
|
||||||
import com.intellij.notification.*;
|
import com.intellij.notification.*;
|
||||||
import com.intellij.openapi.application.Application;
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.application.ex.ApplicationEx;
|
import com.intellij.openapi.application.ex.ApplicationEx;
|
||||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||||
@@ -27,13 +26,8 @@ import com.intellij.openapi.components.PersistentStateComponent;
|
|||||||
import com.intellij.openapi.components.State;
|
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.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.editor.EditorFactory;
|
|
||||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||||
import com.intellij.openapi.editor.actionSystem.TypedAction;
|
import com.intellij.openapi.editor.actionSystem.TypedAction;
|
||||||
import com.intellij.openapi.editor.event.EditorFactoryAdapter;
|
|
||||||
import com.intellij.openapi.editor.event.EditorFactoryEvent;
|
|
||||||
import com.intellij.openapi.editor.ex.EditorEx;
|
|
||||||
import com.intellij.openapi.extensions.PluginId;
|
import com.intellij.openapi.extensions.PluginId;
|
||||||
import com.intellij.openapi.keymap.Keymap;
|
import com.intellij.openapi.keymap.Keymap;
|
||||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
||||||
@@ -46,13 +40,10 @@ import com.intellij.openapi.ui.Messages;
|
|||||||
import com.intellij.openapi.util.SystemInfo;
|
import com.intellij.openapi.util.SystemInfo;
|
||||||
import com.intellij.openapi.wm.StatusBar;
|
import com.intellij.openapi.wm.StatusBar;
|
||||||
import com.intellij.openapi.wm.WindowManager;
|
import com.intellij.openapi.wm.WindowManager;
|
||||||
import com.maddyhome.idea.vim.command.CommandState;
|
|
||||||
import com.maddyhome.idea.vim.ex.CommandParser;
|
import com.maddyhome.idea.vim.ex.CommandParser;
|
||||||
import com.maddyhome.idea.vim.ex.VimScriptParser;
|
import com.maddyhome.idea.vim.ex.VimScriptParser;
|
||||||
import com.maddyhome.idea.vim.group.*;
|
import com.maddyhome.idea.vim.group.*;
|
||||||
import com.maddyhome.idea.vim.helper.DocumentManager;
|
import com.maddyhome.idea.vim.helper.DocumentManager;
|
||||||
import com.maddyhome.idea.vim.helper.EditorData;
|
|
||||||
import com.maddyhome.idea.vim.helper.EditorDataContext;
|
|
||||||
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
|
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
|
||||||
import com.maddyhome.idea.vim.option.Options;
|
import com.maddyhome.idea.vim.option.Options;
|
||||||
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
|
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
|
||||||
@@ -60,7 +51,6 @@ import org.jdom.Element;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.HyperlinkEvent;
|
import javax.swing.event.HyperlinkEvent;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -88,13 +78,6 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
public static final String IDEAVIM_NOTIFICATION_TITLE = "IdeaVim";
|
public static final String IDEAVIM_NOTIFICATION_TITLE = "IdeaVim";
|
||||||
public static final int STATE_VERSION = 4;
|
public static final int STATE_VERSION = 4;
|
||||||
|
|
||||||
private static final boolean BLOCK_CURSOR_VIM_VALUE = true;
|
|
||||||
private static final boolean ANIMATED_SCROLLING_VIM_VALUE = false;
|
|
||||||
private static final boolean REFRAIN_FROM_SCROLLING_VIM_VALUE = true;
|
|
||||||
|
|
||||||
private boolean isBlockCursor = false;
|
|
||||||
private boolean isAnimatedScrolling = false;
|
|
||||||
private boolean isRefrainFromScrolling = false;
|
|
||||||
private boolean error = false;
|
private boolean error = false;
|
||||||
|
|
||||||
private int previousStateVersion = 0;
|
private int previousStateVersion = 0;
|
||||||
@@ -105,8 +88,6 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
|
|
||||||
private static final Logger LOG = Logger.getInstance(VimPlugin.class);
|
private static final Logger LOG = Logger.getInstance(VimPlugin.class);
|
||||||
|
|
||||||
private final Application myApp;
|
|
||||||
|
|
||||||
@NotNull private final MotionGroup motion;
|
@NotNull private final MotionGroup motion;
|
||||||
@NotNull private final ChangeGroup change;
|
@NotNull private final ChangeGroup change;
|
||||||
@NotNull private final CopyGroup copy;
|
@NotNull private final CopyGroup copy;
|
||||||
@@ -119,11 +100,10 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
@NotNull private final DigraphGroup digraph;
|
@NotNull private final DigraphGroup digraph;
|
||||||
@NotNull private final HistoryGroup history;
|
@NotNull private final HistoryGroup history;
|
||||||
@NotNull private final KeyGroup key;
|
@NotNull private final KeyGroup key;
|
||||||
@NotNull private WindowGroup window;
|
@NotNull private final WindowGroup window;
|
||||||
|
@NotNull private final EditorGroup editor;
|
||||||
public VimPlugin(final Application app) {
|
|
||||||
myApp = app;
|
|
||||||
|
|
||||||
|
public VimPlugin() {
|
||||||
motion = new MotionGroup();
|
motion = new MotionGroup();
|
||||||
change = new ChangeGroup();
|
change = new ChangeGroup();
|
||||||
copy = new CopyGroup();
|
copy = new CopyGroup();
|
||||||
@@ -137,6 +117,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
history = new HistoryGroup();
|
history = new HistoryGroup();
|
||||||
key = new KeyGroup();
|
key = new KeyGroup();
|
||||||
window = new WindowGroup();
|
window = new WindowGroup();
|
||||||
|
editor = new EditorGroup();
|
||||||
|
|
||||||
LOG.debug("VimPlugin ctr");
|
LOG.debug("VimPlugin ctr");
|
||||||
}
|
}
|
||||||
@@ -205,6 +186,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
search.saveData(element);
|
search.saveData(element);
|
||||||
history.saveData(element);
|
history.saveData(element);
|
||||||
key.saveData(element);
|
key.saveData(element);
|
||||||
|
editor.saveData(element);
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
@@ -230,6 +212,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
search.readData(element);
|
search.readData(element);
|
||||||
history.readData(element);
|
history.readData(element);
|
||||||
key.readData(element);
|
key.readData(element);
|
||||||
|
editor.readData(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -297,6 +280,11 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
return getInstance().window;
|
return getInstance().window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static EditorGroup getEditor() {
|
||||||
|
return getInstance().editor;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static PluginId getPluginId() {
|
public static PluginId getPluginId() {
|
||||||
return PluginId.getId(IDEAVIM_PLUGIN_ID);
|
return PluginId.getId(IDEAVIM_PLUGIN_ID);
|
||||||
@@ -367,38 +355,38 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
|
|
||||||
private void turnOnPlugin() {
|
private void turnOnPlugin() {
|
||||||
KeyHandler.getInstance().fullReset(null);
|
KeyHandler.getInstance().fullReset(null);
|
||||||
setCursors(BLOCK_CURSOR_VIM_VALUE);
|
|
||||||
setAnimatedScrolling(ANIMATED_SCROLLING_VIM_VALUE);
|
|
||||||
setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
|
|
||||||
|
|
||||||
|
getEditor().turnOn();
|
||||||
getMotion().turnOn();
|
getMotion().turnOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void turnOffPlugin() {
|
private void turnOffPlugin() {
|
||||||
KeyHandler.getInstance().fullReset(null);
|
KeyHandler.getInstance().fullReset(null);
|
||||||
setCursors(isBlockCursor);
|
|
||||||
setAnimatedScrolling(isAnimatedScrolling);
|
|
||||||
setRefrainFromScrolling(isRefrainFromScrolling);
|
|
||||||
|
|
||||||
|
getEditor().turnOff();
|
||||||
getMotion().turnOff();
|
getMotion().turnOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateState() {
|
private void updateState() {
|
||||||
if (isEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
if (isEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
boolean requiresRestart = false;
|
boolean requiresRestart = false;
|
||||||
if (previousStateVersion < 2 && SystemInfo.isMac) {
|
if (SystemInfo.isMac) {
|
||||||
final MacKeyRepeat keyRepeat = MacKeyRepeat.getInstance();
|
final MacKeyRepeat keyRepeat = MacKeyRepeat.getInstance();
|
||||||
final Boolean enabled = keyRepeat.isEnabled();
|
final Boolean enabled = keyRepeat.isEnabled();
|
||||||
if (enabled == null || !enabled) {
|
final Boolean isKeyRepeat = editor.isKeyRepeat();
|
||||||
|
if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) {
|
||||||
if (Messages.showYesNoDialog("Do you want to enable repeating keys in Mac OS X on press and hold " +
|
if (Messages.showYesNoDialog("Do you want to enable repeating keys in Mac OS X on press and hold " +
|
||||||
"(requires restart)?\n\n" +
|
"(requires restart)?\n\n" +
|
||||||
"(You can do it manually by running 'defaults write -g " +
|
"(You can do it manually by running 'defaults write -g " +
|
||||||
"ApplePressAndHoldEnabled 0' in the console).", IDEAVIM_NOTIFICATION_TITLE,
|
"ApplePressAndHoldEnabled 0' in the console).", IDEAVIM_NOTIFICATION_TITLE,
|
||||||
Messages.getQuestionIcon()
|
Messages.getQuestionIcon()) == Messages.YES) {
|
||||||
) == Messages.YES) {
|
editor.setKeyRepeat(true);
|
||||||
keyRepeat.setEnabled(true);
|
keyRepeat.setEnabled(true);
|
||||||
requiresRestart = true;
|
requiresRestart = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
editor.setKeyRepeat(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (previousStateVersion > 0 && previousStateVersion < 3) {
|
if (previousStateVersion > 0 && previousStateVersion < 3) {
|
||||||
@@ -456,40 +444,6 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
DocumentManager.getInstance().addDocumentListener(new MarkGroup.MarkUpdater());
|
DocumentManager.getInstance().addDocumentListener(new MarkGroup.MarkUpdater());
|
||||||
DocumentManager.getInstance().addDocumentListener(new SearchGroup.DocumentSearchListener());
|
DocumentManager.getInstance().addDocumentListener(new SearchGroup.DocumentSearchListener());
|
||||||
|
|
||||||
eventFacade.addEditorFactoryListener(new EditorFactoryAdapter() {
|
|
||||||
@Override
|
|
||||||
public void editorCreated(@NotNull EditorFactoryEvent event) {
|
|
||||||
final Editor editor = event.getEditor();
|
|
||||||
isBlockCursor = editor.getSettings().isBlockCursor();
|
|
||||||
isAnimatedScrolling = editor.getSettings().isAnimatedScrolling();
|
|
||||||
isRefrainFromScrolling = editor.getSettings().isRefrainFromScrolling();
|
|
||||||
EditorData.initializeEditor(editor);
|
|
||||||
DocumentManager.getInstance().addListeners(editor.getDocument());
|
|
||||||
key.registerRequiredShortcutKeys(editor);
|
|
||||||
|
|
||||||
if (VimPlugin.isEnabled()) {
|
|
||||||
// Turn on insert mode if editor doesn't have any file
|
|
||||||
if (!EditorData.isFileEditor(editor) && editor.getDocument().isWritable() &&
|
|
||||||
!CommandState.inInsertMode(editor)) {
|
|
||||||
KeyHandler.getInstance().handleKey(editor, KeyStroke.getKeyStroke('i'), new EditorDataContext(editor));
|
|
||||||
}
|
|
||||||
editor.getSettings().setBlockCursor(!CommandState.inInsertMode(editor));
|
|
||||||
editor.getSettings().setAnimatedScrolling(ANIMATED_SCROLLING_VIM_VALUE);
|
|
||||||
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void editorReleased(@NotNull EditorFactoryEvent event) {
|
|
||||||
final Editor editor = event.getEditor();
|
|
||||||
EditorData.uninitializeEditor(editor);
|
|
||||||
key.unregisterShortcutKeys(editor);
|
|
||||||
editor.getSettings().setAnimatedScrolling(isAnimatedScrolling);
|
|
||||||
editor.getSettings().setRefrainFromScrolling(isRefrainFromScrolling);
|
|
||||||
DocumentManager.getInstance().removeListeners(editor.getDocument());
|
|
||||||
}
|
|
||||||
}, myApp);
|
|
||||||
|
|
||||||
eventFacade.addProjectManagerListener(new ProjectManagerAdapter() {
|
eventFacade.addProjectManagerListener(new ProjectManagerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void projectOpened(@NotNull final Project project) {
|
public void projectOpened(@NotNull final Project project) {
|
||||||
@@ -499,27 +453,4 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCursors(boolean isBlock) {
|
|
||||||
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
|
||||||
for (Editor editor : editors) {
|
|
||||||
// Vim plugin should be turned on in insert mode
|
|
||||||
((EditorEx)editor).setInsertMode(true);
|
|
||||||
editor.getSettings().setBlockCursor(isBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAnimatedScrolling(boolean isOn) {
|
|
||||||
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
|
||||||
for (Editor editor : editors) {
|
|
||||||
editor.getSettings().setAnimatedScrolling(isOn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRefrainFromScrolling(boolean isOn) {
|
|
||||||
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
|
||||||
for (Editor editor : editors) {
|
|
||||||
editor.getSettings().setRefrainFromScrolling(isOn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -76,6 +76,7 @@ public class VimShortcutKeyAction extends AnAction implements DumbAware {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
@NotNull private static final Set<KeyStroke> NON_FILE_EDITOR_KEYS = ImmutableSet.<KeyStroke>builder()
|
@NotNull private static final Set<KeyStroke> NON_FILE_EDITOR_KEYS = ImmutableSet.<KeyStroke>builder()
|
||||||
|
.addAll(getKeyStrokes(VK_ENTER, 0))
|
||||||
.addAll(getKeyStrokes(VK_ESCAPE, 0))
|
.addAll(getKeyStrokes(VK_ESCAPE, 0))
|
||||||
.addAll(getKeyStrokes(VK_TAB, 0))
|
.addAll(getKeyStrokes(VK_TAB, 0))
|
||||||
.addAll(getKeyStrokes(VK_UP, 0))
|
.addAll(getKeyStrokes(VK_UP, 0))
|
||||||
@@ -144,8 +145,8 @@ public class VimShortcutKeyAction extends AnAction implements DumbAware {
|
|||||||
return isExitInsertMode(keyStroke);
|
return isExitInsertMode(keyStroke);
|
||||||
}
|
}
|
||||||
if (CommandState.inInsertMode(editor)) {
|
if (CommandState.inInsertMode(editor)) {
|
||||||
// XXX: <Enter> and <Tab> won't be recorded in macros
|
// XXX: <Tab> won't be recorded in macros
|
||||||
if (keyCode == VK_ENTER || keyCode == VK_TAB) {
|
if (keyCode == VK_TAB) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Debug watch, Python console, etc.
|
// Debug watch, Python console, etc.
|
||||||
|
@@ -42,7 +42,7 @@ public class MotionLastColumnAction extends MotionEditorAction {
|
|||||||
private static class Handler extends MotionEditorActionHandler {
|
private static class Handler extends MotionEditorActionHandler {
|
||||||
public int getOffset(@NotNull Editor editor, DataContext context, int count, int rawCount, Argument argument) {
|
public int getOffset(@NotNull Editor editor, DataContext context, int count, int rawCount, Argument argument) {
|
||||||
boolean allow = false;
|
boolean allow = false;
|
||||||
if (CommandState.inInsertMode(editor) || CommandState.inRepeatMode(editor)) {
|
if (CommandState.inInsertMode(editor)) {
|
||||||
allow = true;
|
allow = true;
|
||||||
}
|
}
|
||||||
else if (CommandState.getInstance(editor).getMode() == CommandState.Mode.VISUAL) {
|
else if (CommandState.getInstance(editor).getMode() == CommandState.Mode.VISUAL) {
|
||||||
|
@@ -20,7 +20,6 @@ package com.maddyhome.idea.vim.command;
|
|||||||
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.group.RegisterGroup;
|
|
||||||
import com.maddyhome.idea.vim.helper.EditorData;
|
import com.maddyhome.idea.vim.helper.EditorData;
|
||||||
import com.maddyhome.idea.vim.key.ParentNode;
|
import com.maddyhome.idea.vim.key.ParentNode;
|
||||||
import com.maddyhome.idea.vim.option.NumberOption;
|
import com.maddyhome.idea.vim.option.NumberOption;
|
||||||
@@ -38,7 +37,7 @@ public class CommandState {
|
|||||||
public static final int DEFAULT_TIMEOUT_LENGTH = 1000;
|
public static final int DEFAULT_TIMEOUT_LENGTH = 1000;
|
||||||
|
|
||||||
@Nullable private static Command ourLastChange = null;
|
@Nullable private static Command ourLastChange = null;
|
||||||
private static char ourLastRegister = RegisterGroup.REGISTER_DEFAULT;
|
private char myLastChangeRegister;
|
||||||
|
|
||||||
@NotNull private final Stack<State> myStates = new Stack<State>();
|
@NotNull private final Stack<State> myStates = new Stack<State>();
|
||||||
@NotNull private final State myDefaultState = new State(Mode.COMMAND, SubMode.NONE, MappingMode.NORMAL);
|
@NotNull private final State myDefaultState = new State(Mode.COMMAND, SubMode.NONE, MappingMode.NORMAL);
|
||||||
@@ -53,6 +52,7 @@ public class CommandState {
|
|||||||
myMappingTimer = new Timer(DEFAULT_TIMEOUT_LENGTH, null);
|
myMappingTimer = new Timer(DEFAULT_TIMEOUT_LENGTH, null);
|
||||||
myMappingTimer.setRepeats(false);
|
myMappingTimer.setRepeats(false);
|
||||||
myStates.push(new State(Mode.COMMAND, SubMode.NONE, MappingMode.NORMAL));
|
myStates.push(new State(Mode.COMMAND, SubMode.NONE, MappingMode.NORMAL));
|
||||||
|
myLastChangeRegister = VimPlugin.getRegister().getDefaultRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -255,7 +255,7 @@ public class CommandState {
|
|||||||
* @return The register key
|
* @return The register key
|
||||||
*/
|
*/
|
||||||
public char getLastChangeRegister() {
|
public char getLastChangeRegister() {
|
||||||
return ourLastRegister;
|
return myLastChangeRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,7 +265,7 @@ public class CommandState {
|
|||||||
*/
|
*/
|
||||||
public void saveLastChangeCommand(Command cmd) {
|
public void saveLastChangeCommand(Command cmd) {
|
||||||
ourLastChange = cmd;
|
ourLastChange = cmd;
|
||||||
ourLastRegister = VimPlugin.getRegister().getCurrentRegister();
|
myLastChangeRegister = VimPlugin.getRegister().getCurrentRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRecording() {
|
public boolean isRecording() {
|
||||||
|
@@ -70,6 +70,7 @@ public class CommandParser {
|
|||||||
public void registerHandlers() {
|
public void registerHandlers() {
|
||||||
if (registered) return;
|
if (registered) return;
|
||||||
|
|
||||||
|
new ActionListHandler();
|
||||||
new AsciiHandler();
|
new AsciiHandler();
|
||||||
new CmdFilterHandler();
|
new CmdFilterHandler();
|
||||||
new CopyTextHandler();
|
new CopyTextHandler();
|
||||||
@@ -77,6 +78,7 @@ public class CommandParser {
|
|||||||
new DigraphHandler();
|
new DigraphHandler();
|
||||||
new DumpLineHandler();
|
new DumpLineHandler();
|
||||||
new EditFileHandler();
|
new EditFileHandler();
|
||||||
|
new ActionHandler();
|
||||||
new ExitHandler();
|
new ExitHandler();
|
||||||
new FindClassHandler();
|
new FindClassHandler();
|
||||||
new FindFileHandler();
|
new FindFileHandler();
|
||||||
|
74
src/com/maddyhome/idea/vim/ex/handler/ActionHandler.java
Normal file
74
src/com/maddyhome/idea/vim/ex/handler/ActionHandler.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||||
|
* Copyright (C) 2003-2014 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.maddyhome.idea.vim.ex.handler;
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.ActionManager;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
|
import com.intellij.openapi.application.Application;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
|
import com.maddyhome.idea.vim.ex.CommandHandler;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExCommand;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExException;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author smartbomb
|
||||||
|
*/
|
||||||
|
public class ActionHandler extends CommandHandler {
|
||||||
|
public ActionHandler() {
|
||||||
|
super("action", "", RANGE_FORBIDDEN | DONT_REOPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean execute(@NotNull Editor editor, @NotNull final DataContext context,
|
||||||
|
@NotNull ExCommand cmd) throws ExException {
|
||||||
|
final String actionName = cmd.getArgument().trim();
|
||||||
|
final AnAction action = ActionManager.getInstance().getAction(actionName);
|
||||||
|
if (action == null) {
|
||||||
|
VimPlugin.showMessage("Action not found: " + actionName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Application application = ApplicationManager.getApplication();
|
||||||
|
if (application.isUnitTestMode()) {
|
||||||
|
executeAction(action, context, actionName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
application.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
executeAction(action, context, actionName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeAction(@NotNull AnAction action, @NotNull DataContext context, @NotNull String actionName) {
|
||||||
|
try {
|
||||||
|
KeyHandler.executeAction(action, context);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
// TODO: Find out if any runtime exceptions may happen here
|
||||||
|
assert false : "Error while executing :action " + actionName + " (" + action + "): " + e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
src/com/maddyhome/idea/vim/ex/handler/ActionListHandler.java
Normal file
85
src/com/maddyhome/idea/vim/ex/handler/ActionListHandler.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||||
|
* Copyright (C) 2003-2014 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.maddyhome.idea.vim.ex.handler;
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.*;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
|
import com.maddyhome.idea.vim.ex.CommandHandler;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExCommand;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExException;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
|
import com.maddyhome.idea.vim.helper.StringHelper;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author smartbomb
|
||||||
|
*/
|
||||||
|
public class ActionListHandler extends CommandHandler {
|
||||||
|
public ActionListHandler() {
|
||||||
|
super("actionlist", "", RANGE_FORBIDDEN | DONT_REOPEN | ARGUMENT_OPTIONAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean execute(@NotNull Editor editor, @NotNull final DataContext context,
|
||||||
|
@NotNull ExCommand cmd) throws ExException {
|
||||||
|
final String arg = cmd.getArgument().trim().toLowerCase();
|
||||||
|
final List<String> args = StringUtil.split(arg, "*");
|
||||||
|
final ActionManager actionManager = ActionManager.getInstance();
|
||||||
|
final List<String> actionNames = Arrays.asList(actionManager.getActionIds(""));
|
||||||
|
Collections.sort(actionNames, String.CASE_INSENSITIVE_ORDER);
|
||||||
|
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("--- Actions ---\n");
|
||||||
|
|
||||||
|
for (String actionName : actionNames) {
|
||||||
|
if (match(actionName, args)) {
|
||||||
|
builder.append(StringHelper.leftJustify(actionName, 50, ' '));
|
||||||
|
final AnAction action = actionManager.getAction(actionName);
|
||||||
|
final Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
|
||||||
|
for (Shortcut shortcut : shortcuts) {
|
||||||
|
builder.append(" ");
|
||||||
|
if (shortcut instanceof KeyboardShortcut) {
|
||||||
|
final KeyboardShortcut keyboardShortcut = (KeyboardShortcut)shortcut;
|
||||||
|
builder.append(StringHelper.toKeyNotation(keyboardShortcut.getFirstKeyStroke()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.append(shortcut.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExOutputModel.getInstance(editor).output(builder.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean match(@NotNull String actionName, @NotNull List<String> args) {
|
||||||
|
for (String argChunk : args) {
|
||||||
|
if (!actionName.toLowerCase().contains(argChunk)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -23,10 +23,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
|||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.common.TextRange;
|
import com.maddyhome.idea.vim.common.TextRange;
|
||||||
import com.maddyhome.idea.vim.ex.CommandHandler;
|
import com.maddyhome.idea.vim.ex.*;
|
||||||
import com.maddyhome.idea.vim.ex.ExCommand;
|
|
||||||
import com.maddyhome.idea.vim.ex.ExException;
|
|
||||||
import com.maddyhome.idea.vim.ex.Ranges;
|
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper;
|
import com.maddyhome.idea.vim.helper.MessageHelper;
|
||||||
import com.maddyhome.idea.vim.helper.Msg;
|
import com.maddyhome.idea.vim.helper.Msg;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -38,41 +35,42 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class CmdFilterHandler extends CommandHandler {
|
public class CmdFilterHandler extends CommandHandler {
|
||||||
public CmdFilterHandler() {
|
public CmdFilterHandler() {
|
||||||
super("!", "", RANGE_REQUIRED | ARGUMENT_OPTIONAL | WRITABLE);
|
super("!", "", RANGE_OPTIONAL | ARGUMENT_OPTIONAL | WRITABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
||||||
logger.info("execute");
|
logger.info("execute");
|
||||||
|
|
||||||
Ranges ranges = cmd.getRanges();
|
String command = cmd.getArgument();
|
||||||
if (ranges.size() == 0) {
|
if (command.length() == 0) {
|
||||||
// Need some range
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Filter
|
|
||||||
TextRange range = cmd.getTextRange(editor, context, false);
|
|
||||||
String command = cmd.getArgument();
|
|
||||||
if (command.indexOf('!') != -1) {
|
|
||||||
String last = VimPlugin.getProcess().getLastCommand();
|
|
||||||
if (last == null || last.length() == 0) {
|
|
||||||
VimPlugin.showMessage(MessageHelper.message(Msg.e_noprev));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
command = command.replaceAll("!", last);
|
if (command.indexOf('!') != -1) {
|
||||||
}
|
String last = VimPlugin.getProcess().getLastCommand();
|
||||||
|
if (last == null || last.length() == 0) {
|
||||||
if (command == null || command.length() == 0) {
|
VimPlugin.showMessage(MessageHelper.message(Msg.e_noprev));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
command = command.replaceAll("!", last);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Ranges ranges = cmd.getRanges();
|
||||||
|
if (ranges.size() == 0) {
|
||||||
|
// Show command output in a window
|
||||||
|
String commandOutput = VimPlugin.getProcess().executeCommand(command, null);
|
||||||
|
ExOutputModel.getInstance(editor).output(commandOutput);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Filter
|
||||||
|
TextRange range = cmd.getTextRange(editor, context, false);
|
||||||
return VimPlugin.getProcess().executeFilter(editor, range, command);
|
return VimPlugin.getProcess().executeFilter(editor, range, command);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
}
|
||||||
throw new ExException(e.getMessage());
|
catch (IOException e) {
|
||||||
}
|
throw new ExException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,7 +26,6 @@ import com.maddyhome.idea.vim.common.TextRange;
|
|||||||
import com.maddyhome.idea.vim.ex.CommandHandler;
|
import com.maddyhome.idea.vim.ex.CommandHandler;
|
||||||
import com.maddyhome.idea.vim.ex.ExCommand;
|
import com.maddyhome.idea.vim.ex.ExCommand;
|
||||||
import com.maddyhome.idea.vim.ex.ExException;
|
import com.maddyhome.idea.vim.ex.ExException;
|
||||||
import com.maddyhome.idea.vim.group.RegisterGroup;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +38,7 @@ public class DeleteLinesHandler extends CommandHandler {
|
|||||||
|
|
||||||
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
||||||
StringBuilder arg = new StringBuilder(cmd.getArgument());
|
StringBuilder arg = new StringBuilder(cmd.getArgument());
|
||||||
char register = RegisterGroup.REGISTER_DEFAULT;
|
char register = VimPlugin.getRegister().getDefaultRegister();
|
||||||
if (arg.length() > 0 && (arg.charAt(0) < '0' || arg.charAt(0) > '9')) {
|
if (arg.length() > 0 && (arg.charAt(0) < '0' || arg.charAt(0) > '9')) {
|
||||||
register = arg.charAt(0);
|
register = arg.charAt(0);
|
||||||
arg.deleteCharAt(0);
|
arg.deleteCharAt(0);
|
||||||
|
@@ -49,7 +49,7 @@ public class PutLinesHandler extends CommandHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
registerGroup.selectRegister(RegisterGroup.REGISTER_DEFAULT);
|
registerGroup.selectRegister(registerGroup.getDefaultRegister());
|
||||||
}
|
}
|
||||||
|
|
||||||
final int offset = EditorHelper.getLineStartOffset(editor, line + 1);
|
final int offset = EditorHelper.getLineStartOffset(editor, line + 1);
|
||||||
|
@@ -26,7 +26,6 @@ import com.maddyhome.idea.vim.common.TextRange;
|
|||||||
import com.maddyhome.idea.vim.ex.CommandHandler;
|
import com.maddyhome.idea.vim.ex.CommandHandler;
|
||||||
import com.maddyhome.idea.vim.ex.ExCommand;
|
import com.maddyhome.idea.vim.ex.ExCommand;
|
||||||
import com.maddyhome.idea.vim.ex.ExException;
|
import com.maddyhome.idea.vim.ex.ExException;
|
||||||
import com.maddyhome.idea.vim.group.RegisterGroup;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +38,7 @@ public class YankLinesHandler extends CommandHandler {
|
|||||||
|
|
||||||
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, @NotNull ExCommand cmd) throws ExException {
|
||||||
StringBuilder arg = new StringBuilder(cmd.getArgument());
|
StringBuilder arg = new StringBuilder(cmd.getArgument());
|
||||||
char register = RegisterGroup.REGISTER_DEFAULT;
|
char register = VimPlugin.getRegister().getDefaultRegister();
|
||||||
if (arg.length() > 0 && (arg.charAt(0) < '0' || arg.charAt(0) > '9')) {
|
if (arg.length() > 0 && (arg.charAt(0) < '0' || arg.charAt(0) > '9')) {
|
||||||
register = arg.charAt(0);
|
register = arg.charAt(0);
|
||||||
arg.deleteCharAt(0);
|
arg.deleteCharAt(0);
|
||||||
|
@@ -17,10 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.maddyhome.idea.vim.group;
|
package com.maddyhome.idea.vim.group;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.intellij.openapi.actionSystem.ActionManager;
|
import com.intellij.openapi.actionSystem.ActionManager;
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
@@ -36,6 +33,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
|||||||
import com.intellij.openapi.fileTypes.FileType;
|
import com.intellij.openapi.fileTypes.FileType;
|
||||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||||
@@ -54,10 +52,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides all the insert/replace related functionality
|
* Provides all the insert/replace related functionality
|
||||||
@@ -385,6 +380,8 @@ public class ChangeGroup {
|
|||||||
public void documentChanged(@NotNull DocumentEvent e) {
|
public void documentChanged(@NotNull DocumentEvent e) {
|
||||||
final String newFragment = e.getNewFragment().toString();
|
final String newFragment = e.getNewFragment().toString();
|
||||||
final String oldFragment = e.getOldFragment().toString();
|
final String oldFragment = e.getOldFragment().toString();
|
||||||
|
final int newFragmentLength = newFragment.length();
|
||||||
|
final int oldFragmentLength = oldFragment.length();
|
||||||
|
|
||||||
// Repeat buffer limits
|
// Repeat buffer limits
|
||||||
if (repeatCharsCount > MAX_REPEAT_CHARS_COUNT) {
|
if (repeatCharsCount > MAX_REPEAT_CHARS_COUNT) {
|
||||||
@@ -394,41 +391,46 @@ public class ChangeGroup {
|
|||||||
// <Enter> is added to strokes as an action during processing in order to indent code properly in the repeat
|
// <Enter> is added to strokes as an action during processing in order to indent code properly in the repeat
|
||||||
// command
|
// command
|
||||||
if (newFragment.startsWith("\n") && newFragment.trim().isEmpty()) {
|
if (newFragment.startsWith("\n") && newFragment.trim().isEmpty()) {
|
||||||
|
strokes.addAll(getAdjustCaretActions(e));
|
||||||
|
oldOffset = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore multi-character indents as they should be inserted automatically while repeating <Enter> actions
|
// Ignore multi-character indents as they should be inserted automatically while repeating <Enter> actions
|
||||||
if (newFragment.length() > 1 && newFragment.trim().isEmpty()) {
|
if (newFragmentLength > 1 && newFragment.trim().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int delta = e.getOffset() + oldFragment.length() - oldOffset;
|
strokes.addAll(getAdjustCaretActions(e));
|
||||||
|
|
||||||
|
if (oldFragmentLength > 0) {
|
||||||
|
final AnAction editorDelete = ActionManager.getInstance().getAction("EditorDelete");
|
||||||
|
for (int i = 0; i < oldFragmentLength; i++) {
|
||||||
|
strokes.add(editorDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFragmentLength > 0) {
|
||||||
|
strokes.add(newFragment.toCharArray());
|
||||||
|
}
|
||||||
|
repeatCharsCount += newFragmentLength;
|
||||||
|
oldOffset = e.getOffset() + newFragmentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private List<AnAction> getAdjustCaretActions(DocumentEvent e) {
|
||||||
|
final int delta = e.getOffset() - oldOffset;
|
||||||
if (oldOffset >= 0 && delta != 0) {
|
if (oldOffset >= 0 && delta != 0) {
|
||||||
|
final List<AnAction> positionCaretActions = new ArrayList<AnAction>();
|
||||||
final String motionName = delta < 0 ? "VimMotionLeft" : "VimMotionRight";
|
final String motionName = delta < 0 ? "VimMotionLeft" : "VimMotionRight";
|
||||||
final AnAction action = ActionManager.getInstance().getAction(motionName);
|
final AnAction action = ActionManager.getInstance().getAction(motionName);
|
||||||
final int count = Math.abs(delta);
|
final int count = Math.abs(delta);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
strokes.add(action);
|
positionCaretActions.add(action);
|
||||||
}
|
}
|
||||||
|
return positionCaretActions;
|
||||||
}
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
if (oldFragment.length() > 0) {
|
|
||||||
final AnAction editorBackSpace = ActionManager.getInstance().getAction("EditorBackSpace");
|
|
||||||
for (int i = 0; i < oldFragment.length(); i++) {
|
|
||||||
strokes.add(editorBackSpace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strokes.add(newFragment.toCharArray());
|
|
||||||
repeatCharsCount += newFragment.length();
|
|
||||||
|
|
||||||
if (newFragment.length() > 0) {
|
|
||||||
// TODO: If newFragment is shorter than oldFragment?
|
|
||||||
oldOffset = e.getOffset() + newFragment.length();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
oldOffset = e.getOffset() - oldFragment.length();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,9 +498,7 @@ public class ChangeGroup {
|
|||||||
}
|
}
|
||||||
else if (lastStroke instanceof char[]) {
|
else if (lastStroke instanceof char[]) {
|
||||||
final char[] chars = (char[])lastStroke;
|
final char[] chars = (char[])lastStroke;
|
||||||
for (char c : chars) {
|
insertText(editor, editor.getCaretModel().getOffset(), new String(chars));
|
||||||
processKey(editor, context, KeyStroke.getKeyStroke(c));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,8 +546,10 @@ public class ChangeGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the user pressing the Enter key. If this is REPLACE mode we need to turn off OVERWRITE before and
|
* Processes the Enter key by running the first successful action registered for "ENTER" keystroke.
|
||||||
* then turn OVERWRITE back on after sending the "Enter" key.
|
*
|
||||||
|
* If this is REPLACE mode we need to turn off OVERWRITE before and then turn OVERWRITE back on after sending the
|
||||||
|
* "ENTER" key.
|
||||||
*
|
*
|
||||||
* @param editor The editor to press "Enter" in
|
* @param editor The editor to press "Enter" in
|
||||||
* @param context The data context
|
* @param context The data context
|
||||||
@@ -556,7 +558,13 @@ public class ChangeGroup {
|
|||||||
if (CommandState.getInstance(editor).getMode() == CommandState.Mode.REPLACE) {
|
if (CommandState.getInstance(editor).getMode() == CommandState.Mode.REPLACE) {
|
||||||
KeyHandler.executeAction("EditorToggleInsertState", context);
|
KeyHandler.executeAction("EditorToggleInsertState", context);
|
||||||
}
|
}
|
||||||
KeyHandler.executeAction("EditorEnter", context);
|
final KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
||||||
|
final List<AnAction> actions = VimPlugin.getKey().getActions(editor.getComponent(), enterKeyStroke);
|
||||||
|
for (AnAction action : actions) {
|
||||||
|
if (KeyHandler.executeAction(action, context)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (CommandState.getInstance(editor).getMode() == CommandState.Mode.REPLACE) {
|
if (CommandState.getInstance(editor).getMode() == CommandState.Mode.REPLACE) {
|
||||||
KeyHandler.executeAction("EditorToggleInsertState", context);
|
KeyHandler.executeAction("EditorToggleInsertState", context);
|
||||||
}
|
}
|
||||||
@@ -1018,11 +1026,12 @@ public class ChangeGroup {
|
|||||||
* @return true if able to delete count lines, false if not
|
* @return true if able to delete count lines, false if not
|
||||||
*/
|
*/
|
||||||
public boolean changeLine(@NotNull Editor editor, @NotNull DataContext context, int count) {
|
public boolean changeLine(@NotNull Editor editor, @NotNull DataContext context, int count) {
|
||||||
|
final LogicalPosition pos = editor.offsetToLogicalPosition(editor.getCaretModel().getOffset());
|
||||||
|
final boolean insertBelow = pos.line + count >= EditorHelper.getLineCount(editor);
|
||||||
|
|
||||||
boolean res = deleteLine(editor, count);
|
boolean res = deleteLine(editor, count);
|
||||||
if (res) {
|
if (res) {
|
||||||
final int lastLine = EditorHelper.getLineCount(editor) - 1;
|
if (insertBelow) {
|
||||||
final LogicalPosition pos = editor.offsetToLogicalPosition(editor.getCaretModel().getOffset());
|
|
||||||
if (pos.line >= lastLine) {
|
|
||||||
insertNewLineBelow(editor, context);
|
insertNewLineBelow(editor, context);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1070,13 +1079,13 @@ public class ChangeGroup {
|
|||||||
}
|
}
|
||||||
String id = ActionManager.getInstance().getId(motion.getAction());
|
String id = ActionManager.getInstance().getId(motion.getAction());
|
||||||
boolean kludge = false;
|
boolean kludge = false;
|
||||||
boolean bigWord = false;
|
boolean bigWord = id.equals("VimMotionBigWordRight");
|
||||||
final CharSequence chars = editor.getDocument().getCharsSequence();
|
final CharSequence chars = editor.getDocument().getCharsSequence();
|
||||||
final int offset = editor.getCaretModel().getOffset();
|
final int offset = editor.getCaretModel().getOffset();
|
||||||
final CharacterHelper.CharacterType charType = CharacterHelper.charType(chars.charAt(offset), false);
|
final CharacterHelper.CharacterType charType = CharacterHelper.charType(chars.charAt(offset), bigWord);
|
||||||
if (EditorHelper.getFileSize(editor) > 0 && charType != CharacterHelper.CharacterType.WHITESPACE) {
|
if (EditorHelper.getFileSize(editor) > 0 && charType != CharacterHelper.CharacterType.WHITESPACE) {
|
||||||
final boolean lastWordChar = offset > EditorHelper.getFileSize(editor) ||
|
final boolean lastWordChar = offset > EditorHelper.getFileSize(editor) ||
|
||||||
CharacterHelper.charType(chars.charAt(offset + 1), false) != charType;
|
CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType;
|
||||||
final ImmutableSet<String> wordMotions = ImmutableSet.of(
|
final ImmutableSet<String> wordMotions = ImmutableSet.of(
|
||||||
"VimMotionWordRight", "VimMotionBigWordRight", "VimMotionCamelRight");
|
"VimMotionWordRight", "VimMotionBigWordRight", "VimMotionCamelRight");
|
||||||
if (wordMotions.contains(id) && lastWordChar) {
|
if (wordMotions.contains(id) && lastWordChar) {
|
||||||
@@ -1093,7 +1102,6 @@ public class ChangeGroup {
|
|||||||
}
|
}
|
||||||
else if (id.equals("VimMotionBigWordRight")) {
|
else if (id.equals("VimMotionBigWordRight")) {
|
||||||
kludge = true;
|
kludge = true;
|
||||||
bigWord = true;
|
|
||||||
motion.setAction(ActionManager.getInstance().getAction("VimMotionBigWordEndRight"));
|
motion.setAction(ActionManager.getInstance().getAction("VimMotionBigWordEndRight"));
|
||||||
motion.setFlags(Command.FLAG_MOT_INCLUSIVE);
|
motion.setFlags(Command.FLAG_MOT_INCLUSIVE);
|
||||||
}
|
}
|
||||||
@@ -1542,16 +1550,12 @@ public class ChangeGroup {
|
|||||||
private boolean sortTextRange(@NotNull Editor editor, int start, int end,
|
private boolean sortTextRange(@NotNull Editor editor, int start, int end,
|
||||||
@NotNull Comparator<String> lineComparator) {
|
@NotNull Comparator<String> lineComparator) {
|
||||||
final String selectedText = editor.getDocument().getText(new TextRangeInterval(start, end));
|
final String selectedText = editor.getDocument().getText(new TextRangeInterval(start, end));
|
||||||
final String lineSeparator = CodeStyleSettingsManager.getSettings(editor.getProject()).getLineSeparator();
|
final List<String> lines = Arrays.asList(StringUtil.splitByLines(selectedText));
|
||||||
final List<String> lines = Lists.newArrayList(Splitter.on(lineSeparator).split(selectedText));
|
|
||||||
|
|
||||||
if (lines.size() < 1) {
|
if (lines.size() < 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(lines, lineComparator);
|
Collections.sort(lines, lineComparator);
|
||||||
replaceText(editor, start, end, Joiner.on(lineSeparator).join(lines));
|
replaceText(editor, start, end, StringUtil.join(lines, "\n"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -162,7 +162,10 @@ public class CopyGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pos = editor.getCaretModel().getOffset() + 1;
|
pos = editor.getCaretModel().getOffset();
|
||||||
|
if (!EditorHelper.isLineEmpty(editor, editor.getCaretModel().getLogicalPosition().line, false)) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// In case when text is empty this can occur
|
// In case when text is empty this can occur
|
||||||
if (pos > 0 && pos > editor.getDocument().getTextLength()) {
|
if (pos > 0 && pos > editor.getDocument().getTextLength()) {
|
||||||
|
279
src/com/maddyhome/idea/vim/group/EditorGroup.java
Normal file
279
src/com/maddyhome/idea/vim/group/EditorGroup.java
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
package com.maddyhome.idea.vim.group;
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.editor.*;
|
||||||
|
import com.intellij.openapi.editor.colors.ColorKey;
|
||||||
|
import com.intellij.openapi.editor.colors.EditorColors;
|
||||||
|
import com.intellij.openapi.editor.colors.EditorFontType;
|
||||||
|
import com.intellij.openapi.editor.event.*;
|
||||||
|
import com.intellij.openapi.editor.ex.EditorEx;
|
||||||
|
import com.maddyhome.idea.vim.EventFacade;
|
||||||
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
|
import com.maddyhome.idea.vim.command.CommandState;
|
||||||
|
import com.maddyhome.idea.vim.helper.*;
|
||||||
|
import com.maddyhome.idea.vim.option.OptionChangeEvent;
|
||||||
|
import com.maddyhome.idea.vim.option.OptionChangeListener;
|
||||||
|
import com.maddyhome.idea.vim.option.Options;
|
||||||
|
import org.jdom.Element;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
public class EditorGroup {
|
||||||
|
private static final boolean BLOCK_CURSOR_VIM_VALUE = true;
|
||||||
|
private static final boolean ANIMATED_SCROLLING_VIM_VALUE = false;
|
||||||
|
private static final boolean REFRAIN_FROM_SCROLLING_VIM_VALUE = true;
|
||||||
|
|
||||||
|
private boolean isBlockCursor = false;
|
||||||
|
private boolean isAnimatedScrolling = false;
|
||||||
|
private boolean isRefrainFromScrolling = false;
|
||||||
|
private Boolean isKeyRepeat = null;
|
||||||
|
|
||||||
|
private final CaretListener myLineNumbersCaretListener = new CaretAdapter() {
|
||||||
|
@Override
|
||||||
|
public void caretPositionChanged(CaretEvent e) {
|
||||||
|
updateLineNumbers(e.getEditor());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final LineNumbersGutterProvider myLineNumbersGutterProvider = new LineNumbersGutterProvider();
|
||||||
|
|
||||||
|
public EditorGroup() {
|
||||||
|
final Options options = Options.getInstance();
|
||||||
|
final OptionChangeListener numbersChangeListener = new OptionChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void valueChange(OptionChangeEvent event) {
|
||||||
|
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||||
|
updateLineNumbers(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options.getOption(Options.NUMBER).addOptionChangeListener(numbersChangeListener);
|
||||||
|
options.getOption(Options.RELATIVE_NUMBER).addOptionChangeListener(numbersChangeListener);
|
||||||
|
|
||||||
|
EventFacade.getInstance().addEditorFactoryListener(new EditorFactoryAdapter() {
|
||||||
|
@Override
|
||||||
|
public void editorCreated(@NotNull EditorFactoryEvent event) {
|
||||||
|
final Editor editor = event.getEditor();
|
||||||
|
isBlockCursor = editor.getSettings().isBlockCursor();
|
||||||
|
isAnimatedScrolling = editor.getSettings().isAnimatedScrolling();
|
||||||
|
isRefrainFromScrolling = editor.getSettings().isRefrainFromScrolling();
|
||||||
|
EditorData.initializeEditor(editor);
|
||||||
|
DocumentManager.getInstance().addListeners(editor.getDocument());
|
||||||
|
VimPlugin.getKey().registerRequiredShortcutKeys(editor);
|
||||||
|
|
||||||
|
if (VimPlugin.isEnabled()) {
|
||||||
|
initLineNumbers(editor);
|
||||||
|
// Turn on insert mode if editor doesn't have any file
|
||||||
|
if (!EditorData.isFileEditor(editor) && editor.getDocument().isWritable() &&
|
||||||
|
!CommandState.inInsertMode(editor)) {
|
||||||
|
KeyHandler.getInstance().handleKey(editor, KeyStroke.getKeyStroke('i'), new EditorDataContext(editor));
|
||||||
|
}
|
||||||
|
editor.getSettings().setBlockCursor(!CommandState.inInsertMode(editor));
|
||||||
|
editor.getSettings().setAnimatedScrolling(ANIMATED_SCROLLING_VIM_VALUE);
|
||||||
|
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void editorReleased(@NotNull EditorFactoryEvent event) {
|
||||||
|
final Editor editor = event.getEditor();
|
||||||
|
deinitLineNumbers(editor);
|
||||||
|
EditorData.uninitializeEditor(editor);
|
||||||
|
VimPlugin.getKey().unregisterShortcutKeys(editor);
|
||||||
|
editor.getSettings().setAnimatedScrolling(isAnimatedScrolling);
|
||||||
|
editor.getSettings().setRefrainFromScrolling(isRefrainFromScrolling);
|
||||||
|
DocumentManager.getInstance().removeListeners(editor.getDocument());
|
||||||
|
}
|
||||||
|
}, ApplicationManager.getApplication());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void turnOn() {
|
||||||
|
setCursors(BLOCK_CURSOR_VIM_VALUE);
|
||||||
|
setAnimatedScrolling(ANIMATED_SCROLLING_VIM_VALUE);
|
||||||
|
setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
|
||||||
|
|
||||||
|
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||||
|
if (!EditorData.getEditorGroup(editor)) {
|
||||||
|
initLineNumbers(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void turnOff() {
|
||||||
|
setCursors(isBlockCursor);
|
||||||
|
setAnimatedScrolling(isAnimatedScrolling);
|
||||||
|
setRefrainFromScrolling(isRefrainFromScrolling);
|
||||||
|
|
||||||
|
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||||
|
deinitLineNumbers(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initLineNumbers(@NotNull final Editor editor) {
|
||||||
|
editor.getCaretModel().addCaretListener(myLineNumbersCaretListener);
|
||||||
|
EditorData.setEditorGroup(editor, true);
|
||||||
|
|
||||||
|
final EditorSettings settings = editor.getSettings();
|
||||||
|
EditorData.setLineNumbersShown(editor, settings.isLineNumbersShown());
|
||||||
|
updateLineNumbers(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deinitLineNumbers(@NotNull Editor editor) {
|
||||||
|
editor.getCaretModel().removeCaretListener(myLineNumbersCaretListener);
|
||||||
|
EditorData.setEditorGroup(editor, false);
|
||||||
|
|
||||||
|
editor.getGutter().closeAllAnnotations();
|
||||||
|
editor.getSettings().setLineNumbersShown(EditorData.isLineNumbersShown(editor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLineNumbers(@NotNull Editor editor) {
|
||||||
|
final Options options = Options.getInstance();
|
||||||
|
final boolean relativeLineNumber = options.isSet(Options.RELATIVE_NUMBER);
|
||||||
|
final boolean lineNumber = options.isSet(Options.NUMBER);
|
||||||
|
|
||||||
|
final EditorSettings settings = editor.getSettings();
|
||||||
|
settings.setLineNumbersShown(lineNumber && !relativeLineNumber);
|
||||||
|
|
||||||
|
if (relativeLineNumber) {
|
||||||
|
final EditorGutter gutter = editor.getGutter();
|
||||||
|
gutter.closeAllAnnotations();
|
||||||
|
gutter.registerTextAnnotation(myLineNumbersGutterProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCursors(boolean isBlock) {
|
||||||
|
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
||||||
|
for (Editor editor : editors) {
|
||||||
|
// Vim plugin should be turned on in insert mode
|
||||||
|
((EditorEx)editor).setInsertMode(true);
|
||||||
|
editor.getSettings().setBlockCursor(isBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAnimatedScrolling(boolean isOn) {
|
||||||
|
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
||||||
|
for (Editor editor : editors) {
|
||||||
|
editor.getSettings().setAnimatedScrolling(isOn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRefrainFromScrolling(boolean isOn) {
|
||||||
|
Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
||||||
|
for (Editor editor : editors) {
|
||||||
|
editor.getSettings().setRefrainFromScrolling(isOn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveData(@NotNull Element element) {
|
||||||
|
if (isKeyRepeat != null) {
|
||||||
|
final Element editor = new Element("editor");
|
||||||
|
element.addContent(editor);
|
||||||
|
final Element keyRepeat = new Element("key-repeat");
|
||||||
|
keyRepeat.setAttribute("enabled", Boolean.toString(isKeyRepeat));
|
||||||
|
editor.addContent(keyRepeat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readData(@NotNull Element element) {
|
||||||
|
final Element editor = element.getChild("editor");
|
||||||
|
if (editor != null) {
|
||||||
|
final Element keyRepeat = editor.getChild("key-repeat");
|
||||||
|
if (keyRepeat != null) {
|
||||||
|
final String enabled = keyRepeat.getAttributeValue("enabled");
|
||||||
|
if (enabled != null) {
|
||||||
|
isKeyRepeat = Boolean.valueOf(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Boolean isKeyRepeat() {
|
||||||
|
return isKeyRepeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyRepeat(@Nullable Boolean value) {
|
||||||
|
this.isKeyRepeat = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LineNumbersGutterProvider implements TextAnnotationGutterProvider {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getLineText(int line, @NotNull Editor editor) {
|
||||||
|
if (VimPlugin.isEnabled() && EditorData.isFileEditor(editor)) {
|
||||||
|
final Options options = Options.getInstance();
|
||||||
|
final boolean relativeLineNumber = options.isSet(Options.RELATIVE_NUMBER);
|
||||||
|
final boolean lineNumber = options.isSet(Options.NUMBER);
|
||||||
|
if (relativeLineNumber && lineNumber && isCaretLine(line, editor)) {
|
||||||
|
return lineNumberToString(getLineNumber(line), editor);
|
||||||
|
}
|
||||||
|
else if (relativeLineNumber) {
|
||||||
|
return lineNumberToString(getRelativeLineNumber(line, editor), editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCaretLine(int line, @NotNull Editor editor) {
|
||||||
|
return line == editor.getCaretModel().getLogicalPosition().line;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getLineNumber(int line) {
|
||||||
|
return line + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRelativeLineNumber(int line, @NotNull Editor editor) {
|
||||||
|
final int visualLine = EditorHelper.logicalLineToVisualLine(editor, line);
|
||||||
|
final int currentLine = editor.getCaretModel().getLogicalPosition().line;
|
||||||
|
final int currentVisualLine = EditorHelper.logicalLineToVisualLine(editor, currentLine);
|
||||||
|
return Math.abs(currentVisualLine - visualLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String lineNumberToString(int lineNumber, @NotNull Editor editor) {
|
||||||
|
final int lineCount = editor.getDocument().getLineCount();
|
||||||
|
final int digitsCount = (int)Math.ceil(Math.log10(lineCount));
|
||||||
|
return StringHelper.leftJustify("" + lineNumber, digitsCount, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getToolTip(int line, Editor editor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EditorFontType getStyle(int line, Editor editor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ColorKey getColor(int line, Editor editor) {
|
||||||
|
return EditorColors.LINE_NUMBERS_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Color getBgColor(int line, Editor editor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AnAction> getPopupActions(int line, Editor editor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void gutterClosed() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -21,9 +21,11 @@ package com.maddyhome.idea.vim.group;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.intellij.openapi.actionSystem.*;
|
import com.intellij.openapi.actionSystem.*;
|
||||||
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
||||||
|
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.EditorFactory;
|
import com.intellij.openapi.editor.EditorFactory;
|
||||||
import com.intellij.openapi.keymap.Keymap;
|
import com.intellij.openapi.keymap.Keymap;
|
||||||
|
import com.intellij.openapi.keymap.KeymapManager;
|
||||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
||||||
import com.maddyhome.idea.vim.EventFacade;
|
import com.maddyhome.idea.vim.EventFacade;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
@@ -41,8 +43,10 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.helper.StringHelper.leftJustify;
|
import static com.maddyhome.idea.vim.helper.StringHelper.leftJustify;
|
||||||
import static com.maddyhome.idea.vim.helper.StringHelper.toKeyNotation;
|
import static com.maddyhome.idea.vim.helper.StringHelper.toKeyNotation;
|
||||||
@@ -429,4 +433,48 @@ public class KeyGroup {
|
|||||||
// TODO: Add more codes
|
// TODO: Add more codes
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
|
||||||
|
final List<AnAction> results = new ArrayList<AnAction>();
|
||||||
|
results.addAll(getLocalActions(component, keyStroke));
|
||||||
|
results.addAll(getKeymapActions(keyStroke));
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static List<AnAction> getLocalActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
|
||||||
|
final List<AnAction> results = new ArrayList<AnAction>();
|
||||||
|
final KeyboardShortcut keyStrokeShortcut = new KeyboardShortcut(keyStroke, null);
|
||||||
|
for (Component c = component; c != null; c = c.getParent()) {
|
||||||
|
if (c instanceof JComponent) {
|
||||||
|
final List<AnAction> actions = ActionUtil.getActions((JComponent)c);
|
||||||
|
for (AnAction action : actions) {
|
||||||
|
if (action instanceof VimShortcutKeyAction) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final com.intellij.openapi.actionSystem.Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
|
||||||
|
for (com.intellij.openapi.actionSystem.Shortcut shortcut : shortcuts) {
|
||||||
|
if (shortcut.isKeyboard() && shortcut.startsWith(keyStrokeShortcut) && !results.contains(action)) {
|
||||||
|
results.add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static List<AnAction> getKeymapActions(@NotNull KeyStroke keyStroke) {
|
||||||
|
final List<AnAction> results = new ArrayList<AnAction>();
|
||||||
|
final Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
|
||||||
|
for (String id : keymap.getActionIds(keyStroke)) {
|
||||||
|
final AnAction action = ActionManager.getInstance().getAction(id);
|
||||||
|
if (action != null) {
|
||||||
|
results.add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -678,6 +678,7 @@ public class MotionGroup {
|
|||||||
|
|
||||||
public int repeatLastMatchChar(@NotNull Editor editor, int count) {
|
public int repeatLastMatchChar(@NotNull Editor editor, int count) {
|
||||||
int res = -1;
|
int res = -1;
|
||||||
|
int startPos = editor.getCaretModel().getOffset();
|
||||||
switch (lastFTCmd) {
|
switch (lastFTCmd) {
|
||||||
case LAST_F:
|
case LAST_F:
|
||||||
res = moveCaretToNextCharacterOnLine(editor, -count, lastFTChar);
|
res = moveCaretToNextCharacterOnLine(editor, -count, lastFTChar);
|
||||||
@@ -687,9 +688,15 @@ public class MotionGroup {
|
|||||||
break;
|
break;
|
||||||
case LAST_T:
|
case LAST_T:
|
||||||
res = moveCaretToBeforeNextCharacterOnLine(editor, -count, lastFTChar);
|
res = moveCaretToBeforeNextCharacterOnLine(editor, -count, lastFTChar);
|
||||||
|
if (res == startPos && Math.abs(count) == 1) {
|
||||||
|
res = moveCaretToBeforeNextCharacterOnLine(editor, 2 * count, lastFTChar);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case LAST_t:
|
case LAST_t:
|
||||||
res = moveCaretToBeforeNextCharacterOnLine(editor, count, lastFTChar);
|
res = moveCaretToBeforeNextCharacterOnLine(editor, count, lastFTChar);
|
||||||
|
if (res == startPos && Math.abs(count) == 1) {
|
||||||
|
res = moveCaretToBeforeNextCharacterOnLine(editor, 2 * count, lastFTChar);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1186,8 +1193,12 @@ public class MotionGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void moveCaret(@NotNull Editor editor, int offset) {
|
public static void moveCaret(@NotNull Editor editor, int offset) {
|
||||||
|
moveCaret(editor, offset, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void moveCaret(@NotNull Editor editor, int offset, boolean forceKeepVisual) {
|
||||||
if (offset >= 0 && offset <= editor.getDocument().getTextLength()) {
|
if (offset >= 0 && offset <= editor.getDocument().getTextLength()) {
|
||||||
final boolean keepVisual = keepVisual(editor);
|
final boolean keepVisual = forceKeepVisual || keepVisual(editor);
|
||||||
if (editor.getCaretModel().getOffset() != offset) {
|
if (editor.getCaretModel().getOffset() != offset) {
|
||||||
if (!keepVisual) {
|
if (!keepVisual) {
|
||||||
// XXX: Hack for preventing the merge multiple carets that results in loosing the primary caret for |v_d|
|
// XXX: Hack for preventing the merge multiple carets that results in loosing the primary caret for |v_d|
|
||||||
@@ -1461,7 +1472,7 @@ public class MotionGroup {
|
|||||||
CommandState.getInstance(editor).pushState(CommandState.Mode.VISUAL, mode, MappingMode.VISUAL);
|
CommandState.getInstance(editor).pushState(CommandState.Mode.VISUAL, mode, MappingMode.VISUAL);
|
||||||
visualStart = start;
|
visualStart = start;
|
||||||
updateSelection(editor, end);
|
updateSelection(editor, end);
|
||||||
MotionGroup.moveCaret(editor, visualEnd);
|
MotionGroup.moveCaret(editor, visualEnd, true);
|
||||||
}
|
}
|
||||||
else if (mode == currentMode) {
|
else if (mode == currentMode) {
|
||||||
exitVisual(editor);
|
exitVisual(editor);
|
||||||
@@ -1574,17 +1585,25 @@ public class MotionGroup {
|
|||||||
public TextRange getVisualRange(@NotNull Editor editor) {
|
public TextRange getVisualRange(@NotNull Editor editor) {
|
||||||
final TextRange res = new TextRange(editor.getSelectionModel().getBlockSelectionStarts(),
|
final TextRange res = new TextRange(editor.getSelectionModel().getBlockSelectionStarts(),
|
||||||
editor.getSelectionModel().getBlockSelectionEnds());
|
editor.getSelectionModel().getBlockSelectionEnds());
|
||||||
// If the last left/right motion was the $ command, simulate each line being selected to end-of-line
|
|
||||||
final CommandState.SubMode subMode = CommandState.getInstance(editor).getSubMode();
|
final CommandState.SubMode subMode = CommandState.getInstance(editor).getSubMode();
|
||||||
if (subMode == CommandState.SubMode.VISUAL_BLOCK && EditorData.getLastColumn(editor) >= MotionGroup.LAST_COLUMN) {
|
if (subMode == CommandState.SubMode.VISUAL_BLOCK) {
|
||||||
final int[] starts = res.getStartOffsets();
|
|
||||||
final int[] ends = res.getEndOffsets();
|
final int[] ends = res.getEndOffsets();
|
||||||
for (int i = 0; i < starts.length; i++) {
|
|
||||||
if (ends[i] > starts[i]) {
|
// If the last left/right motion was the $ command, simulate each line being selected to end-of-line
|
||||||
ends[i] = EditorHelper.getLineEndForOffset(editor, starts[i]);
|
if (EditorData.getLastColumn(editor) >= MotionGroup.LAST_COLUMN) {
|
||||||
|
final int[] starts = res.getStartOffsets();
|
||||||
|
for (int i = 0; i < starts.length; i++) {
|
||||||
|
if (ends[i] > starts[i]) {
|
||||||
|
ends[i] = EditorHelper.getLineEndForOffset(editor, starts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < ends.length; ++i) {
|
||||||
|
ends[i] = EditorHelper.normalizeOffset(editor, ends[i] + 1, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new TextRange(starts, ends);
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -1775,7 +1794,7 @@ public class MotionGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable private Editor dragEditor = null;
|
@Nullable private Editor dragEditor = null;
|
||||||
@NotNull private CommandState.SubMode mode;
|
@NotNull private CommandState.SubMode mode = CommandState.SubMode.NONE;
|
||||||
private int startOff;
|
private int startOff;
|
||||||
private int endOff;
|
private int endOff;
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ import com.intellij.openapi.editor.Editor;
|
|||||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.util.text.CharSequenceReader;
|
||||||
import com.maddyhome.idea.vim.KeyHandler;
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.command.Command;
|
import com.maddyhome.idea.vim.command.Command;
|
||||||
@@ -37,6 +38,7 @@ import com.maddyhome.idea.vim.ex.ExException;
|
|||||||
import com.maddyhome.idea.vim.helper.EditorData;
|
import com.maddyhome.idea.vim.helper.EditorData;
|
||||||
import com.maddyhome.idea.vim.ui.ExEntryPanel;
|
import com.maddyhome.idea.vim.ui.ExEntryPanel;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -73,7 +75,7 @@ public class ProcessGroup {
|
|||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
VirtualFile vf = EditorData.getVirtualFile(editor);
|
VirtualFile vf = EditorData.getVirtualFile(editor);
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode() && vf != null) {
|
if (!ApplicationManager.getApplication().isUnitTestMode() && project != null && vf != null) {
|
||||||
FileEditorManager.getInstance(project).openFile(vf, true);
|
FileEditorManager.getInstance(project).openFile(vf, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +163,7 @@ public class ProcessGroup {
|
|||||||
// version 1050.
|
// version 1050.
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode() && (flg & CommandParser.RES_DONT_REOPEN) == 0) {
|
if (!ApplicationManager.getApplication().isUnitTestMode() && (flg & CommandParser.RES_DONT_REOPEN) == 0) {
|
||||||
VirtualFile vf = EditorData.getVirtualFile(editor);
|
VirtualFile vf = EditorData.getVirtualFile(editor);
|
||||||
if (vf != null) {
|
if (project != null && vf != null) {
|
||||||
FileEditorManager.getInstance(project).openFile(vf, true);
|
FileEditorManager.getInstance(project).openFile(vf, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +184,7 @@ public class ProcessGroup {
|
|||||||
public void run() {
|
public void run() {
|
||||||
//editor.getContentComponent().requestFocus();
|
//editor.getContentComponent().requestFocus();
|
||||||
VirtualFile vf = EditorData.getVirtualFile(editor);
|
VirtualFile vf = EditorData.getVirtualFile(editor);
|
||||||
if (vf != null) {
|
if (project != null && vf != null) {
|
||||||
FileEditorManager.getInstance(project).openFile(vf, true);
|
FileEditorManager.getInstance(project).openFile(vf, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,33 +224,37 @@ public class ProcessGroup {
|
|||||||
return initText;
|
return initText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean executeFilter(@NotNull Editor editor, @NotNull TextRange range, String command) throws IOException {
|
public boolean executeFilter(@NotNull Editor editor, @NotNull TextRange range,
|
||||||
if (logger.isDebugEnabled()) logger.debug("command=" + command);
|
@NotNull String command) throws IOException {
|
||||||
CharSequence chars = editor.getDocument().getCharsSequence();
|
final CharSequence charsSequence = editor.getDocument().getCharsSequence();
|
||||||
StringReader car = new StringReader(chars.subSequence(range.getStartOffset(),
|
final int startOffset = range.getStartOffset();
|
||||||
range.getEndOffset()).toString());
|
final int endOffset = range.getEndOffset();
|
||||||
StringWriter sw = new StringWriter();
|
final String output = executeCommand(command, charsSequence.subSequence(startOffset, endOffset));
|
||||||
|
editor.getDocument().replaceString(startOffset, endOffset, output);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug("about to create filter");
|
@NotNull
|
||||||
Process filter = Runtime.getRuntime().exec(command);
|
public String executeCommand(@NotNull String command, @Nullable CharSequence input) throws IOException {
|
||||||
logger.debug("filter created");
|
if (logger.isDebugEnabled()) {
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(filter.getOutputStream()));
|
logger.debug("command=" + command);
|
||||||
logger.debug("sending text");
|
}
|
||||||
copy(car, writer);
|
|
||||||
|
final Process process = Runtime.getRuntime().exec(command);
|
||||||
|
|
||||||
|
if (input != null) {
|
||||||
|
final BufferedWriter outputWriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
||||||
|
copy(new CharSequenceReader(input), outputWriter);
|
||||||
|
outputWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
copy(inputReader, writer);
|
||||||
writer.close();
|
writer.close();
|
||||||
logger.debug("sent");
|
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(filter.getInputStream()));
|
|
||||||
logger.debug("getting result");
|
|
||||||
copy(reader, sw);
|
|
||||||
sw.close();
|
|
||||||
logger.debug("received");
|
|
||||||
|
|
||||||
editor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), sw.toString());
|
|
||||||
|
|
||||||
lastCommand = command;
|
lastCommand = command;
|
||||||
|
return writer.toString();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copy(@NotNull Reader from, @NotNull Writer to) throws IOException {
|
private void copy(@NotNull Reader from, @NotNull Writer to) throws IOException {
|
||||||
|
@@ -18,8 +18,12 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.group;
|
package com.maddyhome.idea.vim.group;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
|
import com.intellij.util.Function;
|
||||||
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.command.CommandState;
|
import com.maddyhome.idea.vim.command.CommandState;
|
||||||
import com.maddyhome.idea.vim.command.SelectionType;
|
import com.maddyhome.idea.vim.command.SelectionType;
|
||||||
@@ -27,6 +31,10 @@ import com.maddyhome.idea.vim.common.Register;
|
|||||||
import com.maddyhome.idea.vim.common.TextRange;
|
import com.maddyhome.idea.vim.common.TextRange;
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper;
|
import com.maddyhome.idea.vim.helper.EditorHelper;
|
||||||
import com.maddyhome.idea.vim.helper.StringHelper;
|
import com.maddyhome.idea.vim.helper.StringHelper;
|
||||||
|
import com.maddyhome.idea.vim.option.ListOption;
|
||||||
|
import com.maddyhome.idea.vim.option.OptionChangeEvent;
|
||||||
|
import com.maddyhome.idea.vim.option.OptionChangeListener;
|
||||||
|
import com.maddyhome.idea.vim.option.Options;
|
||||||
import com.maddyhome.idea.vim.ui.ClipboardHandler;
|
import com.maddyhome.idea.vim.ui.ClipboardHandler;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -34,33 +42,45 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This group works with command associated with copying and pasting text
|
* This group works with command associated with copying and pasting text
|
||||||
*/
|
*/
|
||||||
public class RegisterGroup {
|
public class RegisterGroup {
|
||||||
/**
|
|
||||||
* The register key for the default register
|
|
||||||
*/
|
|
||||||
public static final char REGISTER_DEFAULT = '"';
|
|
||||||
|
|
||||||
private static final String WRITABLE_REGISTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-*+_/\"";
|
private static final String WRITABLE_REGISTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-*+_/\"";
|
||||||
private static final String READONLY_REGISTERS = ":.%#=/";
|
private static final String READONLY_REGISTERS = ":.%#=/";
|
||||||
private static final String RECORDABLE_REGISTER = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
private static final String RECORDABLE_REGISTER = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
private static final String PLAYBACK_REGISTER = RECORDABLE_REGISTER + "\".*+";
|
private static final String PLAYBACK_REGISTER = RECORDABLE_REGISTER + "\".*+";
|
||||||
private static final String VALID_REGISTERS = WRITABLE_REGISTERS + READONLY_REGISTERS;
|
private static final String VALID_REGISTERS = WRITABLE_REGISTERS + READONLY_REGISTERS;
|
||||||
|
private static final List<Character> CLIPBOARD_REGISTERS = ImmutableList.of('*', '+');
|
||||||
private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName());
|
private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName());
|
||||||
|
|
||||||
private char lastRegister = REGISTER_DEFAULT;
|
private char defaultRegister = '"';
|
||||||
|
private char lastRegister = defaultRegister;
|
||||||
@NotNull private final HashMap<Character, Register> registers = new HashMap<Character, Register>();
|
@NotNull private final HashMap<Character, Register> registers = new HashMap<Character, Register>();
|
||||||
private char recordRegister = 0;
|
private char recordRegister = 0;
|
||||||
@Nullable private List<KeyStroke> recordList = null;
|
@Nullable private List<KeyStroke> recordList = null;
|
||||||
public RegisterGroup() {}
|
|
||||||
|
public RegisterGroup() {
|
||||||
|
final ListOption clipboardOption = Options.getInstance().getListOption(Options.CLIPBOARD);
|
||||||
|
if (clipboardOption != null) {
|
||||||
|
clipboardOption.addOptionChangeListener(new OptionChangeListener() {
|
||||||
|
public void valueChange(OptionChangeEvent event) {
|
||||||
|
if (clipboardOption.contains("unnamed")) {
|
||||||
|
defaultRegister = '*';
|
||||||
|
}
|
||||||
|
else if (clipboardOption.contains("unnamedplus")) {
|
||||||
|
defaultRegister = '+';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defaultRegister = '"';
|
||||||
|
}
|
||||||
|
lastRegister = defaultRegister;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if the last selected register can be written to.
|
* Check to see if the last selected register can be written to.
|
||||||
@@ -91,7 +111,7 @@ public class RegisterGroup {
|
|||||||
* Reset the selected register back to the default register.
|
* Reset the selected register back to the default register.
|
||||||
*/
|
*/
|
||||||
public void resetRegister() {
|
public void resetRegister() {
|
||||||
lastRegister = REGISTER_DEFAULT;
|
lastRegister = defaultRegister;
|
||||||
logger.debug("register reset");
|
logger.debug("register reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +167,7 @@ public class RegisterGroup {
|
|||||||
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
|
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (register == '*' || register == '+') {
|
else if (CLIPBOARD_REGISTERS.contains(register)) {
|
||||||
ClipboardHandler.setClipboardText(text);
|
ClipboardHandler.setClipboardText(text);
|
||||||
}
|
}
|
||||||
// Put the text in the specified register
|
// Put the text in the specified register
|
||||||
@@ -157,8 +177,8 @@ public class RegisterGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also add it to the default register if the default wasn't specified
|
// Also add it to the default register if the default wasn't specified
|
||||||
if (register != REGISTER_DEFAULT && ".:/".indexOf(register) == -1) {
|
if (register != defaultRegister && ".:/".indexOf(register) == -1) {
|
||||||
registers.put(REGISTER_DEFAULT, new Register(REGISTER_DEFAULT, type, text));
|
registers.put(defaultRegister, new Register(defaultRegister, type, text));
|
||||||
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
|
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +201,7 @@ public class RegisterGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Yanks also go to register 0 if the default register was used
|
// Yanks also go to register 0 if the default register was used
|
||||||
else if (register == REGISTER_DEFAULT) {
|
else if (register == defaultRegister) {
|
||||||
registers.put('0', new Register('0', type, text));
|
registers.put('0', new Register('0', type, text));
|
||||||
if (logger.isDebugEnabled()) logger.debug("register '" + '0' + "' contains: \"" + text + "\"");
|
if (logger.isDebugEnabled()) logger.debug("register '" + '0' + "' contains: \"" + text + "\"");
|
||||||
}
|
}
|
||||||
@@ -220,19 +240,7 @@ public class RegisterGroup {
|
|||||||
if (Character.isUpperCase(r)) {
|
if (Character.isUpperCase(r)) {
|
||||||
r = Character.toLowerCase(r);
|
r = Character.toLowerCase(r);
|
||||||
}
|
}
|
||||||
|
return CLIPBOARD_REGISTERS.contains(r) ? refreshClipboardRegister(r) : registers.get(new Character(r));
|
||||||
Register reg = null;
|
|
||||||
if (r == '*' || r == '+') {
|
|
||||||
String text = ClipboardHandler.getClipboardText();
|
|
||||||
if (text != null) {
|
|
||||||
reg = new Register(r, SelectionType.CHARACTER_WISE, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reg = registers.get(new Character(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,11 +252,23 @@ public class RegisterGroup {
|
|||||||
return lastRegister;
|
return lastRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The register key for the default register.
|
||||||
|
*/
|
||||||
|
public char getDefaultRegister() {
|
||||||
|
return defaultRegister;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<Register> getRegisters() {
|
public List<Register> getRegisters() {
|
||||||
ArrayList<Register> res = new ArrayList<Register>(registers.values());
|
final List<Register> res = new ArrayList<Register>(registers.values());
|
||||||
|
for (Character r : CLIPBOARD_REGISTERS) {
|
||||||
|
final Register register = refreshClipboardRegister(r);
|
||||||
|
if (register != null) {
|
||||||
|
res.add(register);
|
||||||
|
}
|
||||||
|
}
|
||||||
Collections.sort(res, new Register.KeySorter<Register>());
|
Collections.sort(res, new Register.KeySorter<Register>());
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,4 +395,33 @@ public class RegisterGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Register refreshClipboardRegister(char r) {
|
||||||
|
final String text = ClipboardHandler.getClipboardText();
|
||||||
|
if (text != null) {
|
||||||
|
return new Register(r, guessSelectionType(text), text);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private SelectionType guessSelectionType(@NotNull String text) {
|
||||||
|
final String[] lines = StringUtil.splitByLines(text);
|
||||||
|
final HashSet<Integer> lengths = new HashSet<Integer>(ContainerUtil.map(lines, new Function<String, Integer>() {
|
||||||
|
@Override
|
||||||
|
public Integer fun(String s) {
|
||||||
|
return s.length();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (lines.length > 1 && lengths.size() == 1) {
|
||||||
|
return SelectionType.BLOCK_WISE;
|
||||||
|
}
|
||||||
|
else if (text.endsWith("\n")) {
|
||||||
|
return SelectionType.LINE_WISE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SelectionType.CHARACTER_WISE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -187,6 +187,22 @@ public class EditorData {
|
|||||||
editor.putUserData(MOTION_GROUP, adapter);
|
editor.putUserData(MOTION_GROUP, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean getEditorGroup(@NotNull Editor editor) {
|
||||||
|
return editor.getUserData(EDITOR_GROUP) == Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setEditorGroup(@NotNull Editor editor, boolean value) {
|
||||||
|
editor.putUserData(EDITOR_GROUP, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLineNumbersShown(@NotNull Editor editor) {
|
||||||
|
return editor.getUserData(LINE_NUMBERS_SHOWN) == Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLineNumbersShown(@NotNull Editor editor, boolean value) {
|
||||||
|
editor.putUserData(LINE_NUMBERS_SHOWN, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isConsoleOutput(@NotNull Editor editor) {
|
public static boolean isConsoleOutput(@NotNull Editor editor) {
|
||||||
Object res = editor.getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);
|
Object res = editor.getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);
|
||||||
logger.debug("isConsoleOutput for editor " + editor + " - " + res);
|
logger.debug("isConsoleOutput for editor " + editor + " - " + res);
|
||||||
@@ -238,6 +254,8 @@ public class EditorData {
|
|||||||
private static final Key<CommandState> COMMAND_STATE = new Key<CommandState>("commandState");
|
private static final Key<CommandState> COMMAND_STATE = new Key<CommandState>("commandState");
|
||||||
private static final Key<Boolean> CHANGE_GROUP = new Key<Boolean>("changeGroup");
|
private static final Key<Boolean> CHANGE_GROUP = new Key<Boolean>("changeGroup");
|
||||||
private static final Key<Boolean> MOTION_GROUP = new Key<Boolean>("motionGroup");
|
private static final Key<Boolean> MOTION_GROUP = new Key<Boolean>("motionGroup");
|
||||||
|
public static final Key<Boolean> EDITOR_GROUP = new Key<Boolean>("editorGroup");
|
||||||
|
public static final Key<Boolean> LINE_NUMBERS_SHOWN = new Key<Boolean>("lineNumbersShown");
|
||||||
private static final Key<ExOutputPanel> MORE_PANEL = new Key<ExOutputPanel>("IdeaVim.morePanel");
|
private static final Key<ExOutputPanel> MORE_PANEL = new Key<ExOutputPanel>("IdeaVim.morePanel");
|
||||||
private static final Key<ExOutputModel> EX_OUTPUT_MODEL = new Key<ExOutputModel>("IdeaVim.exOutputModel");
|
private static final Key<ExOutputModel> EX_OUTPUT_MODEL = new Key<ExOutputModel>("IdeaVim.exOutputModel");
|
||||||
|
|
||||||
|
@@ -113,6 +113,9 @@ public class SearchHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bend = findBlockLocation(chars, type, close, 1, bstart + 1, 1);
|
int bend = findBlockLocation(chars, type, close, 1, bstart + 1, 1);
|
||||||
|
if (bend == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isOuter) {
|
if (!isOuter) {
|
||||||
bstart++;
|
bstart++;
|
||||||
@@ -530,7 +533,7 @@ public class SearchHelper {
|
|||||||
if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && !spaceWords) {
|
if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && !spaceWords) {
|
||||||
pos = skipSpace(chars, pos - 1, step, size) + 1;
|
pos = skipSpace(chars, pos - 1, step, size) + 1;
|
||||||
}
|
}
|
||||||
if (CharacterHelper.charType(chars.charAt(pos), bigWord) != CharacterHelper.charType(chars.charAt(pos - 1), bigWord)) {
|
if (pos > 0 && CharacterHelper.charType(chars.charAt(pos), bigWord) != CharacterHelper.charType(chars.charAt(pos - 1), bigWord)) {
|
||||||
pos += step;
|
pos += step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1272,7 +1275,7 @@ public class SearchHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ch == '\n') {
|
else if (ch == '\n') {
|
||||||
int end = offset; // Save where we found the punctuation.
|
int end = offset; // Save where we found the newline.
|
||||||
if (dir > 0) {
|
if (dir > 0) {
|
||||||
offset++;
|
offset++;
|
||||||
while (offset < max) {
|
while (offset < max) {
|
||||||
@@ -1305,15 +1308,17 @@ public class SearchHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
offset--;
|
if (offset > 0) {
|
||||||
while (offset >= 0) {
|
|
||||||
ch = chars.charAt(offset);
|
|
||||||
if (ch != '\n') {
|
|
||||||
offset++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset--;
|
offset--;
|
||||||
|
while (offset >= 0) {
|
||||||
|
ch = chars.charAt(offset);
|
||||||
|
if (ch != '\n') {
|
||||||
|
offset++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset < end) {
|
if (offset < end) {
|
||||||
|
@@ -33,6 +33,10 @@ import java.util.*;
|
|||||||
* Maintains the set of support options
|
* Maintains the set of support options
|
||||||
*/
|
*/
|
||||||
public class Options {
|
public class Options {
|
||||||
|
public static final String RELATIVE_NUMBER = "relativenumber";
|
||||||
|
public static final String NUMBER = "number";
|
||||||
|
public static final String CLIPBOARD = "clipboard";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the singleton instance of the options
|
* Gets the singleton instance of the options
|
||||||
*
|
*
|
||||||
@@ -80,6 +84,15 @@ public class Options {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ListOption getListOption(@NotNull String name) {
|
||||||
|
final Option option = getOption(name);
|
||||||
|
if (option instanceof ListOption) {
|
||||||
|
return (ListOption)option;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all options
|
* Gets all options
|
||||||
*
|
*
|
||||||
@@ -447,6 +460,9 @@ public class Options {
|
|||||||
addOption(new NumberOption("undolevels", "ul", 1000, -1, Integer.MAX_VALUE));
|
addOption(new NumberOption("undolevels", "ul", 1000, -1, Integer.MAX_VALUE));
|
||||||
addOption(new ToggleOption("visualbell", "vb", false));
|
addOption(new ToggleOption("visualbell", "vb", false));
|
||||||
addOption(new ToggleOption("wrapscan", "ws", true));
|
addOption(new ToggleOption("wrapscan", "ws", true));
|
||||||
|
addOption(new ToggleOption(NUMBER, "nu", false));
|
||||||
|
addOption(new ToggleOption(RELATIVE_NUMBER, "rnu", false));
|
||||||
|
addOption(new ListOption(CLIPBOARD, "cb", new String[]{"autoselect,exclude:cons\\|linux"}, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOption(@NotNull Option option) {
|
private void addOption(@NotNull Option option) {
|
||||||
|
@@ -114,7 +114,7 @@ public class ExEntryPanel extends JPanel {
|
|||||||
oldGlass.addComponentListener(adapter);
|
oldGlass.addComponentListener(adapter);
|
||||||
positionPanel();
|
positionPanel();
|
||||||
oldGlass.setVisible(true);
|
oldGlass.setVisible(true);
|
||||||
entry.requestFocus();
|
entry.requestFocusInWindow();
|
||||||
}
|
}
|
||||||
active = true;
|
active = true;
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,8 @@ import javax.swing.*;
|
|||||||
import javax.swing.text.Document;
|
import javax.swing.text.Document;
|
||||||
import javax.swing.text.Keymap;
|
import javax.swing.text.Keymap;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -59,6 +61,16 @@ public class ExTextField extends JTextField {
|
|||||||
loadKeymap(map, ExKeyBindings.getBindings(), actions);
|
loadKeymap(map, ExKeyBindings.getBindings(), actions);
|
||||||
map.setDefaultAction(new ExEditorKit.DefaultExKeyHandler());
|
map.setDefaultAction(new ExEditorKit.DefaultExKeyHandler());
|
||||||
setKeymap(map);
|
setKeymap(map);
|
||||||
|
addFocusListener(new FocusListener() {
|
||||||
|
@Override
|
||||||
|
public void focusGained(FocusEvent e) {
|
||||||
|
setCaretPosition(getText().length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void focusLost(FocusEvent e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//origCaret = getCaret();
|
//origCaret = getCaret();
|
||||||
//blockCaret = new BlockCaret();
|
//blockCaret = new BlockCaret();
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.plugins.ideavim;
|
package org.jetbrains.plugins.ideavim;
|
||||||
|
|
||||||
|
import com.intellij.ide.highlighter.JavaFileType;
|
||||||
import com.intellij.openapi.application.PathManager;
|
import com.intellij.openapi.application.PathManager;
|
||||||
import com.intellij.openapi.editor.Caret;
|
import com.intellij.openapi.editor.Caret;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
@@ -83,6 +84,12 @@ public abstract class VimTestCase extends UsefulTestCase {
|
|||||||
return myFixture.getEditor();
|
return myFixture.getEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected Editor configureByJavaText(@NotNull String content) {
|
||||||
|
myFixture.configureByText(JavaFileType.INSTANCE, content);
|
||||||
|
return myFixture.getEditor();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
protected Editor typeText(@NotNull final List<KeyStroke> keys) {
|
protected Editor typeText(@NotNull final List<KeyStroke> keys) {
|
||||||
final Editor editor = myFixture.getEditor();
|
final Editor editor = myFixture.getEditor();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.plugins.ideavim.action;
|
package org.jetbrains.plugins.ideavim.action;
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.fileTypes.PlainTextFileType;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.maddyhome.idea.vim.KeyHandler;
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
@@ -20,20 +21,12 @@ import static com.maddyhome.idea.vim.helper.StringHelper.stringToKeys;
|
|||||||
public class ChangeActionTest extends VimTestCase {
|
public class ChangeActionTest extends VimTestCase {
|
||||||
// |c| |t|
|
// |c| |t|
|
||||||
public void testChangeLinesTillForwards() {
|
public void testChangeLinesTillForwards() {
|
||||||
doTest(parseKeys("ct(", "for "),
|
doTest(parseKeys("ct(", "for "), "<caret>if (condition) {\n" + "}\n", "for (condition) {\n" + "}\n");
|
||||||
"<caret>if (condition) {\n" +
|
|
||||||
"}\n",
|
|
||||||
"for (condition) {\n" +
|
|
||||||
"}\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-276 |c| |T|
|
// VIM-276 |c| |T|
|
||||||
public void testChangeLinesTillBackwards() {
|
public void testChangeLinesTillBackwards() {
|
||||||
doTest(parseKeys("cT("),
|
doTest(parseKeys("cT("), "if (condition) {<caret>\n" + "}\n", "if (\n" + "}\n");
|
||||||
"if (condition) {<caret>\n" +
|
|
||||||
"}\n",
|
|
||||||
"if (\n" +
|
|
||||||
"}\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-276 |c| |F|
|
// VIM-276 |c| |F|
|
||||||
@@ -67,9 +60,7 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
|
|
||||||
// VIM-157 |~|
|
// VIM-157 |~|
|
||||||
public void testToggleCharCase() {
|
public void testToggleCharCase() {
|
||||||
doTest(parseKeys("~~"),
|
doTest(parseKeys("~~"), "<caret>hello world\n", "HEllo world\n");
|
||||||
"<caret>hello world\n",
|
|
||||||
"HEllo world\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-157 |~|
|
// VIM-157 |~|
|
||||||
@@ -100,11 +91,7 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
|
|
||||||
// |d| |w|
|
// |d| |w|
|
||||||
public void testDeleteLastWordBeforeEOL() {
|
public void testDeleteLastWordBeforeEOL() {
|
||||||
doTest(parseKeys("dw"),
|
doTest(parseKeys("dw"), "one <caret>two\n" + "three\n", "one \n" + "three\n");
|
||||||
"one <caret>two\n" +
|
|
||||||
"three\n",
|
|
||||||
"one \n" +
|
|
||||||
"three\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-105 |d| |w|
|
// VIM-105 |d| |w|
|
||||||
@@ -128,17 +115,17 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
|
|
||||||
// VIM-105 |d| |w| |count|
|
// VIM-105 |d| |w| |count|
|
||||||
public void testDeleteTwoWordsOnTwoLines() {
|
public void testDeleteTwoWordsOnTwoLines() {
|
||||||
doTest(parseKeys("d2w"),
|
doTest(parseKeys("d2w"), "one <caret>two\n" + "three four\n", "one four\n");
|
||||||
"one <caret>two\n" +
|
|
||||||
"three four\n",
|
|
||||||
"one four\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-200 |c| |w|
|
// VIM-200 |c| |w|
|
||||||
public void testChangeWordAtLastChar() {
|
public void testChangeWordAtLastChar() {
|
||||||
doTest(parseKeys("cw"),
|
doTest(parseKeys("cw"), "on<caret>e two three\n", "on two three\n");
|
||||||
"on<caret>e two three\n",
|
}
|
||||||
"on two three\n");
|
|
||||||
|
// VIM-515 |c| |W|
|
||||||
|
public void testChangeBigWordWithPunctuationAndAlpha() {
|
||||||
|
doTest(parseKeys("cW"), "foo<caret>(bar baz\n", "foo baz\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-300 |c| |w|
|
// VIM-300 |c| |w|
|
||||||
@@ -156,13 +143,18 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
assertOffset(4);
|
assertOffset(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-536 |cc|
|
||||||
|
public void testChangeLineAtSecondLastLine() {
|
||||||
|
doTest(parseKeys("ccbaz"),
|
||||||
|
"<caret>foo\n" +
|
||||||
|
"bar\n",
|
||||||
|
"baz\n" +
|
||||||
|
"bar\n");
|
||||||
|
}
|
||||||
|
|
||||||
// VIM-394 |d| |v_aw|
|
// VIM-394 |d| |v_aw|
|
||||||
public void testDeleteIndentedWordBeforePunctuation() {
|
public void testDeleteIndentedWordBeforePunctuation() {
|
||||||
doTest(parseKeys("daw"),
|
doTest(parseKeys("daw"), "foo\n" + " <caret>bar, baz\n", "foo\n" + " , baz\n");
|
||||||
"foo\n" +
|
|
||||||
" <caret>bar, baz\n",
|
|
||||||
"foo\n" +
|
|
||||||
" , baz\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// |d| |v_aw|
|
// |d| |v_aw|
|
||||||
@@ -182,18 +174,13 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
|
|
||||||
// VIM-393 |d|
|
// VIM-393 |d|
|
||||||
public void testDeleteBadArgument() {
|
public void testDeleteBadArgument() {
|
||||||
doTest(parseKeys("dD", "dd"),
|
doTest(parseKeys("dD", "dd"), "one\n" + "two\n", "two\n");
|
||||||
"one\n" +
|
|
||||||
"two\n",
|
|
||||||
"two\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-262 |i_CTRL-R|
|
// VIM-262 |i_CTRL-R|
|
||||||
public void testInsertFromRegister() {
|
public void testInsertFromRegister() {
|
||||||
VimPlugin.getRegister().setKeys('a', stringToKeys("World"));
|
VimPlugin.getRegister().setKeys('a', stringToKeys("World"));
|
||||||
doTest(parseKeys("A", ", ", "<C-R>", "a", "!"),
|
doTest(parseKeys("A", ", ", "<C-R>", "a", "!"), "<caret>Hello\n", "Hello, World!\n");
|
||||||
"<caret>Hello\n",
|
|
||||||
"Hello, World!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-421 |c| |w|
|
// VIM-421 |c| |w|
|
||||||
@@ -212,9 +199,7 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
|
|
||||||
// VIM-421 |c| |w|
|
// VIM-421 |c| |w|
|
||||||
public void testChangeLastCharInLine() {
|
public void testChangeLastCharInLine() {
|
||||||
doTest(parseKeys("cw"),
|
doTest(parseKeys("cw"), "fo<caret>o\n", "fo<caret>\n");
|
||||||
"fo<caret>o\n",
|
|
||||||
"fo<caret>\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIM-404 |O|
|
// VIM-404 |O|
|
||||||
@@ -270,14 +255,83 @@ public class ChangeActionTest extends VimTestCase {
|
|||||||
"bar\n" +
|
"bar\n" +
|
||||||
"baz\n" +
|
"baz\n" +
|
||||||
"quux\n",
|
"quux\n",
|
||||||
"<caret>oo\n" +
|
"<caret>o\n" +
|
||||||
"ar\n" +
|
"r\n" +
|
||||||
"az\n" +
|
"z\n" +
|
||||||
"quux\n");
|
"quux\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testDeleteCharVisualBlock() {
|
||||||
|
doTest(parseKeys("<C-V>", "jjl", "x"),
|
||||||
|
"<caret>foo\n" +
|
||||||
|
"bar\n" +
|
||||||
|
"baz\n" +
|
||||||
|
"quux\n",
|
||||||
|
"<caret>o\n" +
|
||||||
|
"r\n" +
|
||||||
|
"z\n" +
|
||||||
|
"quux\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-511 |.|
|
||||||
|
public void testRepeatWithBackspaces() {
|
||||||
|
doTest(parseKeys("ce", "foo", "<BS><BS><BS>", "foo", "<Esc>", "j0", "."),
|
||||||
|
"<caret>foo baz\n" +
|
||||||
|
"baz quux\n",
|
||||||
|
"foo baz\n" +
|
||||||
|
"fo<caret>o quux\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-511 |.|
|
||||||
|
public void testRepeatWithParensAndQuotesAutoInsertion() {
|
||||||
|
configureByJavaText("class C <caret>{\n" +
|
||||||
|
"}\n");
|
||||||
|
typeText(parseKeys("o", "foo(\"<Right>, \"<Right><Right>;", "<Esc>", "."));
|
||||||
|
myFixture.checkResult("class C {\n" +
|
||||||
|
" foo(\"\", \"\");\n" +
|
||||||
|
" foo(\"\", \"\");\n" +
|
||||||
|
"}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-511 |.|
|
||||||
|
public void testDeleteBothParensAndStartAgain() {
|
||||||
|
configureByJavaText("class C <caret>{\n" +
|
||||||
|
"}\n");
|
||||||
|
typeText(parseKeys("o", "C(", "<BS>", "(int i) {}", "<Esc>", "."));
|
||||||
|
myFixture.checkResult("class C {\n" +
|
||||||
|
" C(int i) {}\n" +
|
||||||
|
" C(int i) {}\n" +
|
||||||
|
"}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-613 |.|
|
||||||
|
public void testDeleteEndOfLineAndAgain() {
|
||||||
|
configureByText("<caret>- 1\n" +
|
||||||
|
"- 2\n" +
|
||||||
|
"- 3\n");
|
||||||
|
typeText(parseKeys("d$", "j", "."));
|
||||||
|
myFixture.checkResult("\n" +
|
||||||
|
"\n" +
|
||||||
|
"- 3\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-511 |.|
|
||||||
|
public void testAutoCompleteCurlyBraceWithEnterWithinFunctionBody() {
|
||||||
|
configureByJavaText("class C <caret>{\n" +
|
||||||
|
"}\n");
|
||||||
|
typeText(parseKeys("o", "C(", "<BS>", "(int i) {", "<Enter>", "i = 3;", "<Esc>", "<Down>", "."));
|
||||||
|
myFixture.checkResult("class C {\n" +
|
||||||
|
" C(int i) {\n" +
|
||||||
|
" i = 3;\n" +
|
||||||
|
" }\n" +
|
||||||
|
" C(int i) {\n" +
|
||||||
|
" i = 3;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}\n");
|
||||||
|
}
|
||||||
|
|
||||||
private void doTest(final List<KeyStroke> keys, String before, String after) {
|
private void doTest(final List<KeyStroke> keys, String before, String after) {
|
||||||
myFixture.configureByText("a.java", before);
|
myFixture.configureByText(PlainTextFileType.INSTANCE, before);
|
||||||
final Editor editor = myFixture.getEditor();
|
final Editor editor = myFixture.getEditor();
|
||||||
final KeyHandler keyHandler = KeyHandler.getInstance();
|
final KeyHandler keyHandler = KeyHandler.getInstance();
|
||||||
final EditorDataContext dataContext = new EditorDataContext(editor);
|
final EditorDataContext dataContext = new EditorDataContext(editor);
|
||||||
|
@@ -2,6 +2,10 @@ package org.jetbrains.plugins.ideavim.action;
|
|||||||
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.maddyhome.idea.vim.command.CommandState;
|
import com.maddyhome.idea.vim.command.CommandState;
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
|
import com.maddyhome.idea.vim.common.Register;
|
||||||
|
import com.maddyhome.idea.vim.option.ListOption;
|
||||||
|
import com.maddyhome.idea.vim.option.Options;
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase;
|
import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
||||||
@@ -29,6 +33,17 @@ public class CopyActionTest extends VimTestCase {
|
|||||||
"three\n");
|
"three\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-723 |p|
|
||||||
|
public void testYankPasteToEmptyLine() {
|
||||||
|
typeTextInFile(parseKeys("yiw", "j", "p"),
|
||||||
|
"foo\n" +
|
||||||
|
"\n" +
|
||||||
|
"bar\n");
|
||||||
|
myFixture.checkResult("foo\n" +
|
||||||
|
"foo\n" +
|
||||||
|
"bar\n");
|
||||||
|
}
|
||||||
|
|
||||||
// VIM-390 |yy| |p|
|
// VIM-390 |yy| |p|
|
||||||
public void testYankLinePasteAtLastLine() {
|
public void testYankLinePasteAtLastLine() {
|
||||||
typeTextInFile(parseKeys("yy", "p"),
|
typeTextInFile(parseKeys("yy", "p"),
|
||||||
@@ -64,10 +79,9 @@ public class CopyActionTest extends VimTestCase {
|
|||||||
|
|
||||||
public void testWrongYankQuoteYankLine() {
|
public void testWrongYankQuoteYankLine() {
|
||||||
assertPluginError(false);
|
assertPluginError(false);
|
||||||
typeTextInFile(parseKeys("y\"", "yy", "p"),
|
typeTextInFile(parseKeys("y\"", "yy", "p"), "one <caret>two\n" +
|
||||||
"one <caret>two\n" +
|
"three\n" +
|
||||||
"three\n" +
|
"four\n");
|
||||||
"four\n");
|
|
||||||
assertPluginError(false);
|
assertPluginError(false);
|
||||||
myFixture.checkResult("one two\n" +
|
myFixture.checkResult("one two\n" +
|
||||||
"one two\n" +
|
"one two\n" +
|
||||||
@@ -97,8 +111,8 @@ public class CopyActionTest extends VimTestCase {
|
|||||||
//
|
//
|
||||||
// The problem is that the selection range should be 1-char wide when entering the visual block mode
|
// The problem is that the selection range should be 1-char wide when entering the visual block mode
|
||||||
|
|
||||||
myFixture.checkResult("* *one\n" +
|
myFixture.checkResult("* * one\n" +
|
||||||
"* *two\n");
|
"* * two\n");
|
||||||
assertSelection(null);
|
assertSelection(null);
|
||||||
assertOffset(2);
|
assertOffset(2);
|
||||||
}
|
}
|
||||||
@@ -112,4 +126,49 @@ public class CopyActionTest extends VimTestCase {
|
|||||||
assertMode(CommandState.Mode.COMMAND);
|
assertMode(CommandState.Mode.COMMAND);
|
||||||
assertSelection(null);
|
assertSelection(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-476 |yy| |'clipboard'|
|
||||||
|
public void testClipboardUnnamed() {
|
||||||
|
assertEquals('\"', VimPlugin.getRegister().getDefaultRegister());
|
||||||
|
final ListOption clipboardOption = Options.getInstance().getListOption(Options.CLIPBOARD);
|
||||||
|
assertNotNull(clipboardOption);
|
||||||
|
clipboardOption.set("unnamed");
|
||||||
|
assertEquals('*', VimPlugin.getRegister().getDefaultRegister());
|
||||||
|
typeTextInFile(parseKeys("yy"),
|
||||||
|
"foo\n" +
|
||||||
|
"<caret>bar\n" +
|
||||||
|
"baz\n");
|
||||||
|
final Register starRegister = VimPlugin.getRegister().getRegister('*');
|
||||||
|
if (starRegister != null) {
|
||||||
|
assertEquals("bar\n", starRegister.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-792 |"*| |yy| |p|
|
||||||
|
public void testLineWiseClipboardYankPaste() {
|
||||||
|
configureByText("<caret>foo\n");
|
||||||
|
typeText(parseKeys("\"*yy", "\"*p"));
|
||||||
|
final Register register = VimPlugin.getRegister().getRegister('*');
|
||||||
|
if (register != null) {
|
||||||
|
assertEquals("foo\n", register.getText());
|
||||||
|
myFixture.checkResult("foo\n" +
|
||||||
|
"<caret>foo\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-792 |"*| |CTRL-V| |v_y| |p|
|
||||||
|
public void testBlockWiseClipboardYankPaste() {
|
||||||
|
configureByText("<caret>foo\n" +
|
||||||
|
"bar\n" +
|
||||||
|
"baz\n");
|
||||||
|
typeText(parseKeys("<C-V>j", "\"*y", "\"*p"));
|
||||||
|
final Register register = VimPlugin.getRegister().getRegister('*');
|
||||||
|
if (register != null) {
|
||||||
|
assertEquals("f\n" +
|
||||||
|
"b", register.getText());
|
||||||
|
myFixture.checkResult("ffoo\n" +
|
||||||
|
"bbar\n" +
|
||||||
|
"baz\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -84,6 +84,54 @@ public class MotionActionTest extends VimTestCase {
|
|||||||
assertMode(COMMAND);
|
assertMode(COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |;|
|
||||||
|
public void testTillCharRight() {
|
||||||
|
typeTextInFile(parseKeys("t:;"),
|
||||||
|
"<caret> 1:a 2:b 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:a <caret>2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |;|
|
||||||
|
public void testTillCharRightRepeated() {
|
||||||
|
typeTextInFile(parseKeys("t:;"),
|
||||||
|
"<caret> 1:a 2:b 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:a <caret>2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |;|
|
||||||
|
public void testTillCharRightRepeatedWithCount2() {
|
||||||
|
typeTextInFile(parseKeys("t:2;"),
|
||||||
|
"<caret> 1:a 2:b 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:a <caret>2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |;|
|
||||||
|
public void testTillCharRightRepeatedWithCountHigherThan2() {
|
||||||
|
typeTextInFile(parseKeys("t:3;"), "<caret> 1:a 2:b 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:a 2:b <caret>3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |,|
|
||||||
|
public void testTillCharRightReverseRepeated() {
|
||||||
|
typeTextInFile(parseKeys("t:,,"),
|
||||||
|
" 1:a 2:b<caret> 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:<caret>a 2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |,|
|
||||||
|
public void testTillCharRightReverseRepeatedWithCount2() {
|
||||||
|
typeTextInFile(parseKeys("t:,2,"),
|
||||||
|
" 1:a 2:b<caret> 3:c \n");
|
||||||
|
myFixture.checkResult(" 1:<caret>a 2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// VIM-771 |t| |,|
|
||||||
|
public void testTillCharRightReverseRepeatedWithCountHigherThan3() {
|
||||||
|
typeTextInFile(parseKeys("t:,3,"),
|
||||||
|
" 0:_ 1:a 2:b<caret> 3:c \n");
|
||||||
|
myFixture.checkResult(" 0:<caret>_ 1:a 2:b 3:c \n");
|
||||||
|
}
|
||||||
|
|
||||||
// VIM-326 |d| |v_ib|
|
// VIM-326 |d| |v_ib|
|
||||||
public void testDeleteInnerBlock() {
|
public void testDeleteInnerBlock() {
|
||||||
typeTextInFile(parseKeys("di)"),
|
typeTextInFile(parseKeys("di)"),
|
||||||
@@ -113,6 +161,12 @@ public class MotionActionTest extends VimTestCase {
|
|||||||
assertOffset(4);
|
assertOffset(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// |v_ib|
|
||||||
|
public void testInnerBlockCrashWhenNoDelimiterFound() {
|
||||||
|
typeTextInFile(parseKeys("di)"), "(x\n");
|
||||||
|
myFixture.checkResult("(x\n");
|
||||||
|
}
|
||||||
|
|
||||||
// VIM-314 |d| |v_iB|
|
// VIM-314 |d| |v_iB|
|
||||||
public void testDeleteInnerCurlyBraceBlock() {
|
public void testDeleteInnerCurlyBraceBlock() {
|
||||||
typeTextInFile(parseKeys("di{"),
|
typeTextInFile(parseKeys("di{"),
|
||||||
@@ -198,6 +252,12 @@ public class MotionActionTest extends VimTestCase {
|
|||||||
myFixture.checkResult("Hello World! Bye.\n");
|
myFixture.checkResult("Hello World! Bye.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// |v_as|
|
||||||
|
public void testSentenceMotionPastStartOfFile() {
|
||||||
|
typeTextInFile(parseKeys("8("), "\n" +
|
||||||
|
"P<caret>.\n");
|
||||||
|
}
|
||||||
|
|
||||||
// |d| |v_ip|
|
// |d| |v_ip|
|
||||||
public void testDeleteInnerParagraph() {
|
public void testDeleteInnerParagraph() {
|
||||||
typeTextInFile(parseKeys("dip"),
|
typeTextInFile(parseKeys("dip"),
|
||||||
@@ -500,6 +560,13 @@ public class MotionActionTest extends VimTestCase {
|
|||||||
assertOffset(2);
|
assertOffset(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// |b|
|
||||||
|
public void testWordBackwardsAtFirstLineWithWhitespaceInFront() {
|
||||||
|
typeTextInFile(parseKeys("b"),
|
||||||
|
" <caret>x\n");
|
||||||
|
assertOffset(0);
|
||||||
|
}
|
||||||
|
|
||||||
public void testRightToLastChar() {
|
public void testRightToLastChar() {
|
||||||
typeTextInFile(parseKeys("i<Right>"),
|
typeTextInFile(parseKeys("i<Right>"),
|
||||||
"on<caret>e\n");
|
"on<caret>e\n");
|
||||||
|
@@ -52,4 +52,16 @@ public class ShiftRightLinesActionTest extends VimTestCase {
|
|||||||
typeText(parseKeys("vG$>>"));
|
typeText(parseKeys("vG$>>"));
|
||||||
myFixture.checkResult(" Hello,\n world!\n\n");
|
myFixture.checkResult(" Hello,\n world!\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-705 repeating a multiline indent would only affect last line
|
||||||
|
public void testShiftsMultiLineSelectionRepeat() {
|
||||||
|
myFixture.configureByText("a.txt", "<caret>a\nb\n");
|
||||||
|
typeText(parseKeys("Vj>."));
|
||||||
|
myFixture.checkResult(" a\n b\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShiftsDontCrashKeyHandler() {
|
||||||
|
myFixture.configureByText("a.txt", "\n");
|
||||||
|
typeText(parseKeys("<I<>", "<I<>"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.plugins.ideavim.ex;
|
package org.jetbrains.plugins.ideavim.ex;
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.command.CommandState;
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase;
|
import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
||||||
@@ -27,4 +28,14 @@ public class VariousCommandsTest extends VimTestCase {
|
|||||||
myFixture.checkResult("Hello World!\n" +
|
myFixture.checkResult("Hello World!\n" +
|
||||||
"<caret>Hello \n");
|
"<caret>Hello \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VIM-652 |:action|
|
||||||
|
public void testEditorRightAction() {
|
||||||
|
configureByText("<caret>foo\n" +
|
||||||
|
"bar\n");
|
||||||
|
typeText(commandToKeys("action EditorRight"));
|
||||||
|
assertMode(CommandState.Mode.COMMAND);
|
||||||
|
myFixture.checkResult("f<caret>oo\n" +
|
||||||
|
"bar\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user