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

Compare commits

...

93 Commits
0.37 ... 0.38

Author SHA1 Message Date
Andrey Vlasovskikh
69f4611552 Version 0.38 2014-12-01 14:01:25 +03:00
Andrey Vlasovskikh
31a25449a8 Updated the changelist 2014-12-01 13:59:34 +03:00
Andrey Vlasovskikh
26a247c0bf Revert "Unified tests initialization for IntelliJ 13+ Community and Ultimate"
This reverts commit 296ef1bdf9.
2014-11-28 22:29:15 +03:00
Andrey Vlasovskikh
1c7cd23475 Updated IntelliJ version 2014-11-28 21:44:37 +03:00
Andrey Vlasovskikh
296ef1bdf9 Unified tests initialization for IntelliJ 13+ Community and Ultimate 2014-11-28 20:22:43 +03:00
Andrey Vlasovskikh
642659bc9b VIM-410 Use the standard editor line numbers for supporting 'nu'
Annotations-based line numbers reset all other annotations on caret
move, so the results of VCS annotate are reset all the time. It is
necessary for 'rnu', but for 'nu' we can use standard editor line
numbers and preserve the ability to show VCS annotations during caret
movement operations.
2014-11-26 19:49:09 +03:00
Andrey Vlasovskikh
f0e8d065b7 Merge remote-tracking branch 'dezgeg/fixes/vim-723-paste-wrong-line' 2014-11-26 18:18:54 +03:00
Andrey Vlasovskikh
520d852c04 Merge remote-tracking branch 'dezgeg/fixes/vim-771-repeated-semicolon' 2014-11-26 18:12:14 +03:00
Andrey Vlasovskikh
8d4d7a421a Merge remote-tracking branch 'dezgeg/fixes/crashes' 2014-11-26 17:58:27 +03:00
Andrey Vlasovskikh
802b83b0fe VIM-818 Enable key repeat on Mac OS X every time it gets reset by the OS 2014-11-26 17:21:18 +03:00
Tuomas Tynkkynen
31f598d1e1 VIM-723 Fix pasting to an empty line
When pasting on an empty line, the pasted text would go to the start of
next line instead.
2014-11-17 03:47:50 +02:00
Tuomas Tynkkynen
46e6fd0847 VIM-771 Fix semicolon repeat for 'till char' motion
Based on empirical testing with Vim, ';' should work like this:
assuming "<caret>1:a 2:b 3:c" with ':' as the last f/t character:

- "t:" does nothing
- ";"  cursor goes to '2'
- "2;" cursor goes to '2', same as the previous
- "3;" cursor goes to '3'
2014-11-16 18:58:56 +02:00
Tuomas Tynkkynen
1441a60f4b Fix AIOOBE when '(' motion goes past start of file
If first character of the file is a newline, then findSentenceEnd()
could return -2 when the 'previous sentence' motion is performed,
leading to an eventual crash. Found by fuzzing.
2014-11-16 17:08:47 +02:00
Tuomas Tynkkynen
ebdf107946 Fix AIOOBE crash when using 'b' on first line
If 'b' were used on the first word of the file, and the word was
preceded by whitespace, ArrayIndexOutOfBoundsException would occur.
Found by fuzzing.
2014-11-16 17:08:47 +02:00
Tuomas Tynkkynen
38d672c9f9 Fix KeyHandler crash when using '<' or '>'
The '<' and '>' commands weren't marked with FLAG_OP_PEND even though
they should, which sometimes caused EmptyStackException in KeyHandler
(when typing <I<><I<> for example). Found by fuzzing.
2014-11-16 17:08:46 +02:00
Tuomas Tynkkynen
75d34abd45 Fix IOOBE when 'i)' motion doesn't find other delimiter
Found by fuzzing.
2014-11-16 17:08:43 +02:00
Andrey Vlasovskikh
1d98738e4d Updated the changelog 2014-11-15 00:11:35 +03:00
Andrey Vlasovskikh
3cfa0e1844 Merge remote-tracking branch 'dezgeg/fixes/vim-515-cW-command' 2014-11-15 00:09:00 +03:00
Andrey Vlasovskikh
82211a4373 Updated the changelog 2014-11-15 00:08:32 +03:00
Andrey Vlasovskikh
e324b04a94 Added Tuomas Tynkkynen to the list of contributors 2014-11-15 00:02:09 +03:00
Andrey Vlasovskikh
49d0c51d97 Merge branch 'vim-536-cc-second-to-last-line' 2014-11-15 00:00:43 +03:00
Andrey Vlasovskikh
fe4bc3b4a9 Moved line line position calculation before deletion 2014-11-15 00:00:13 +03:00
Tuomas Tynkkynen
58d964063c VIM-515 Fix cW command detecting end-of-word incorrectly
A cW command on text like 'x$$$$' or '$xxxx' would incorrectly delete
just the first character, and not the rest.
2014-11-14 22:51:46 +02:00
Andrey Vlasovskikh
17d3e37e1d Merge branch 'vim-567-run-external-command-in-window' 2014-11-14 23:43:42 +03:00
Andrey Vlasovskikh
54f6a16bd6 Nullity checks 2014-11-14 23:41:17 +03:00
Andrey Vlasovskikh
f4ffc5d198 Get rid of Reader and Writer classes in executeCommand() 2014-11-14 23:35:27 +03:00
Andrey Vlasovskikh
3d8010bf88 Removed debug output 2014-11-14 23:18:53 +03:00
Andrey Vlasovskikh
ec2cc3a7f9 Code style 2014-11-14 23:17:50 +03:00
Andrey Vlasovskikh
52b7b9bcd8 Merge branch 'vim-705-multi-line-indent-broken' 2014-11-14 23:05:03 +03:00
Andrey Vlasovskikh
8ad0fcf42d Default value for @NotNull field mode 2014-11-14 23:04:33 +03:00
Andrey Vlasovskikh
aa6cc45988 Made moveCaret(Editor, int, boolean) private 2014-11-14 23:02:32 +03:00
Tuomas Tynkkynen
da22b8297b VIM-536 Fix 'cc' on second-to-last line in file
Previously, 'cc' on the second-to-last line of a file would instead open
a new line after the last line of the file.
2014-11-14 16:56:05 +02:00
Tuomas Tynkkynen
798d82e941 VIM-567 Extend :! to allow running non-filter commands
This commit allows the Ex command '!' to be ran without a range, with
the results displayed in a window.

For example, run ':! ls' in normal mode for a quick directory listing.
2014-11-11 20:32:24 +02:00
Tuomas Tynkkynen
ac8ac302ca VIM-705 Fix repeated multiline indent
When a visual mode command is repeated, code calls into
MotionGroup#toggleVisual() to setup a 'fake' visual mode selection. But
when MotionGroup.moveCaret() is called, it notices that the indent
command has the FLAG_EXIT_VISUAL flag, and leaves visual mode right
away.
2014-11-10 23:32:09 +02:00
Tuomas Tynkkynen
22c3a73102 VIM-613 Fix repeat after 'd$'
Previously, repeating a 'd$' command would incorrectly delete the
newline from the line.
2014-11-10 16:36:40 +02:00
Andrey Vlasovskikh
1222fdb043 Merge pull request #47 from TylerNHansen/master
Update README.md - typo fix
2014-10-29 22:43:24 +03:00
Tyler Hansen
78a50c2f53 Update README.md 2014-10-29 12:19:13 -07:00
Andrey Vlasovskikh
6d261a7afa Merge pull request #46 from Baldrs/patch-1
Typo
2014-10-24 18:41:40 +04:00
Baldrs
2e37292478 Typo 2014-10-24 17:40:34 +03:00
Andrey Vlasovskikh
a4907ec9c8 Links to GitHub and YouTrack in the plugin info 2014-10-24 16:41:00 +04:00
Andrey Vlasovskikh
992bfe73b6 Updated changes in plugin.xml 2014-10-24 16:37:29 +04:00
Andrey Vlasovskikh
c186254a7e Updated dev version 2014-10-24 16:36:21 +04:00
Andrey Vlasovskikh
1dc739f32c Added :action and :actionlist to the docs 2014-10-24 16:35:56 +04:00
Andrey Vlasovskikh
9804cd83a6 VIM-652 Added a test for :action 2014-10-24 16:13:40 +04:00
Andrey Vlasovskikh
aa5b99c47a Added smartbomb to the list of contributors 2014-10-24 16:04:57 +04:00
Andrey Vlasovskikh
f95f5e8901 Merge branch 'action-command' 2014-10-24 16:02:21 +04:00
Andrey Vlasovskikh
206b303407 Renamed ExecuteActionByNameHandler to ActionHandler
The name of an Ex command handler should correspond to the Ex command
name.
2014-10-24 16:01:38 +04:00
Andrey Vlasovskikh
751bff53ee Removed checks for action execution problems not reproducible at the moment
We need to collect more data from the beta testers about these problems.
2014-10-24 16:00:23 +04:00
Andrey Vlasovskikh
b6ef0c509d We don't need two Alexeys at the moment 2014-10-23 22:47:41 +04:00
Andrey Vlasovskikh
30304d6836 VIM-794 Fixed NCDFE related to 'number' in IDEs other than IntelliJ 2014-10-23 22:45:19 +04:00
Andrey Vlasovskikh
f5df49b139 Don't allow short names for IdeaVim-specific :action and :actionlist 2014-10-23 19:01:58 +04:00
Andrey Vlasovskikh
bf8ba1a49b Prettier output of :actionlist 2014-10-23 18:58:50 +04:00
Andrey Vlasovskikh
9f2697658b Fixed code style 2014-10-23 18:25:01 +04:00
smartbomb
36fd59b92c ExecuteActionByName use the content context on actions with the EnabledInModalContext flag set
(cherry picked from commit d375740)
2014-10-23 18:02:12 +04:00
Andrey Vlasovskikh
88d946546a Added Alexey Shmalko to the list of contributors 2014-10-23 17:30:06 +04:00
Andrey Vlasovskikh
6036c0c262 Updated CHANGES 2014-10-23 16:59:41 +04:00
Andrey Vlasovskikh
20e831b56a Updated tests after fixing VIM-501 2014-10-23 16:58:43 +04:00
Andrey Vlasovskikh
72b74e075c Merge branch 'visual_block_delete' 2014-10-23 16:55:17 +04:00
Andrey Vlasovskikh
3c6ede2f8f Normalize offsets in order to prevent selecting newlines 2014-10-23 16:53:31 +04:00
Andrey Vlasovskikh
5434edbd54 VIM-792 Fixed line-wise and block-wise paste commands for * and + registers 2014-10-23 16:09:56 +04:00
Andrey Vlasovskikh
6a8c7e4b17 VIM-511 Record caret adjustment changes to the document during <Enter> processing
We have to handle Enter by our VimShortcutKeyAction in order to be
able to record it as an action for repeating it via '.'. Since original
Enter handlers are not run in this case we invoke them manually by
collecting a list of actions that can be run for the editor component
on Enter and then running the first action ready to run.

Caret adjustments are detected on changes to the document caused by
Enter. This allows to position the caret properly (e.g. between {})
before recording Enter.
2014-10-23 15:26:22 +04:00
Alexey Shmalko
0ac659f2d1 Fix visual block deleting
Currently deleting visual block leaves last char in line untouched. This
patch fixes that as well as tests.
2014-10-21 21:40:43 +03:00
Tony Kay
7eae40ca9a added a failing test 2014-10-21 11:05:43 -07:00
Andrey Vlasovskikh
b3d12c8b58 VIM-511 Fixed removing a paren just after inserting it with auto-inserting matching parens on 2014-10-21 21:47:06 +04:00
Andrey Vlasovskikh
3f92dba1b7 VIM-511 Updated test data 2014-10-21 21:16:11 +04:00
Andrey Vlasovskikh
0aedc08cfa More tests for VIM-511 2014-10-21 20:42:04 +04:00
Andrey Vlasovskikh
8312f5cffd VIM-511 Added a test for repeating a change that includes auto-inserted parens and quotes 2014-10-21 19:41:11 +04:00
Andrey Vlasovskikh
9f6338441e Updated CHANGES 2014-10-21 19:09:56 +04:00
Andrey Vlasovskikh
27efe0c9d6 Handle left and right motions during key repeat only as document (caret) changes
Previously they have been recorded twice: implicitly by a document
change listener as changes to the caret position and by a command
processor.
2014-10-21 18:24:36 +04:00
Andrey Vlasovskikh
b5bf6c08d8 Repeat typing commands by inserting text instead of handling a typed key
It will prevent auto-completion and other auto-inserting typed key
handlers from messing up with the repeated text.
2014-10-21 18:22:19 +04:00
Andrey Vlasovskikh
e3fce51ea1 VIM-511 Fixed editing offset after <BS> for '.' command 2014-10-21 16:56:54 +04:00
Andrey Vlasovskikh
13b4e93bf4 Run the test only if the system clipboard is available 2014-10-20 16:53:25 +04:00
Andrey Vlasovskikh
4ec0ab281f Removed the list of compatible IDEs
The same list is shown on the plugin's page and duplicated in the
README.
2014-10-20 16:09:32 +04:00
Andrey Vlasovskikh
39c96019b6 Typo 2014-10-20 16:08:29 +04:00
Andrey Vlasovskikh
21f2f60355 Updated CHANGES 2014-10-20 16:07:50 +04:00
Andrey Vlasovskikh
0de654dcaf Added Thomas B Homburg to the list of contributors 2014-10-20 16:02:11 +04:00
Andrey Vlasovskikh
d59e472814 Added 'clipboard' to the list of :set commands 2014-10-20 16:01:09 +04:00
Andrey Vlasovskikh
cc2ed452f0 Merge branch 'clipboard-unnamed'
Conflicts:
	src/com/maddyhome/idea/vim/option/Options.java
	test/org/jetbrains/plugins/ideavim/action/CopyActionTest.java
2014-10-20 15:59:15 +04:00
Andrey Vlasovskikh
d4d3843725 VIM-476 Added default register reset on 'clipboard' change
Added a test for :set clipboard=unnamed.
2014-10-20 15:53:33 +04:00
Andrey Vlasovskikh
dee16da1c2 Coding style 2014-10-20 14:52:22 +04:00
Andrey Vlasovskikh
e09b85870f Added Jaime Sanchez to the list of contributors 2014-10-20 13:27:31 +04:00
Andrey Vlasovskikh
8596911a0e VIM-483 VIM-410 Added support for 'number' and 'relativenumber' commands
These commands override the line numbers setting in the IDE when the
Vim emulation is enabled.
2014-10-20 13:27:09 +04:00
Andrey Vlasovskikh
6c2de9f151 Extracted EditorGroup 2014-10-17 17:07:39 +04:00
Andrey Vlasovskikh
d3a6b1e39e Use '\n' as universal line separator for sorting lines
The Document class takes care of detecting and using the correct
platform-specific line separators.
2014-10-17 14:54:48 +04:00
Andrey Vlasovskikh
3cb9b19aea Added Chang Wang to the list of contributors 2014-10-16 23:32:42 +04:00
Andrey Vlasovskikh
86aa59bb29 Merge branch 'vim-624' 2014-10-16 23:29:33 +04:00
smartbomb
c6eeaed7da :actionlist added support for wildcards 2014-10-15 22:49:08 +02:00
smartbomb
edba90f188 Renamed :findaction => :actionlist + added statusbar error message when calling invalid action names 2014-10-15 21:17:26 +02:00
smartbomb
7943e34bde Fix action execution contexts, use a delay on popup actions to allow the command handler to unwind 2014-10-15 08:31:44 +02:00
smartbomb
74970c74b4 Implemented :findaction 2014-10-14 22:47:03 +02:00
smartbomb
722431f5b2 VIM-652 Add support for executing and mapping arbitrary IDEA actions
* no tests performed..! *

Example usage:
:nnoremap gi :action GotoImplementation<CR>
:nnoremap gu :action FindUsages<CR>
:nnoremap gcw :action RenameElement<CR>

Action overview:
6c6cb47c5a/platform/platform-resources-en/src/messages/ActionsBundle.properties
2014-10-13 21:58:38 +02:00
Thomas B Homburg
df8e455a6d Get default register from clipboard=unnamed setting 2014-08-26 22:51:17 +02:00
Chang Wang
b35bec2839 deselect visual selection range '<,'> when poping up ex entry field. 2014-08-13 16:40:50 -07:00
37 changed files with 1177 additions and 353 deletions

View File

@@ -28,6 +28,11 @@ Contributors:
* [salaam](mailto:kphayen@gmail.com)
* [Alexey Shmalko](mailto:rasen.dubi@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
contact the maintainer.

View File

@@ -4,12 +4,44 @@ The Changelog
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
----------------
A bugfix release.
Bug fixes:
* VIM-784 Fixed visual line selection where the start of the selection range

View File

@@ -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.
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.
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).
### 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
------------

View File

@@ -1,4 +1,4 @@
version-id:0.37
version-id:0.38
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

View File

@@ -3,22 +3,26 @@ List of Supported Set Commands
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
'gdefault' 'gd' the ":substitute" flag 'g' is default on
'history' 'hi' number of command-lines that are remembered
'hlsearch' 'hls' highlight matches with last search pattern
'ignorecase' 'ic' ignore case in search patterns
'matchpairs' 'mps' pairs of characters that "%" can match
'nrformats' 'nf' number formats recognized for CTRL-A command
'scroll' 'scr' lines to scroll with CTRL-U and CTRL-D
'scrolljump' 'sj' minimum number of lines to scroll
'scrolloff' 'so' minimum nr. of lines above and below cursor
'selection' 'sel' what type of selection to use
'showmode' 'smd' message on status line to show current mode
'sidescroll' 'ss' minimum number of columns to scroll horizontal
'sidescrolloff' 'siso' min. nr. of columns to left and right of cursor
'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
'clipboard' 'cb' clipboard options
'digraph' 'dg' enable the entering of digraphs in Insert mode
'gdefault' 'gd' the ":substitute" flag 'g' is default on
'history' 'hi' number of command-lines that are remembered
'hlsearch' 'hls' highlight matches with last search pattern
'ignorecase' 'ic' ignore case in search patterns
'matchpairs' 'mps' pairs of characters that "%" can match
'nrformats' 'nf' number formats recognized for CTRL-A command
'number' 'nu' print the line number in front of each line
'relativenumber' 'rnu' show the line number relative to the line with
the cursor
'scroll' 'scr' lines to scroll with CTRL-U and CTRL-D
'scrolljump' 'sj' minimum number of lines to scroll
'scrolloff' 'so' minimum nr. of lines above and below cursor
'selection' 'sel' what type of selection to use
'showmode' 'smd' message on status line to show current mode
'sidescroll' 'ss' minimum number of columns to scroll horizontal
'sidescrolloff' 'siso' min. nr. of columns to left and right of cursor
'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

View File

@@ -3,6 +3,13 @@
<id>IdeaVIM</id>
<change-notes>
<![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>
<ul>
<li>Various bug fixes</li>
@@ -41,9 +48,13 @@
<description>
<![CDATA[
<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>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>
<version>@VERSION@</version>

View File

@@ -292,17 +292,19 @@ public class KeyHandler {
}
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 &&
VimPlugin.getRegister().getCurrentRegister() == RegisterGroup.REGISTER_DEFAULT) {
if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
CommandProcessor.getInstance().executeCommand(editor.getProject(), new Runnable() {
@Override
public void run() {
KeyHandler.executeAction("EditorEscape", context);
}
}, "", null);
if (state != State.COMMAND && count == 0 && currentArg == Argument.Type.NONE && currentCmd.size() == 0) {
RegisterGroup register = VimPlugin.getRegister();
if (register.getCurrentRegister() == register.getDefaultRegister()) {
if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
CommandProcessor.getInstance().executeCommand(editor.getProject(), new Runnable() {
@Override
public void run() {
KeyHandler.executeAction("EditorEscape", context);
}
}, "", null);
}
VimPlugin.indicateError();
}
VimPlugin.indicateError();
}
reset(editor);
}
@@ -560,12 +562,10 @@ public class KeyHandler {
* @param name The name of the action to execute
* @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();
AnAction action = aMgr.getAction(name);
if (action != null) {
executeAction(action, context);
}
return action != null && executeAction(action, context);
}
/**
@@ -574,16 +574,20 @@ public class KeyHandler {
* @param action The action to execute
* @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.
// We don't have a specific InputEvent so that is null
// What is "place"? Leave it the empty string for now.
// Is the template presentation sufficient?
// What are the modifiers? Is zero OK?
action.actionPerformed(
new AnActionEvent(null, context, "", action.getTemplatePresentation(), ActionManager.getInstance(),
// API change - don't merge
0));
final AnActionEvent event = new AnActionEvent(null, context, "", action.getTemplatePresentation(),
ActionManager.getInstance(), 0);
action.update(event);
if (event.getPresentation().isEnabled()) {
action.actionPerformed(event);
return true;
}
return false;
}
/**

View File

@@ -630,11 +630,11 @@ public class RegisterActions {
new Shortcut("=="));
parser.registerAction(MappingMode.N, "VimShiftLeftLines", Command.Type.CHANGE,
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);
parser.registerAction(MappingMode.N, "VimShiftRightLines", Command.Type.CHANGE,
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);
// Jump Actions
@@ -722,11 +722,11 @@ public class RegisterActions {
new Shortcut(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK)));
parser.registerAction(MappingMode.I, "VimMotionLastColumn", Command.Type.INSERT, Command.FLAG_SAVE_STROKE,
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_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_KP_RIGHT, 0))
});

View File

@@ -18,7 +18,6 @@
package com.maddyhome.idea.vim;
import com.intellij.notification.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationEx;
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.Storage;
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.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.keymap.Keymap;
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.wm.StatusBar;
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.VimScriptParser;
import com.maddyhome.idea.vim.group.*;
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.option.Options;
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
@@ -60,7 +51,6 @@ import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
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 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 int previousStateVersion = 0;
@@ -105,8 +88,6 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
private static final Logger LOG = Logger.getInstance(VimPlugin.class);
private final Application myApp;
@NotNull private final MotionGroup motion;
@NotNull private final ChangeGroup change;
@NotNull private final CopyGroup copy;
@@ -119,11 +100,10 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
@NotNull private final DigraphGroup digraph;
@NotNull private final HistoryGroup history;
@NotNull private final KeyGroup key;
@NotNull private WindowGroup window;
public VimPlugin(final Application app) {
myApp = app;
@NotNull private final WindowGroup window;
@NotNull private final EditorGroup editor;
public VimPlugin() {
motion = new MotionGroup();
change = new ChangeGroup();
copy = new CopyGroup();
@@ -137,6 +117,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
history = new HistoryGroup();
key = new KeyGroup();
window = new WindowGroup();
editor = new EditorGroup();
LOG.debug("VimPlugin ctr");
}
@@ -205,6 +186,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
search.saveData(element);
history.saveData(element);
key.saveData(element);
editor.saveData(element);
return element;
}
@@ -230,6 +212,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
search.readData(element);
history.readData(element);
key.readData(element);
editor.readData(element);
}
@NotNull
@@ -297,6 +280,11 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
return getInstance().window;
}
@NotNull
public static EditorGroup getEditor() {
return getInstance().editor;
}
@NotNull
public static PluginId getPluginId() {
return PluginId.getId(IDEAVIM_PLUGIN_ID);
@@ -367,38 +355,38 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
private void turnOnPlugin() {
KeyHandler.getInstance().fullReset(null);
setCursors(BLOCK_CURSOR_VIM_VALUE);
setAnimatedScrolling(ANIMATED_SCROLLING_VIM_VALUE);
setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
getEditor().turnOn();
getMotion().turnOn();
}
private void turnOffPlugin() {
KeyHandler.getInstance().fullReset(null);
setCursors(isBlockCursor);
setAnimatedScrolling(isAnimatedScrolling);
setRefrainFromScrolling(isRefrainFromScrolling);
getEditor().turnOff();
getMotion().turnOff();
}
private void updateState() {
if (isEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
boolean requiresRestart = false;
if (previousStateVersion < 2 && SystemInfo.isMac) {
if (SystemInfo.isMac) {
final MacKeyRepeat keyRepeat = MacKeyRepeat.getInstance();
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 " +
"(requires restart)?\n\n" +
"(You can do it manually by running 'defaults write -g " +
"ApplePressAndHoldEnabled 0' in the console).", IDEAVIM_NOTIFICATION_TITLE,
Messages.getQuestionIcon()
) == Messages.YES) {
Messages.getQuestionIcon()) == Messages.YES) {
editor.setKeyRepeat(true);
keyRepeat.setEnabled(true);
requiresRestart = true;
}
else {
editor.setKeyRepeat(false);
}
}
}
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 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() {
@Override
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);
}
}
}

View File

@@ -76,6 +76,7 @@ public class VimShortcutKeyAction extends AnAction implements DumbAware {
.build();
@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_TAB, 0))
.addAll(getKeyStrokes(VK_UP, 0))
@@ -144,8 +145,8 @@ public class VimShortcutKeyAction extends AnAction implements DumbAware {
return isExitInsertMode(keyStroke);
}
if (CommandState.inInsertMode(editor)) {
// XXX: <Enter> and <Tab> won't be recorded in macros
if (keyCode == VK_ENTER || keyCode == VK_TAB) {
// XXX: <Tab> won't be recorded in macros
if (keyCode == VK_TAB) {
return false;
}
// Debug watch, Python console, etc.

View File

@@ -42,7 +42,7 @@ public class MotionLastColumnAction extends MotionEditorAction {
private static class Handler extends MotionEditorActionHandler {
public int getOffset(@NotNull Editor editor, DataContext context, int count, int rawCount, Argument argument) {
boolean allow = false;
if (CommandState.inInsertMode(editor) || CommandState.inRepeatMode(editor)) {
if (CommandState.inInsertMode(editor)) {
allow = true;
}
else if (CommandState.getInstance(editor).getMode() == CommandState.Mode.VISUAL) {

View File

@@ -20,7 +20,6 @@ package com.maddyhome.idea.vim.command;
import com.intellij.openapi.editor.Editor;
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.key.ParentNode;
import com.maddyhome.idea.vim.option.NumberOption;
@@ -38,7 +37,7 @@ public class CommandState {
public static final int DEFAULT_TIMEOUT_LENGTH = 1000;
@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 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.setRepeats(false);
myStates.push(new State(Mode.COMMAND, SubMode.NONE, MappingMode.NORMAL));
myLastChangeRegister = VimPlugin.getRegister().getDefaultRegister();
}
@NotNull
@@ -255,7 +255,7 @@ public class CommandState {
* @return The register key
*/
public char getLastChangeRegister() {
return ourLastRegister;
return myLastChangeRegister;
}
/**
@@ -265,7 +265,7 @@ public class CommandState {
*/
public void saveLastChangeCommand(Command cmd) {
ourLastChange = cmd;
ourLastRegister = VimPlugin.getRegister().getCurrentRegister();
myLastChangeRegister = VimPlugin.getRegister().getCurrentRegister();
}
public boolean isRecording() {

View File

@@ -70,6 +70,7 @@ public class CommandParser {
public void registerHandlers() {
if (registered) return;
new ActionListHandler();
new AsciiHandler();
new CmdFilterHandler();
new CopyTextHandler();
@@ -77,6 +78,7 @@ public class CommandParser {
new DigraphHandler();
new DumpLineHandler();
new EditFileHandler();
new ActionHandler();
new ExitHandler();
new FindClassHandler();
new FindFileHandler();

View 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;
}
}
}

View 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;
}
}

View File

@@ -23,10 +23,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.common.TextRange;
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.Ranges;
import com.maddyhome.idea.vim.ex.*;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.Msg;
import org.jetbrains.annotations.NotNull;
@@ -38,41 +35,42 @@ import java.io.IOException;
*/
public class CmdFilterHandler extends CommandHandler {
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 {
logger.info("execute");
Ranges ranges = cmd.getRanges();
if (ranges.size() == 0) {
// Need some range
String command = cmd.getArgument();
if (command.length() == 0) {
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 == null || command.length() == 0) {
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);
}
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);
}
catch (IOException e) {
throw new ExException(e.getMessage());
}
}
catch (IOException e) {
throw new ExException(e.getMessage());
}
}

View File

@@ -26,7 +26,6 @@ import com.maddyhome.idea.vim.common.TextRange;
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.group.RegisterGroup;
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 {
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')) {
register = arg.charAt(0);
arg.deleteCharAt(0);

View File

@@ -49,7 +49,7 @@ public class PutLinesHandler extends CommandHandler {
}
}
else {
registerGroup.selectRegister(RegisterGroup.REGISTER_DEFAULT);
registerGroup.selectRegister(registerGroup.getDefaultRegister());
}
final int offset = EditorHelper.getLineStartOffset(editor, line + 1);

View File

@@ -26,7 +26,6 @@ import com.maddyhome.idea.vim.common.TextRange;
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.group.RegisterGroup;
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 {
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')) {
register = arg.charAt(0);
arg.deleteCharAt(0);

View File

@@ -17,10 +17,7 @@
*/
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.Lists;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
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.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
@@ -54,10 +52,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.*;
/**
* Provides all the insert/replace related functionality
@@ -385,6 +380,8 @@ public class ChangeGroup {
public void documentChanged(@NotNull DocumentEvent e) {
final String newFragment = e.getNewFragment().toString();
final String oldFragment = e.getOldFragment().toString();
final int newFragmentLength = newFragment.length();
final int oldFragmentLength = oldFragment.length();
// Repeat buffer limits
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
// command
if (newFragment.startsWith("\n") && newFragment.trim().isEmpty()) {
strokes.addAll(getAdjustCaretActions(e));
oldOffset = -1;
return;
}
// 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;
}
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) {
final List<AnAction> positionCaretActions = new ArrayList<AnAction>();
final String motionName = delta < 0 ? "VimMotionLeft" : "VimMotionRight";
final AnAction action = ActionManager.getInstance().getAction(motionName);
final int count = Math.abs(delta);
for (int i = 0; i < count; i++) {
strokes.add(action);
positionCaretActions.add(action);
}
return positionCaretActions;
}
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();
}
return Collections.emptyList();
}
}
@@ -496,9 +498,7 @@ public class ChangeGroup {
}
else if (lastStroke instanceof char[]) {
final char[] chars = (char[])lastStroke;
for (char c : chars) {
processKey(editor, context, KeyStroke.getKeyStroke(c));
}
insertText(editor, editor.getCaretModel().getOffset(), new String(chars));
}
}
}
@@ -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
* then turn OVERWRITE back on after sending the "Enter" key.
* Processes the Enter key by running the first successful action registered for "ENTER" keystroke.
*
* 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 context The data context
@@ -556,7 +558,13 @@ public class ChangeGroup {
if (CommandState.getInstance(editor).getMode() == CommandState.Mode.REPLACE) {
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) {
KeyHandler.executeAction("EditorToggleInsertState", context);
}
@@ -1018,11 +1026,12 @@ public class ChangeGroup {
* @return true if able to delete count lines, false if not
*/
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);
if (res) {
final int lastLine = EditorHelper.getLineCount(editor) - 1;
final LogicalPosition pos = editor.offsetToLogicalPosition(editor.getCaretModel().getOffset());
if (pos.line >= lastLine) {
if (insertBelow) {
insertNewLineBelow(editor, context);
}
else {
@@ -1070,13 +1079,13 @@ public class ChangeGroup {
}
String id = ActionManager.getInstance().getId(motion.getAction());
boolean kludge = false;
boolean bigWord = false;
boolean bigWord = id.equals("VimMotionBigWordRight");
final CharSequence chars = editor.getDocument().getCharsSequence();
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) {
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(
"VimMotionWordRight", "VimMotionBigWordRight", "VimMotionCamelRight");
if (wordMotions.contains(id) && lastWordChar) {
@@ -1093,7 +1102,6 @@ public class ChangeGroup {
}
else if (id.equals("VimMotionBigWordRight")) {
kludge = true;
bigWord = true;
motion.setAction(ActionManager.getInstance().getAction("VimMotionBigWordEndRight"));
motion.setFlags(Command.FLAG_MOT_INCLUSIVE);
}
@@ -1542,16 +1550,12 @@ public class ChangeGroup {
private boolean sortTextRange(@NotNull Editor editor, int start, int end,
@NotNull Comparator<String> lineComparator) {
final String selectedText = editor.getDocument().getText(new TextRangeInterval(start, end));
final String lineSeparator = CodeStyleSettingsManager.getSettings(editor.getProject()).getLineSeparator();
final List<String> lines = Lists.newArrayList(Splitter.on(lineSeparator).split(selectedText));
final List<String> lines = Arrays.asList(StringUtil.splitByLines(selectedText));
if (lines.size() < 1) {
return false;
}
Collections.sort(lines, lineComparator);
replaceText(editor, start, end, Joiner.on(lineSeparator).join(lines));
replaceText(editor, start, end, StringUtil.join(lines, "\n"));
return true;
}

View File

@@ -162,7 +162,10 @@ public class CopyGroup {
}
}
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
if (pos > 0 && pos > editor.getDocument().getTextLength()) {

View 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() {
}
}
}

View File

@@ -21,9 +21,11 @@ package com.maddyhome.idea.vim.group;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.actionSystem.*;
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.EditorFactory;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.maddyhome.idea.vim.EventFacade;
import com.maddyhome.idea.vim.VimPlugin;
@@ -41,8 +43,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.List;
import static com.maddyhome.idea.vim.helper.StringHelper.leftJustify;
import static com.maddyhome.idea.vim.helper.StringHelper.toKeyNotation;
@@ -429,4 +433,48 @@ public class KeyGroup {
// TODO: Add more codes
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;
}
}

View File

@@ -678,6 +678,7 @@ public class MotionGroup {
public int repeatLastMatchChar(@NotNull Editor editor, int count) {
int res = -1;
int startPos = editor.getCaretModel().getOffset();
switch (lastFTCmd) {
case LAST_F:
res = moveCaretToNextCharacterOnLine(editor, -count, lastFTChar);
@@ -687,9 +688,15 @@ public class MotionGroup {
break;
case LAST_T:
res = moveCaretToBeforeNextCharacterOnLine(editor, -count, lastFTChar);
if (res == startPos && Math.abs(count) == 1) {
res = moveCaretToBeforeNextCharacterOnLine(editor, 2 * count, lastFTChar);
}
break;
case LAST_t:
res = moveCaretToBeforeNextCharacterOnLine(editor, count, lastFTChar);
if (res == startPos && Math.abs(count) == 1) {
res = moveCaretToBeforeNextCharacterOnLine(editor, 2 * count, lastFTChar);
}
break;
}
@@ -1186,8 +1193,12 @@ public class MotionGroup {
}
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()) {
final boolean keepVisual = keepVisual(editor);
final boolean keepVisual = forceKeepVisual || keepVisual(editor);
if (editor.getCaretModel().getOffset() != offset) {
if (!keepVisual) {
// 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);
visualStart = start;
updateSelection(editor, end);
MotionGroup.moveCaret(editor, visualEnd);
MotionGroup.moveCaret(editor, visualEnd, true);
}
else if (mode == currentMode) {
exitVisual(editor);
@@ -1574,17 +1585,25 @@ public class MotionGroup {
public TextRange getVisualRange(@NotNull Editor editor) {
final TextRange res = new TextRange(editor.getSelectionModel().getBlockSelectionStarts(),
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();
if (subMode == CommandState.SubMode.VISUAL_BLOCK && EditorData.getLastColumn(editor) >= MotionGroup.LAST_COLUMN) {
final int[] starts = res.getStartOffsets();
if (subMode == CommandState.SubMode.VISUAL_BLOCK) {
final int[] ends = res.getEndOffsets();
for (int i = 0; i < starts.length; i++) {
if (ends[i] > starts[i]) {
ends[i] = EditorHelper.getLineEndForOffset(editor, starts[i]);
// If the last left/right motion was the $ command, simulate each line being selected to end-of-line
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;
}
@@ -1775,7 +1794,7 @@ public class MotionGroup {
}
@Nullable private Editor dragEditor = null;
@NotNull private CommandState.SubMode mode;
@NotNull private CommandState.SubMode mode = CommandState.SubMode.NONE;
private int startOff;
private int endOff;
}

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.text.CharSequenceReader;
import com.maddyhome.idea.vim.KeyHandler;
import com.maddyhome.idea.vim.VimPlugin;
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.ui.ExEntryPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.*;
@@ -73,7 +75,7 @@ public class ProcessGroup {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
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);
}
}
@@ -161,7 +163,7 @@ public class ProcessGroup {
// version 1050.
if (!ApplicationManager.getApplication().isUnitTestMode() && (flg & CommandParser.RES_DONT_REOPEN) == 0) {
VirtualFile vf = EditorData.getVirtualFile(editor);
if (vf != null) {
if (project != null && vf != null) {
FileEditorManager.getInstance(project).openFile(vf, true);
}
}
@@ -182,7 +184,7 @@ public class ProcessGroup {
public void run() {
//editor.getContentComponent().requestFocus();
VirtualFile vf = EditorData.getVirtualFile(editor);
if (vf != null) {
if (project != null && vf != null) {
FileEditorManager.getInstance(project).openFile(vf, true);
}
}
@@ -222,33 +224,37 @@ public class ProcessGroup {
return initText;
}
public boolean executeFilter(@NotNull Editor editor, @NotNull TextRange range, String command) throws IOException {
if (logger.isDebugEnabled()) logger.debug("command=" + command);
CharSequence chars = editor.getDocument().getCharsSequence();
StringReader car = new StringReader(chars.subSequence(range.getStartOffset(),
range.getEndOffset()).toString());
StringWriter sw = new StringWriter();
public boolean executeFilter(@NotNull Editor editor, @NotNull TextRange range,
@NotNull String command) throws IOException {
final CharSequence charsSequence = editor.getDocument().getCharsSequence();
final int startOffset = range.getStartOffset();
final int endOffset = range.getEndOffset();
final String output = executeCommand(command, charsSequence.subSequence(startOffset, endOffset));
editor.getDocument().replaceString(startOffset, endOffset, output);
return true;
}
logger.debug("about to create filter");
Process filter = Runtime.getRuntime().exec(command);
logger.debug("filter created");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(filter.getOutputStream()));
logger.debug("sending text");
copy(car, writer);
@NotNull
public String executeCommand(@NotNull String command, @Nullable CharSequence input) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("command=" + command);
}
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();
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;
return true;
return writer.toString();
}
private void copy(@NotNull Reader from, @NotNull Writer to) throws IOException {

View File

@@ -18,8 +18,12 @@
package com.maddyhome.idea.vim.group;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.diagnostic.Logger;
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.command.CommandState;
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.helper.EditorHelper;
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 org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -34,33 +42,45 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.*;
/**
* This group works with command associated with copying and pasting text
*/
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 READONLY_REGISTERS = ":.%#=/";
private static final String RECORDABLE_REGISTER = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String PLAYBACK_REGISTER = RECORDABLE_REGISTER + "\".*+";
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 char lastRegister = REGISTER_DEFAULT;
private char defaultRegister = '"';
private char lastRegister = defaultRegister;
@NotNull private final HashMap<Character, Register> registers = new HashMap<Character, Register>();
private char recordRegister = 0;
@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.
@@ -91,7 +111,7 @@ public class RegisterGroup {
* Reset the selected register back to the default register.
*/
public void resetRegister() {
lastRegister = REGISTER_DEFAULT;
lastRegister = defaultRegister;
logger.debug("register reset");
}
@@ -147,7 +167,7 @@ public class RegisterGroup {
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
}
}
else if (register == '*' || register == '+') {
else if (CLIPBOARD_REGISTERS.contains(register)) {
ClipboardHandler.setClipboardText(text);
}
// 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
if (register != REGISTER_DEFAULT && ".:/".indexOf(register) == -1) {
registers.put(REGISTER_DEFAULT, new Register(REGISTER_DEFAULT, type, text));
if (register != defaultRegister && ".:/".indexOf(register) == -1) {
registers.put(defaultRegister, new Register(defaultRegister, type, 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
else if (register == REGISTER_DEFAULT) {
else if (register == defaultRegister) {
registers.put('0', new Register('0', type, text));
if (logger.isDebugEnabled()) logger.debug("register '" + '0' + "' contains: \"" + text + "\"");
}
@@ -220,19 +240,7 @@ public class RegisterGroup {
if (Character.isUpperCase(r)) {
r = Character.toLowerCase(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;
return CLIPBOARD_REGISTERS.contains(r) ? refreshClipboardRegister(r) : registers.get(new Character(r));
}
/**
@@ -244,11 +252,23 @@ public class RegisterGroup {
return lastRegister;
}
/**
* The register key for the default register.
*/
public char getDefaultRegister() {
return defaultRegister;
}
@NotNull
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>());
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;
}
}
}

View File

@@ -187,6 +187,22 @@ public class EditorData {
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) {
Object res = editor.getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);
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<Boolean> CHANGE_GROUP = new Key<Boolean>("changeGroup");
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<ExOutputModel> EX_OUTPUT_MODEL = new Key<ExOutputModel>("IdeaVim.exOutputModel");

View File

@@ -113,6 +113,9 @@ public class SearchHelper {
}
int bend = findBlockLocation(chars, type, close, 1, bstart + 1, 1);
if (bend == -1) {
return null;
}
if (!isOuter) {
bstart++;
@@ -530,7 +533,7 @@ public class SearchHelper {
if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && !spaceWords) {
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;
}
}
@@ -1272,7 +1275,7 @@ public class SearchHelper {
}
}
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) {
offset++;
while (offset < max) {
@@ -1305,15 +1308,17 @@ public class SearchHelper {
}
}
else {
offset--;
while (offset >= 0) {
ch = chars.charAt(offset);
if (ch != '\n') {
offset++;
break;
}
if (offset > 0) {
offset--;
while (offset >= 0) {
ch = chars.charAt(offset);
if (ch != '\n') {
offset++;
break;
}
offset--;
}
}
if (offset < end) {

View File

@@ -33,6 +33,10 @@ import java.util.*;
* Maintains the set of support 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
*
@@ -80,6 +84,15 @@ public class Options {
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
*
@@ -447,6 +460,9 @@ public class Options {
addOption(new NumberOption("undolevels", "ul", 1000, -1, Integer.MAX_VALUE));
addOption(new ToggleOption("visualbell", "vb", false));
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) {

View File

@@ -114,7 +114,7 @@ public class ExEntryPanel extends JPanel {
oldGlass.addComponentListener(adapter);
positionPanel();
oldGlass.setVisible(true);
entry.requestFocus();
entry.requestFocusInWindow();
}
active = true;
}

View File

@@ -32,6 +32,8 @@ import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.Keymap;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.util.Date;
import java.util.List;
@@ -59,6 +61,16 @@ public class ExTextField extends JTextField {
loadKeymap(map, ExKeyBindings.getBindings(), actions);
map.setDefaultAction(new ExEditorKit.DefaultExKeyHandler());
setKeymap(map);
addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
setCaretPosition(getText().length());
}
@Override
public void focusLost(FocusEvent e) {
}
});
//origCaret = getCaret();
//blockCaret = new BlockCaret();

View File

@@ -1,5 +1,6 @@
package org.jetbrains.plugins.ideavim;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@@ -83,6 +84,12 @@ public abstract class VimTestCase extends UsefulTestCase {
return myFixture.getEditor();
}
@NotNull
protected Editor configureByJavaText(@NotNull String content) {
myFixture.configureByText(JavaFileType.INSTANCE, content);
return myFixture.getEditor();
}
@NotNull
protected Editor typeText(@NotNull final List<KeyStroke> keys) {
final Editor editor = myFixture.getEditor();

View File

@@ -1,6 +1,7 @@
package org.jetbrains.plugins.ideavim.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.project.Project;
import com.maddyhome.idea.vim.KeyHandler;
import com.maddyhome.idea.vim.VimPlugin;
@@ -20,20 +21,12 @@ import static com.maddyhome.idea.vim.helper.StringHelper.stringToKeys;
public class ChangeActionTest extends VimTestCase {
// |c| |t|
public void testChangeLinesTillForwards() {
doTest(parseKeys("ct(", "for "),
"<caret>if (condition) {\n" +
"}\n",
"for (condition) {\n" +
"}\n");
doTest(parseKeys("ct(", "for "), "<caret>if (condition) {\n" + "}\n", "for (condition) {\n" + "}\n");
}
// VIM-276 |c| |T|
public void testChangeLinesTillBackwards() {
doTest(parseKeys("cT("),
"if (condition) {<caret>\n" +
"}\n",
"if (\n" +
"}\n");
doTest(parseKeys("cT("), "if (condition) {<caret>\n" + "}\n", "if (\n" + "}\n");
}
// VIM-276 |c| |F|
@@ -67,9 +60,7 @@ public class ChangeActionTest extends VimTestCase {
// VIM-157 |~|
public void testToggleCharCase() {
doTest(parseKeys("~~"),
"<caret>hello world\n",
"HEllo world\n");
doTest(parseKeys("~~"), "<caret>hello world\n", "HEllo world\n");
}
// VIM-157 |~|
@@ -100,11 +91,7 @@ public class ChangeActionTest extends VimTestCase {
// |d| |w|
public void testDeleteLastWordBeforeEOL() {
doTest(parseKeys("dw"),
"one <caret>two\n" +
"three\n",
"one \n" +
"three\n");
doTest(parseKeys("dw"), "one <caret>two\n" + "three\n", "one \n" + "three\n");
}
// VIM-105 |d| |w|
@@ -128,17 +115,17 @@ public class ChangeActionTest extends VimTestCase {
// VIM-105 |d| |w| |count|
public void testDeleteTwoWordsOnTwoLines() {
doTest(parseKeys("d2w"),
"one <caret>two\n" +
"three four\n",
"one four\n");
doTest(parseKeys("d2w"), "one <caret>two\n" + "three four\n", "one four\n");
}
// VIM-200 |c| |w|
public void testChangeWordAtLastChar() {
doTest(parseKeys("cw"),
"on<caret>e two three\n",
"on two three\n");
doTest(parseKeys("cw"), "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|
@@ -156,13 +143,18 @@ public class ChangeActionTest extends VimTestCase {
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|
public void testDeleteIndentedWordBeforePunctuation() {
doTest(parseKeys("daw"),
"foo\n" +
" <caret>bar, baz\n",
"foo\n" +
" , baz\n");
doTest(parseKeys("daw"), "foo\n" + " <caret>bar, baz\n", "foo\n" + " , baz\n");
}
// |d| |v_aw|
@@ -182,18 +174,13 @@ public class ChangeActionTest extends VimTestCase {
// VIM-393 |d|
public void testDeleteBadArgument() {
doTest(parseKeys("dD", "dd"),
"one\n" +
"two\n",
"two\n");
doTest(parseKeys("dD", "dd"), "one\n" + "two\n", "two\n");
}
// VIM-262 |i_CTRL-R|
public void testInsertFromRegister() {
VimPlugin.getRegister().setKeys('a', stringToKeys("World"));
doTest(parseKeys("A", ", ", "<C-R>", "a", "!"),
"<caret>Hello\n",
"Hello, World!\n");
doTest(parseKeys("A", ", ", "<C-R>", "a", "!"), "<caret>Hello\n", "Hello, World!\n");
}
// VIM-421 |c| |w|
@@ -212,9 +199,7 @@ public class ChangeActionTest extends VimTestCase {
// VIM-421 |c| |w|
public void testChangeLastCharInLine() {
doTest(parseKeys("cw"),
"fo<caret>o\n",
"fo<caret>\n");
doTest(parseKeys("cw"), "fo<caret>o\n", "fo<caret>\n");
}
// VIM-404 |O|
@@ -270,14 +255,83 @@ public class ChangeActionTest extends VimTestCase {
"bar\n" +
"baz\n" +
"quux\n",
"<caret>oo\n" +
"ar\n" +
"az\n" +
"<caret>o\n" +
"r\n" +
"z\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) {
myFixture.configureByText("a.java", before);
myFixture.configureByText(PlainTextFileType.INSTANCE, before);
final Editor editor = myFixture.getEditor();
final KeyHandler keyHandler = KeyHandler.getInstance();
final EditorDataContext dataContext = new EditorDataContext(editor);

View File

@@ -2,6 +2,10 @@ package org.jetbrains.plugins.ideavim.action;
import com.intellij.openapi.editor.Editor;
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 static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
@@ -29,6 +33,17 @@ public class CopyActionTest extends VimTestCase {
"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|
public void testYankLinePasteAtLastLine() {
typeTextInFile(parseKeys("yy", "p"),
@@ -64,10 +79,9 @@ public class CopyActionTest extends VimTestCase {
public void testWrongYankQuoteYankLine() {
assertPluginError(false);
typeTextInFile(parseKeys("y\"", "yy", "p"),
"one <caret>two\n" +
"three\n" +
"four\n");
typeTextInFile(parseKeys("y\"", "yy", "p"), "one <caret>two\n" +
"three\n" +
"four\n");
assertPluginError(false);
myFixture.checkResult("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
myFixture.checkResult("* *one\n" +
"* *two\n");
myFixture.checkResult("* * one\n" +
"* * two\n");
assertSelection(null);
assertOffset(2);
}
@@ -112,4 +126,49 @@ public class CopyActionTest extends VimTestCase {
assertMode(CommandState.Mode.COMMAND);
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");
}
}
}

View File

@@ -84,6 +84,54 @@ public class MotionActionTest extends VimTestCase {
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|
public void testDeleteInnerBlock() {
typeTextInFile(parseKeys("di)"),
@@ -113,6 +161,12 @@ public class MotionActionTest extends VimTestCase {
assertOffset(4);
}
// |v_ib|
public void testInnerBlockCrashWhenNoDelimiterFound() {
typeTextInFile(parseKeys("di)"), "(x\n");
myFixture.checkResult("(x\n");
}
// VIM-314 |d| |v_iB|
public void testDeleteInnerCurlyBraceBlock() {
typeTextInFile(parseKeys("di{"),
@@ -198,6 +252,12 @@ public class MotionActionTest extends VimTestCase {
myFixture.checkResult("Hello World! Bye.\n");
}
// |v_as|
public void testSentenceMotionPastStartOfFile() {
typeTextInFile(parseKeys("8("), "\n" +
"P<caret>.\n");
}
// |d| |v_ip|
public void testDeleteInnerParagraph() {
typeTextInFile(parseKeys("dip"),
@@ -500,6 +560,13 @@ public class MotionActionTest extends VimTestCase {
assertOffset(2);
}
// |b|
public void testWordBackwardsAtFirstLineWithWhitespaceInFront() {
typeTextInFile(parseKeys("b"),
" <caret>x\n");
assertOffset(0);
}
public void testRightToLastChar() {
typeTextInFile(parseKeys("i<Right>"),
"on<caret>e\n");

View File

@@ -52,4 +52,16 @@ public class ShiftRightLinesActionTest extends VimTestCase {
typeText(parseKeys("vG$>>"));
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<>"));
}
}

View File

@@ -1,5 +1,6 @@
package org.jetbrains.plugins.ideavim.ex;
import com.maddyhome.idea.vim.command.CommandState;
import org.jetbrains.plugins.ideavim.VimTestCase;
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
@@ -27,4 +28,14 @@ public class VariousCommandsTest extends VimTestCase {
myFixture.checkResult("Hello World!\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");
}
}