mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
17 Commits
0.56
...
0.56.1-EAP
Author | SHA1 | Date | |
---|---|---|---|
![]() |
55f54b2e82 | ||
![]() |
1b18065e68 | ||
![]() |
053dc02152 | ||
![]() |
b8cb4a1295 | ||
![]() |
cd2cbf68a1 | ||
![]() |
73f3be8af0 | ||
![]() |
8cce059fb4 | ||
![]() |
db641ec6f6 | ||
![]() |
9d8239b68d | ||
![]() |
4ec0bac275 | ||
![]() |
613c234cfb | ||
![]() |
83dca71f69 | ||
![]() |
f7ea9cdb6e | ||
![]() |
762cb1804f | ||
![]() |
962cfb7ae2 | ||
![]() |
8415d104e9 | ||
![]() |
abd0f9b961 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,10 @@
|
||||
*.swp
|
||||
/.gradle/
|
||||
|
||||
/.idea/
|
||||
!/.idea/scopes
|
||||
!/.idea/copyright
|
||||
|
||||
/build/
|
||||
/out/
|
||||
/tmp/
|
6
.idea/copyright/IdeaVim.xml
generated
Normal file
6
.idea/copyright/IdeaVim.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="IdeaVim - Vim emulator for IDEs based on the IntelliJ platform Copyright (C) 2003-&#36;today.year The IdeaVim authors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>." />
|
||||
<option name="myName" value="IdeaVim" />
|
||||
</copyright>
|
||||
</component>
|
7
.idea/copyright/profiles_settings.xml
generated
Normal file
7
.idea/copyright/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings>
|
||||
<module2copyright>
|
||||
<element module="Copyright" copyright="IdeaVim" />
|
||||
</module2copyright>
|
||||
</settings>
|
||||
</component>
|
3
.idea/scopes/Copyright.xml
generated
Normal file
3
.idea/scopes/Copyright.xml
generated
Normal file
@@ -0,0 +1,3 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<scope name="Copyright" pattern="file[IdeaVIM.main]:com//*||file[IdeaVIM.test]:*/" />
|
||||
</component>
|
@@ -287,6 +287,10 @@ Contributors:
|
||||
[![icon][github]](https://github.com/kevin70)
|
||||
|
||||
kk
|
||||
* [![icon][mail]](mailto:runforprogram@163.com)
|
||||
[![icon][github]](https://github.com/runforprogram)
|
||||
|
||||
runforprogram
|
||||
|
||||
If you are a contributor and your name is not listed here, feel free to
|
||||
contact the maintainers.
|
||||
|
14
CHANGES.md
14
CHANGES.md
@@ -22,6 +22,20 @@ It is important to distinguish EAP from traditional pre-release software.
|
||||
Please note that the quality of EAP versions may at times be way below even
|
||||
usual beta standards.
|
||||
|
||||
[To Be Released]
|
||||
-------------
|
||||
|
||||
_Available since 0.56.1 EAP:_
|
||||
|
||||
**Fixes:**
|
||||
* [VIM-1992](https://youtrack.jetbrains.com/issue/VIM-1992) Fix mappings to `<S-Letter>`
|
||||
* [VIM-1991](https://youtrack.jetbrains.com/issue/VIM-1991) Fix working with number registers
|
||||
|
||||
**Merged PRs:**
|
||||
* [234](https://github.com/JetBrains/ideavim/pull/234) by [runforprogram](https://github.com/runforprogram): [VIM-1991] fix >0 number register not work
|
||||
|
||||
_To Be Released..._
|
||||
|
||||
0.56, 2020-04-09
|
||||
--------------
|
||||
|
||||
|
@@ -79,36 +79,6 @@ in the issue tracker.
|
||||
* You can install this file by selecting "Settings | Plugins | Install plugin
|
||||
from disk...".
|
||||
|
||||
### Copyright
|
||||
|
||||
1. Go to `Preferences | Appearance & Behavior | Scopes`, press "+" button, `Shared`.
|
||||
Name: Copyright scope
|
||||
Pattern: `file[IdeaVIM.main]:com//*||file[IdeaVIM.test]:*/`
|
||||
|
||||
2. Go to `Preferences | Editor | Copyright | Copyright Profiles` and click the "+" button.
|
||||
Name: IdeaVim
|
||||
Text:
|
||||
|
||||
IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
Copyright (C) 2003-$today.year The IdeaVim authors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
3. Go to `Preferences | Editor | Copyright`, click the "+" button.
|
||||
Scope: Copyright scope
|
||||
Copyright: IdeaVim
|
||||
|
||||
### Testing
|
||||
|
||||
1. Read about the `@VimBehaviorDiffers` annotation.
|
||||
|
119
README.md
119
README.md
@@ -25,23 +25,20 @@ Resources:
|
||||
* [@IdeaVim](https://twitter.com/ideavim) in Twitter
|
||||
|
||||
|
||||
Installation
|
||||
Setup
|
||||
------------
|
||||
|
||||
Use the IDE's plugin manager to install the latest version of the plugin.
|
||||
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.
|
||||
- IdeaVim can be installed via `Settings | Plugins`.
|
||||
See [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#).
|
||||
|
||||
If you wish to disable the plugin, select the "Tools | Vim Emulator" menu so
|
||||
it is unchecked. At this point your IDE will work with its regular keyboard
|
||||
shortcuts.
|
||||
- Use `Tools | Vim Emulator` to enable or disable emulation.
|
||||
|
||||
Keyboard shortcut conflicts between the Vim emulation and the IDE can be
|
||||
resolved via "File | Settings | Editor | Vim Emulation", "File | Settings |
|
||||
Keymap" on Linux & Windows, and via "Preferences | Editor | Vim Emulation",
|
||||
"Preferences | Keymap" on macOS. They can also be resolved by key-mapping
|
||||
commands in your ~/.ideavimrc file.
|
||||
- Use `~/.ideavimrc` file as an analog of `~/.vimrc` ([details](#Files)). XGD standard is supported as well.
|
||||
|
||||
- Shortcut conflicts can be resolved using:
|
||||
- Linux & Windows: `File | Settings | Editor | Vim Emulation` & `File | Settings | Keymap`,
|
||||
- macOS: `Preferences | Editor | Vim Emulation` & `Preferences | Keymap`,
|
||||
- regular vim mappings in the `~/.ideavimrc` file.
|
||||
|
||||
Get Early Access
|
||||
-------------------
|
||||
@@ -49,7 +46,9 @@ Get Early Access
|
||||
Would you like to try new features and fixes? Join the Early Access Program and
|
||||
receive EAP builds as updates!
|
||||
|
||||
1. Click the IdeaVim icon in the status bar | `EAP` | `Get Early Access...`
|
||||
1. Click the IdeaVim icon <img src="resources/META-INF/pluginIcon_noBorders.svg" width="16" height="16" alt="icon"/>
|
||||
in the status bar | `EAP` | `Get Early Access...`
|
||||
|
||||
|
||||
Or subscribe to EAP updates manually:
|
||||
|
||||
@@ -57,7 +56,7 @@ Or subscribe to EAP updates manually:
|
||||
2. Click the gear icon :gear:, select `Manage Plugin Repositories`, and add the following url:
|
||||
`https://plugins.jetbrains.com/plugins/eap/ideavim`
|
||||
|
||||
See [the changelog](CHANGES.md) for the list of hot unreleased features.
|
||||
See [the changelog](CHANGES.md) for the list of unreleased features.
|
||||
|
||||
It is important to distinguish EAP builds from traditional pre-release software.
|
||||
Please note that the quality of EAP versions may at times be way below even
|
||||
@@ -91,7 +90,7 @@ Supported:
|
||||
* Vim web help
|
||||
* Select mode
|
||||
|
||||
Emulated Vim plugins:
|
||||
[Emulated Vim plugins](doc/emulated-plugins.md):
|
||||
|
||||
* vim-easymotion
|
||||
* vim-surround
|
||||
@@ -115,19 +114,19 @@ See also:
|
||||
Files
|
||||
-----
|
||||
|
||||
* ~/.ideavimrc
|
||||
* `~/.ideavimrc`
|
||||
* Your IdeaVim-specific Vim initialization commands
|
||||
|
||||
You can read your ~/.vimrc file from ~/.ideavimrc with this command:
|
||||
You can read your `~/.vimrc` file from `~/.ideavimrc` with this command:
|
||||
|
||||
source ~/.vimrc
|
||||
|
||||
Note, that IdeaVim currently parses ~/.ideavimrc file via simple pattern matching.
|
||||
Note, that IdeaVim currently parses `~/.ideavimrc` file via simple pattern matching.
|
||||
See [VIM-669](https://youtrack.jetbrains.com/issue/VIM-669) for proper parsing
|
||||
of VimL files.
|
||||
|
||||
Also note that if you have overridden the `user.home` JVM option, this
|
||||
will affect where IdeaVim looks for your .ideavimrc file. For example, if you
|
||||
will affect where IdeaVim looks for your `.ideavimrc` file. For example, if you
|
||||
have `-Duser.home=/my/alternate/home` then IdeaVim will source
|
||||
`/my/alternate/home/.ideavimrc` instead of `~/.ideavimrc`.
|
||||
|
||||
@@ -138,62 +137,25 @@ Put your settings to `$XDG_CONFIG_HOME$/ideavim/ideavimrc` file.
|
||||
Emulated Vim Plugins
|
||||
--------------------
|
||||
|
||||
IdeaVim extensions emulate some plugins of the original Vim. In order to use
|
||||
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
|
||||
|
||||
set <extension-name>
|
||||
|
||||
Available extensions:
|
||||
|
||||
* easymotion
|
||||
* Setup:
|
||||
* Install [IdeaVim-EasyMotion](https://plugins.jetbrains.com/plugin/13360-ideavim-easymotion/)
|
||||
and [AceJump](https://plugins.jetbrains.com/plugin/7086-acejump/) plugins.
|
||||
* `set easymotion`
|
||||
* Emulates [vim-easymotion](https://github.com/easymotion/vim-easymotion)
|
||||
* Commands: All commands with the mappings are supported. See the [full list of supported commands](https://github.com/AlexPl292/IdeaVim-EasyMotion#supported-commands).
|
||||
|
||||
* surround
|
||||
* Setup: `set surround`
|
||||
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
|
||||
* Commands: `ys`, `cs`, `ds`, `S`
|
||||
|
||||
* multiple-cursors
|
||||
* Setup: `set multiple-cursors`
|
||||
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
|
||||
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
|
||||
|
||||
* commentary
|
||||
* Setup: `set commentary`
|
||||
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
|
||||
* Commands: `gcc`, `gc + motion`, `v_gc`
|
||||
|
||||
* ReplaceWithRegister
|
||||
* Setup: `set ReplaceWithRegister`
|
||||
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
|
||||
* Commands: `gr`, `grr`
|
||||
|
||||
* argtextobj
|
||||
* Setup:
|
||||
* `set argtextobj`
|
||||
* By default, only the arguments inside parenthesis are considered. To extend the functionality
|
||||
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
|
||||
list of colon-separated pairs (same as VIM's `matchpairs` option), like
|
||||
`let g:argtextobj_pairs="(:),{:},<:>"`. The order of pairs matters when
|
||||
handling symbols that can also be operators: `func(x << 5, 20) >> 17`. To handle
|
||||
this syntax parenthesis, must come before angle brackets in the list.
|
||||
* Emulates [argtextobj.vim](https://www.vim.org/scripts/script.php?script_id=2699)
|
||||
* Additional text objects: `aa`, `ia`
|
||||
|
||||
* textobj-entire
|
||||
* Setup: `set textobj-entire`
|
||||
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
|
||||
* Additional text objects: `ae`, `ie`
|
||||
|
||||
See [doc/emulated-plugins.md](doc/emulated-plugins.md)
|
||||
|
||||
Changes to the IDE
|
||||
------------------
|
||||
|
||||
### 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 or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
||||
* `:action {name}`
|
||||
* Execute an action named `NAME`
|
||||
|
||||
For example, here `\r` is mapped to the Reformat Code action:
|
||||
|
||||
:map \r :action ReformatCode<CR>
|
||||
|
||||
### Undo/Redo
|
||||
|
||||
The IdeaVim plugin uses the undo/redo functionality of the IntelliJ Platform,
|
||||
@@ -212,21 +174,6 @@ improvement.
|
||||
|
||||
See also [unresolved escape issues](https://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 or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
||||
* `:action {name}`
|
||||
* Execute an action named `NAME`
|
||||
|
||||
For example, here `\r` is mapped to the Reformat Code action:
|
||||
|
||||
:map \r :action ReformatCode<CR>
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
|
@@ -9,7 +9,7 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.jetbrains.intellij' version '0.4.16'
|
||||
id 'org.jetbrains.intellij' version '0.4.18'
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
@@ -80,13 +80,13 @@ tasks.register("slackEapNotification") {
|
||||
changeLog = changeLog.replaceAll("\\[(.+)]\\(([^)]+)\\)", '<$2|$1>') // Enable links
|
||||
def message ="""
|
||||
{
|
||||
"text": "Danny Torrence left a 1 star review for your property.",
|
||||
"text": "New version of IdeaVim",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "New EAP released: $version\\n$changeLog"
|
||||
"text": "IdeaVim EAP $version has been relesed\\n$changeLog"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
62
doc/emulated-plugins.md
Normal file
62
doc/emulated-plugins.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Emulated Vim Plugins
|
||||
--------------------
|
||||
|
||||
IdeaVim extensions emulate plugins of the original Vim. In order to use
|
||||
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
|
||||
|
||||
set <extension-name>
|
||||
|
||||
Available extensions:
|
||||
|
||||
## easymotion
|
||||
|
||||
* Setup:
|
||||
* Install [IdeaVim-EasyMotion](https://plugins.jetbrains.com/plugin/13360-ideavim-easymotion/)
|
||||
and [AceJump](https://plugins.jetbrains.com/plugin/7086-acejump/) plugins.
|
||||
* `set easymotion`
|
||||
* Emulates [vim-easymotion](https://github.com/easymotion/vim-easymotion)
|
||||
* Commands: All commands with the mappings are supported. See the [full list of supported commands](https://github.com/AlexPl292/IdeaVim-EasyMotion#supported-commands).
|
||||
|
||||
## surround
|
||||
|
||||
* Setup: `set surround`
|
||||
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
|
||||
* Commands: `ys`, `cs`, `ds`, `S`
|
||||
|
||||
## multiple-cursors
|
||||
|
||||
* Setup: `set multiple-cursors`
|
||||
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
|
||||
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
|
||||
|
||||
## commentary
|
||||
|
||||
* Setup: `set commentary`
|
||||
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
|
||||
* Commands: `gcc`, `gc + motion`, `v_gc`
|
||||
|
||||
## ReplaceWithRegister
|
||||
|
||||
* Setup: `set ReplaceWithRegister`
|
||||
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
|
||||
* Commands: `gr`, `grr`
|
||||
|
||||
## argtextobj
|
||||
|
||||
* Setup:
|
||||
* `set argtextobj`
|
||||
* By default, only the arguments inside parenthesis are considered. To extend the functionality
|
||||
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
|
||||
list of colon-separated pairs (same as VIM's `matchpairs` option), like
|
||||
`let g:argtextobj_pairs="(:),{:},<:>"`. The order of pairs matters when
|
||||
handling symbols that can also be operators: `func(x << 5, 20) >> 17`. To handle
|
||||
this syntax parenthesis, must come before angle brackets in the list.
|
||||
* Emulates [argtextobj.vim](https://www.vim.org/scripts/script.php?script_id=2699)
|
||||
* Additional text objects: `aa`, `ia`
|
||||
|
||||
## textobj-entire
|
||||
|
||||
* Setup: `set textobj-entire`
|
||||
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
|
||||
* Additional text objects: `ae`, `ie`
|
||||
|
@@ -1,11 +1,11 @@
|
||||
# suppress inspection "UnusedProperty" for whole file
|
||||
|
||||
ideaVersion=201-EAP-SNAPSHOT
|
||||
ideaVersion=2020.1
|
||||
downloadIdeaSources=true
|
||||
instrumentPluginCode=true
|
||||
version=SNAPSHOT
|
||||
javaVersion=1.8
|
||||
kotlinVersion=1.3.70
|
||||
kotlinVersion=1.3.71
|
||||
publishUsername=username
|
||||
publishToken=token
|
||||
publishChannels=eap
|
||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
#Fri Mar 20 11:41:45 MSK 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-all.zip
|
||||
#Fri Apr 10 10:57:10 MSK 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
|
@@ -3,12 +3,8 @@
|
||||
<id>IdeaVIM</id>
|
||||
<change-notes><![CDATA[
|
||||
<ul>
|
||||
<li>Support ReplaceWithRegister plugin emulation</li>
|
||||
<li>Support argtextobj.vim plugin emulation</li>
|
||||
<li>Support vim-textobj-entire plugin emulation</li>
|
||||
<li>Support showcmd command</li>
|
||||
<li>Support ls/buffers/files command</li>
|
||||
<li>Control the icon in the status bar using an `ideastatusicon` option</li>
|
||||
<li>Fix mappings for `<S-Letter>`</li>
|
||||
<li>Fix yank/paste with number registers</li>
|
||||
<li>Various bug fixes</li>
|
||||
</ul>
|
||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||
|
9
resources/META-INF/pluginIcon_noBorders.svg
Normal file
9
resources/META-INF/pluginIcon_noBorders.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
|
||||
<defs>
|
||||
<linearGradient id="ideavim_plugin-a" x1="-6.748%" x2="47.286%" y1="33.61%" y2="85.907%">
|
||||
<stop offset="0%" stop-color="#3BEA62"/>
|
||||
<stop offset="100%" stop-color="#087CFA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<polygon fill="url(#ideavim_plugin-a)" fill-rule="evenodd" points="29.019 0 13.988 26.119 13.988 0 0 0 0 40 16.953 40 40 0"/>
|
||||
</svg>
|
After Width: | Height: | Size: 450 B |
@@ -563,7 +563,9 @@ public class KeyHandler {
|
||||
private boolean isCommandCountKey(char chKey, @NotNull CommandState editorState) {
|
||||
// Make sure to avoid handling '0' as the start of a count.
|
||||
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
|
||||
return (editorState.getMode() == CommandState.Mode.COMMAND || editorState.getMode() == CommandState.Mode.VISUAL)
|
||||
return ((editorState.getMode() == CommandState.Mode.COMMAND
|
||||
&&editorState.getSubMode()!=CommandState.SubMode.REGISTER_PENDING)
|
||||
|| editorState.getMode() == CommandState.Mode.VISUAL)
|
||||
&& commandBuilder.isExpectingCount() && Character.isDigit(chKey) && (commandBuilder.getCount() > 0 || chKey != '0');
|
||||
}
|
||||
|
||||
|
@@ -29,17 +29,35 @@ import com.maddyhome.idea.vim.command.Command
|
||||
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
|
||||
import com.maddyhome.idea.vim.helper.vimLastColumn
|
||||
|
||||
sealed class ChangeEditorActionHandler : VimActionHandler.SingleExecution() {
|
||||
/**
|
||||
* Base handler for commands that performs change actions.
|
||||
* This handler stores the commands and they can be repeated later with dot command.
|
||||
*
|
||||
* Use subclasses of this handler:
|
||||
* - [ChangeEditorActionHandler.SingleExecution]
|
||||
* - [ChangeEditorActionHandler.ForEachCaret]
|
||||
*/
|
||||
sealed class ChangeEditorActionHandler : EditorActionHandlerBase(false) {
|
||||
|
||||
/**
|
||||
* This handler executes an action for each caret. That means that if you have 5 carets, [execute] will be
|
||||
* called 5 times.
|
||||
* @see [ChangeEditorActionHandler.SingleExecution] for only one execution.
|
||||
*/
|
||||
abstract class ForEachCaret : ChangeEditorActionHandler() {
|
||||
abstract fun execute(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* This handler executes an action only once for all carets. That means that if you have 5 carets,
|
||||
* [execute] will be called 1 time.
|
||||
* @see [ChangeEditorActionHandler.ForEachCaret] for per-caret execution
|
||||
*/
|
||||
abstract class SingleExecution : ChangeEditorActionHandler() {
|
||||
abstract fun execute(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Boolean
|
||||
}
|
||||
|
||||
final override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||
final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
// Here we have to save the last changed command. This should be done separately for each
|
||||
// call of the task, not for each caret. Currently there is no way to schedule any action
|
||||
// to be worked after each task. So here we override the deprecated execute function which
|
||||
@@ -50,9 +68,9 @@ sealed class ChangeEditorActionHandler : VimActionHandler.SingleExecution() {
|
||||
val worked = Ref.create(true)
|
||||
when (this) {
|
||||
is ForEachCaret -> {
|
||||
editor.caretModel.runForEachCaret({ caret ->
|
||||
if (!caret.isValid) return@runForEachCaret
|
||||
if (!execute(editor, caret, context, cmd.count, cmd.rawCount, cmd.argument)) {
|
||||
editor.caretModel.runForEachCaret({ current ->
|
||||
if (!current.isValid) return@runForEachCaret
|
||||
if (!execute(editor, current, context, cmd.count, cmd.rawCount, cmd.argument)) {
|
||||
worked.set(false)
|
||||
}
|
||||
}, true)
|
||||
|
@@ -36,52 +36,22 @@ import java.util.*
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
/**
|
||||
* Structure of handlers
|
||||
* `~` - this symbol means that this handler cannot be used directly (only its children)
|
||||
* Almost each handler isn't usable by itself and has two children - "SingleExecution" and "ForEachCaret"
|
||||
* which should be used
|
||||
* All the commands in IdeaVim should implement one of the following handlers and be registered in VimActions.xml
|
||||
* Check the KtDocs of handlers for the details.
|
||||
*
|
||||
* ~ EditorActionHandlerBase ~
|
||||
* |
|
||||
* ----------------------------------------------------------------------------
|
||||
* | | |
|
||||
* ~ ForEachCaret ~ ~ SingleExecution ~ ~ VimActionHandler ~
|
||||
* | | / \
|
||||
* TextObjectActionHandler MotionActionHandler / \
|
||||
* SingleExecution ForEachCaret
|
||||
* |
|
||||
* -------------------------------------------------------------
|
||||
* | |
|
||||
* ~ ChangeEditorActionHandler ~ ~ VisualOperatorActionHandler ~
|
||||
* / \ / \
|
||||
* SingleExecution ForEachCaret SingleExecution ForEachCaret
|
||||
* Structure of handlers:
|
||||
*
|
||||
* - [EditorActionHandlerBase]: Base handler for all handlers. Please don't use it directly.
|
||||
* - [VimActionHandler]: .............. Common vim commands.. E.g.: u, <C-W>s, <C-D>.
|
||||
* - [TextObjectActionHandler]: ....... Text objects. ....... E.g.: iw, a(, i>
|
||||
* - [MotionActionHandler]: ........... Motion commands. .... E.g.: k, w, <Up>
|
||||
* - [ChangeEditorActionHandler]: ..... Change commands. .... E.g.: s, r, gU
|
||||
* - [VisualOperatorActionHandler]: ... Visual commands.
|
||||
*
|
||||
* SpecialKeyHandlers are not presented here because these handlers are created to a limited set of commands and they
|
||||
* are already implemented
|
||||
* are already implemented.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handler for common usage
|
||||
*/
|
||||
sealed class VimActionHandler(myRunForEachCaret: Boolean) : EditorActionHandlerBase(myRunForEachCaret) {
|
||||
abstract class ForEachCaret : VimActionHandler(true) {
|
||||
abstract fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean
|
||||
}
|
||||
|
||||
abstract class SingleExecution : VimActionHandler(false) {
|
||||
abstract fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean
|
||||
}
|
||||
|
||||
final override fun baseExecute(editor: Editor, caret: Caret?, context: DataContext, cmd: Command): Boolean {
|
||||
return when (this) {
|
||||
is ForEachCaret -> caret == null || execute(editor, caret, context, cmd)
|
||||
is SingleExecution -> execute(editor, context, cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
|
||||
abstract class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
|
||||
val id: String = getActionId(this::class.java.name)
|
||||
|
||||
abstract val type: Command.Type
|
||||
@@ -97,25 +67,7 @@ sealed class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
|
||||
*/
|
||||
open val flags: EnumSet<CommandFlags> = noneOfEnum()
|
||||
|
||||
|
||||
abstract class ForEachCaret : EditorActionHandlerBase(true) {
|
||||
abstract fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean
|
||||
|
||||
final override fun baseExecute(editor: Editor, caret: Caret?, context: DataContext, cmd: Command): Boolean {
|
||||
if (caret == null) return false
|
||||
return execute(editor, caret, context, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SingleExecution : EditorActionHandlerBase(false) {
|
||||
abstract fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean
|
||||
|
||||
final override fun baseExecute(editor: Editor, caret: Caret?, context: DataContext, cmd: Command): Boolean {
|
||||
return execute(editor, context, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun baseExecute(editor: Editor, caret: Caret?, context: DataContext, cmd: Command): Boolean
|
||||
abstract fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean
|
||||
|
||||
fun execute(editor: Editor, context: DataContext) {
|
||||
val hostEditor: Editor = CommonDataKeys.HOST_EDITOR.getData(context) ?: editor
|
||||
|
@@ -42,7 +42,7 @@ import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
* Base class for motion handlers.
|
||||
* @see [MotionActionHandler.SingleExecution] and [MotionActionHandler.ForEachCaret]
|
||||
*/
|
||||
sealed class MotionActionHandler : EditorActionHandlerBase.SingleExecution() {
|
||||
sealed class MotionActionHandler : EditorActionHandlerBase(false) {
|
||||
|
||||
/**
|
||||
* Base class for motion handlers.
|
||||
@@ -127,7 +127,7 @@ sealed class MotionActionHandler : EditorActionHandlerBase.SingleExecution() {
|
||||
}
|
||||
}
|
||||
|
||||
final override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||
final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
val blockSubmodeActive = editor.inBlockSubMode
|
||||
|
||||
when (this) {
|
||||
|
@@ -41,10 +41,16 @@ import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
*
|
||||
* This handler gets executed for each caret.
|
||||
*/
|
||||
abstract class TextObjectActionHandler : EditorActionHandlerBase.ForEachCaret() {
|
||||
abstract class TextObjectActionHandler : EditorActionHandlerBase(true) {
|
||||
|
||||
final override val type: Command.Type = Command.Type.MOTION
|
||||
|
||||
abstract fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange?
|
||||
override fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
|
||||
/**
|
||||
* This code is called when user executes text object in visual mode. E.g. `va(a(a(`
|
||||
*/
|
||||
final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
if (!editor.inVisualMode) return true
|
||||
|
||||
val range = getRange(editor, caret, context, cmd.count, cmd.rawCount, cmd.argument) ?: return false
|
||||
|
58
src/com/maddyhome/idea/vim/handler/VimActionHandler.kt
Normal file
58
src/com/maddyhome/idea/vim/handler/VimActionHandler.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.maddyhome.idea.vim.handler
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Caret
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.command.Command
|
||||
|
||||
/**
|
||||
* Handler for common usage.
|
||||
*
|
||||
* Use subclasses of this handler:
|
||||
* - [VimActionHandler.SingleExecution]
|
||||
* - [VimActionHandler.ForEachCaret]
|
||||
*/
|
||||
sealed class VimActionHandler(myRunForEachCaret: Boolean) : EditorActionHandlerBase(myRunForEachCaret) {
|
||||
/**
|
||||
* This handler executes an action for each caret. That means that if you have 5 carets,
|
||||
* [execute] will be called 5 times.
|
||||
* @see [VimActionHandler.SingleExecution] for only one execution.
|
||||
*/
|
||||
abstract class ForEachCaret : VimActionHandler(true) {
|
||||
abstract fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* This handler executes an action only once for all carets. That means that if you have 5 carets,
|
||||
* [execute] will be called 1 time.
|
||||
* @see [VimActionHandler.ForEachCaret] for per-caret execution.
|
||||
*/
|
||||
abstract class SingleExecution : VimActionHandler(false) {
|
||||
abstract fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean
|
||||
}
|
||||
|
||||
final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
return when (this) {
|
||||
is ForEachCaret -> execute(editor, caret, context, cmd)
|
||||
is SingleExecution -> execute(editor, context, cmd)
|
||||
}
|
||||
}
|
||||
}
|
@@ -52,14 +52,17 @@ import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
* @author Alex Plate
|
||||
*
|
||||
* Base class for visual operation handlers.
|
||||
* @see [VisualOperatorActionHandler.SingleExecution] and [VisualOperatorActionHandler.ForEachCaret]
|
||||
*
|
||||
* Use subclasses of this handler:
|
||||
* - [VisualOperatorActionHandler.SingleExecution]
|
||||
* - [VisualOperatorActionHandler.ForEachCaret]
|
||||
*/
|
||||
sealed class VisualOperatorActionHandler : VimActionHandler.SingleExecution() {
|
||||
sealed class VisualOperatorActionHandler : EditorActionHandlerBase(false) {
|
||||
/**
|
||||
* Base class for visual operation handlers.
|
||||
* This handler executes an action for each caret. That means that if you have 5 carets,
|
||||
* [executeAction] will be called 5 times.
|
||||
* @see [VisualOperatorActionHandler.SingleExecution] for only one execution
|
||||
* @see [VisualOperatorActionHandler.SingleExecution] for only one execution.
|
||||
*/
|
||||
abstract class ForEachCaret : VisualOperatorActionHandler() {
|
||||
|
||||
@@ -90,7 +93,7 @@ sealed class VisualOperatorActionHandler : VimActionHandler.SingleExecution() {
|
||||
/**
|
||||
* Base class for visual operation handlers.
|
||||
* This handler executes an action only once for all carets. That means that if you have 5 carets,
|
||||
* [executeAction] will be called 1 time.
|
||||
* [executeForAllCarets] will be called 1 time.
|
||||
* @see [VisualOperatorActionHandler.ForEachCaret] for per-caret execution
|
||||
*/
|
||||
abstract class SingleExecution : VisualOperatorActionHandler() {
|
||||
@@ -104,7 +107,7 @@ sealed class VisualOperatorActionHandler : VimActionHandler.SingleExecution() {
|
||||
abstract fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map<Caret, VimSelection>): Boolean
|
||||
}
|
||||
|
||||
final override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||
final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean {
|
||||
logger.info("Execute visual command $cmd")
|
||||
|
||||
editor.vimChangeActionSwitchMode = null
|
||||
@@ -131,9 +134,9 @@ sealed class VisualOperatorActionHandler : VimActionHandler.SingleExecution() {
|
||||
when {
|
||||
selections.keys.isEmpty() -> return false
|
||||
selections.keys.size == 1 -> res.set(executeAction(editor, selections.keys.first(), context, cmd, selections.values.first()))
|
||||
else -> editor.caretModel.runForEachCaret({ caret ->
|
||||
val range = selections.getValue(caret)
|
||||
val loopRes = executeAction(editor, caret, context, cmd, range)
|
||||
else -> editor.caretModel.runForEachCaret({ currentCaret ->
|
||||
val range = selections.getValue(currentCaret)
|
||||
val loopRes = executeAction(editor, currentCaret, context, cmd, range)
|
||||
res.set(loopRes and res.get())
|
||||
}, true)
|
||||
}
|
||||
|
@@ -535,8 +535,8 @@ public class StringHelper {
|
||||
if (modifiers == 0) {
|
||||
return getKeyStroke(c);
|
||||
}
|
||||
else if (modifiers == SHIFT_DOWN_MASK) {
|
||||
return getKeyStroke(Character.toUpperCase(c), modifiers);
|
||||
else if (modifiers == SHIFT_DOWN_MASK && Character.isLetter(c)) {
|
||||
return getKeyStroke(Character.toUpperCase(c));
|
||||
}
|
||||
else {
|
||||
return getKeyStroke(Character.toUpperCase(c), modifiers);
|
||||
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.action.copy
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.command.CommandState
|
||||
import com.maddyhome.idea.vim.command.SelectionType
|
||||
import com.maddyhome.idea.vim.common.Register
|
||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
|
||||
class PutTestAfterCursorActionTest : VimTestCase() {
|
||||
fun `test put from number register`() {
|
||||
VimPlugin.getRegister().saveRegister('4', Register('4', SelectionType.CHARACTER_WISE, "XXX ", ArrayList()))
|
||||
doTest(parseKeys("\"4p"), "This is my${c} text", "This is my XXX${c} text", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.action.copy
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
||||
import junit.framework.Assert
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
|
||||
class YankLineActionTest : VimTestCase() {
|
||||
fun `test yank to number register`() {
|
||||
val before = """
|
||||
${c}I found it in a legendary land
|
||||
all rocks and lavender and tufted grass,
|
||||
""".trimIndent()
|
||||
configureByText(before)
|
||||
typeText(parseKeys("\"4yy"))
|
||||
val register = VimPlugin.getRegister().getRegister('4')!!
|
||||
Assert.assertEquals("I found it in a legendary land\n", register.text)
|
||||
}
|
||||
}
|
@@ -1,379 +0,0 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.ex.handler;
|
||||
|
||||
import com.maddyhome.idea.vim.command.CommandState;
|
||||
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser;
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||
|
||||
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
||||
import static com.maddyhome.idea.vim.helper.StringHelper.stringToKeys;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
public class MapCommandTest extends VimTestCase {
|
||||
public void testMapKtoJ() {
|
||||
configureByText("<caret>foo\n" +
|
||||
"bar\n");
|
||||
typeText(commandToKeys("nmap k j"));
|
||||
assertPluginError(false);
|
||||
assertOffset(0);
|
||||
typeText(parseKeys("k"));
|
||||
assertOffset(4);
|
||||
}
|
||||
|
||||
public void testInsertMapJKtoEsc() {
|
||||
configureByText("<caret>World!\n");
|
||||
typeText(commandToKeys("imap jk <Esc>"));
|
||||
assertPluginError(false);
|
||||
typeText(parseKeys("i", "Hello, ", "jk"));
|
||||
myFixture.checkResult("Hello, World!\n");
|
||||
assertMode(CommandState.Mode.COMMAND);
|
||||
assertOffset(6);
|
||||
}
|
||||
|
||||
public void testBackslashEscape() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("imap \\\\,\\<,\\n foo"));
|
||||
assertPluginError(false);
|
||||
typeText(stringToKeys("i\\,<,\\n"));
|
||||
myFixture.checkResult("foo\n");
|
||||
}
|
||||
|
||||
public void testBackslashAtEnd() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("imap foo\\ bar"));
|
||||
assertPluginError(false);
|
||||
typeText(stringToKeys("ifoo\\"));
|
||||
myFixture.checkResult("bar\n");
|
||||
}
|
||||
|
||||
public void testUnfinishedSpecialKey() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("imap <Esc foo"));
|
||||
typeText(stringToKeys("i<Esc"));
|
||||
myFixture.checkResult("foo\n");
|
||||
}
|
||||
|
||||
public void testUnknownSpecialKey() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("imap <foo> bar"));
|
||||
typeText(stringToKeys("i<foo>"));
|
||||
myFixture.checkResult("bar\n");
|
||||
}
|
||||
|
||||
public void testMapTable() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("map <C-Down> gt"));
|
||||
typeText(commandToKeys("imap foo bar"));
|
||||
typeText(commandToKeys("imap bar <Esc>"));
|
||||
typeText(commandToKeys("imap <C-Down> <C-O>gt"));
|
||||
typeText(commandToKeys("nmap ,f <Plug>Foo"));
|
||||
typeText(commandToKeys("nmap <Plug>Foo iHello<Esc>"));
|
||||
|
||||
typeText(commandToKeys("imap"));
|
||||
assertExOutput("i <C-Down> <C-O>gt\n" +
|
||||
"i bar <Esc>\n" +
|
||||
"i foo bar\n");
|
||||
|
||||
typeText(commandToKeys("map"));
|
||||
assertExOutput(" <C-Down> gt\n" +
|
||||
"n <Plug>Foo iHello<Esc>\n" +
|
||||
"n ,f <Plug>Foo\n");
|
||||
}
|
||||
|
||||
public void testRecursiveMapping() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("imap foo bar"));
|
||||
typeText(commandToKeys("imap bar baz"));
|
||||
typeText(commandToKeys("imap baz quux"));
|
||||
typeText(parseKeys("i", "foo"));
|
||||
myFixture.checkResult("quux\n");
|
||||
}
|
||||
|
||||
public void testNonRecursiveMapping() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("inoremap a b"));
|
||||
assertPluginError(false);
|
||||
typeText(commandToKeys("inoremap b a"));
|
||||
typeText(parseKeys("i", "ab"));
|
||||
myFixture.checkResult("ba\n");
|
||||
}
|
||||
|
||||
public void testNonRecursiveMapTable() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("inoremap jj <Esc>"));
|
||||
typeText(commandToKeys("imap foo bar"));
|
||||
typeText(commandToKeys("imap"));
|
||||
assertExOutput("i foo bar\n" +
|
||||
"i jj * <Esc>\n");
|
||||
}
|
||||
|
||||
public void testNop() {
|
||||
configureByText("<caret>foo\n" +
|
||||
"bar\n");
|
||||
typeText(commandToKeys("noremap <Right> <nop>"));
|
||||
assertPluginError(false);
|
||||
typeText(parseKeys("l", "<Right>"));
|
||||
assertPluginError(false);
|
||||
myFixture.checkResult("foo\n" +
|
||||
"bar\n");
|
||||
assertOffset(1);
|
||||
typeText(commandToKeys("nmap"));
|
||||
assertExOutput("n <Right> * <Nop>\n");
|
||||
}
|
||||
|
||||
public void testIgnoreModifiers() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("nmap <buffer> ,a /a<CR>"));
|
||||
typeText(commandToKeys("nmap <nowait> ,b /b<CR>"));
|
||||
typeText(commandToKeys("nmap <silent> ,c /c<CR>"));
|
||||
typeText(commandToKeys("nmap <special> ,d /d<CR>"));
|
||||
typeText(commandToKeys("nmap <script> ,e /e<CR>"));
|
||||
typeText(commandToKeys("nmap <expr> ,f /f<CR>"));
|
||||
typeText(commandToKeys("nmap <unique> ,g /g<CR>"));
|
||||
typeText(commandToKeys("nmap"));
|
||||
assertExOutput("n ,a /a<CR>\n" +
|
||||
"n ,b /b<CR>\n" +
|
||||
"n ,c /c<CR>\n" +
|
||||
"n ,d /d<CR>\n" +
|
||||
"n ,g /g<CR>\n");
|
||||
}
|
||||
|
||||
// VIM-645 |:nmap|
|
||||
public void testMapSpace() {
|
||||
configureByText("foo\n");
|
||||
typeText(commandToKeys("nmap <space> dw"));
|
||||
typeText(parseKeys(" "));
|
||||
myFixture.checkResult("\n");
|
||||
typeText(parseKeys("i", " ", "<Esc>"));
|
||||
myFixture.checkResult(" \n");
|
||||
}
|
||||
|
||||
// VIM-661 |:noremap| |r|
|
||||
public void testNoMappingInReplaceCharacterArgument() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("noremap A Z"));
|
||||
typeText(parseKeys("rA"));
|
||||
myFixture.checkResult("Aoo\n");
|
||||
}
|
||||
|
||||
// VIM-661 |:omap| |d| |t|
|
||||
public void testNoMappingInNonFirstCharOfOperatorPendingMode() {
|
||||
configureByText("<caret>foo, bar\n");
|
||||
typeText(commandToKeys("omap , ?"));
|
||||
typeText(parseKeys("dt,"));
|
||||
myFixture.checkResult(", bar\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testIgnoreEverythingAfterBar() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b |c \" Something else"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b foo\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testBarEscaped() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b \\| c"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b | cfoo\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testBarEscapedSeveralSpaces() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b \\| c |"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b | c foo\n");
|
||||
}
|
||||
|
||||
// VIM-670 |:map|
|
||||
public void testFirstCharIsNonRecursive() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("map ab abcd"));
|
||||
typeText(parseKeys("ab"));
|
||||
myFixture.checkResult("bcd\n");
|
||||
}
|
||||
|
||||
// VIM-676 |:map|
|
||||
public void testBackspaceCharacterInVimRc() {
|
||||
configureByText("\n");
|
||||
VimScriptParser.executeText("inoremap # X\u0008#\n");
|
||||
typeText(parseKeys("i", "#", "<Esc>"));
|
||||
myFixture.checkResult("#\n");
|
||||
assertMode(CommandState.Mode.COMMAND);
|
||||
typeText(commandToKeys("imap"));
|
||||
assertExOutput("i # * X<C-H>#\n");
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
public void testCancelCharacterInVimRc() {
|
||||
configureByText("<caret>foo\n" +
|
||||
"bar\n");
|
||||
VimScriptParser.executeText("map \u0018i dd\n");
|
||||
typeText(parseKeys("i", "#", "<Esc>"));
|
||||
myFixture.checkResult("#foo\n" +
|
||||
"bar\n");
|
||||
assertMode(CommandState.Mode.COMMAND);
|
||||
typeText(commandToKeys("map"));
|
||||
assertExOutput(" <C-X>i dd\n");
|
||||
typeText(parseKeys("<C-X>i"));
|
||||
myFixture.checkResult("bar\n");
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
public void testBarCtrlVEscaped() {
|
||||
configureByText("<caret>foo\n");
|
||||
VimScriptParser.executeText("imap a b \u0016|\u0016| c |\n");
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b || c foo\n");
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
public void testCtrlMCtrlLAsNewLine() {
|
||||
configureByText("<caret>foo\n");
|
||||
VimScriptParser.executeText("map A :%s/foo/bar/g\r\u000C\n");
|
||||
typeText(parseKeys("A"));
|
||||
myFixture.checkResult("bar\n");
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
public void testRemappingZero() {
|
||||
configureByText("x<caret>yz\n");
|
||||
VimScriptParser.executeText("map 0 ~");
|
||||
typeText(parseKeys("0"));
|
||||
myFixture.checkResult("xYz\n");
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
public void testRemappingZeroStillAllowsZeroToBeUsedInCount() {
|
||||
configureByText("a<caret>bcdefghijklmnop\n");
|
||||
VimScriptParser.executeText("map 0 ^");
|
||||
typeText(parseKeys("10~"));
|
||||
myFixture.checkResult("aBCDEFGHIJKlmnop\n");
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
public void testRemappingDeleteOverridesRemovingLastDigitFromCount() {
|
||||
configureByText("a<caret>bcdefghijklmnop\n");
|
||||
VimScriptParser.executeText("map <Del> ~");
|
||||
typeText(parseKeys("10<Del>"));
|
||||
myFixture.checkResult("aBCDEFGHIJKlmnop\n");
|
||||
}
|
||||
|
||||
// VIM-650 |mapleader|
|
||||
public void testMapLeader() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("let mapleader = \",\""));
|
||||
typeText(commandToKeys("nmap <Leader>z izzz<Esc>"));
|
||||
typeText(parseKeys(",z"));
|
||||
myFixture.checkResult("zzz\n");
|
||||
}
|
||||
|
||||
public void testAmbiguousMapping() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("nmap ,f iHello<Esc>"));
|
||||
typeText(commandToKeys("nmap ,fc iBye<Esc>"));
|
||||
typeText(parseKeys(",fdh"));
|
||||
myFixture.checkResult("Helo\n");
|
||||
|
||||
typeText(parseKeys("diw"));
|
||||
myFixture.checkResult("\n");
|
||||
|
||||
typeText(parseKeys(",fch"));
|
||||
myFixture.checkResult("Bye\n");
|
||||
}
|
||||
|
||||
public void testLongAmbiguousMapping() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("nmap ,foo iHello<Esc>"));
|
||||
typeText(commandToKeys("nmap ,fooc iBye<Esc>"));
|
||||
typeText(parseKeys(",foodh"));
|
||||
myFixture.checkResult("Helo\n");
|
||||
|
||||
typeText(parseKeys("diw"));
|
||||
myFixture.checkResult("\n");
|
||||
|
||||
typeText(parseKeys(",fooch"));
|
||||
myFixture.checkResult("Bye\n");
|
||||
}
|
||||
|
||||
public void testPlugMapping() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("nmap ,f <Plug>Foo"));
|
||||
typeText(commandToKeys("nmap <Plug>Foo iHello<Esc>"));
|
||||
typeText(parseKeys(",fa!<Esc>"));
|
||||
myFixture.checkResult("Hello!\n");
|
||||
}
|
||||
|
||||
public void testIntersectingCommands() {
|
||||
configureByText("123<caret>4567890");
|
||||
typeText(commandToKeys("map ds h"));
|
||||
typeText(commandToKeys("map I 3l"));
|
||||
typeText(parseKeys("dI"));
|
||||
myFixture.checkResult("123<caret>7890");
|
||||
}
|
||||
|
||||
public void testIncompleteMapping() {
|
||||
configureByText("123<caret>4567890");
|
||||
typeText(commandToKeys("map <Plug>(Hi)l lll"));
|
||||
typeText(commandToKeys("map I <Plug>(Hi)"));
|
||||
typeText(parseKeys("Ih"));
|
||||
myFixture.checkResult("12<caret>34567890");
|
||||
}
|
||||
|
||||
public void testIntersectingCommands2() {
|
||||
configureByText("123<caret>4567890");
|
||||
typeText(commandToKeys("map as x"));
|
||||
typeText(parseKeys("gas"));
|
||||
myFixture.checkResult("123<caret>567890");
|
||||
}
|
||||
|
||||
public void testMapZero() {
|
||||
configureByText("A quick <caret>brown fox jumps over the lazy dog");
|
||||
typeText(commandToKeys("nmap 0 w"));
|
||||
typeText(parseKeys("0"));
|
||||
assertOffset(14);
|
||||
}
|
||||
|
||||
public void testMapZeroIgnoredInCount() {
|
||||
configureByText("A quick <caret>brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog");
|
||||
typeText(commandToKeys("nmap 0 w"));
|
||||
typeText(parseKeys("10w"));
|
||||
assertOffset(51);
|
||||
}
|
||||
|
||||
public void testMapNonZeroDigit() {
|
||||
configureByText("A quick <caret>brown fox jumps over the lazy dog");
|
||||
typeText(commandToKeys("nmap 2 w"));
|
||||
typeText(parseKeys("2"));
|
||||
assertOffset(14);
|
||||
}
|
||||
|
||||
public void testMapNonZeroDigitNotIncludedInCount() {
|
||||
configureByText("A quick <caret>brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog");
|
||||
typeText(commandToKeys("nmap 2 w"));
|
||||
typeText(parseKeys("92"));
|
||||
assertOffset(45);
|
||||
}
|
||||
}
|
426
test/org/jetbrains/plugins/ideavim/ex/handler/MapCommandTest.kt
Normal file
426
test/org/jetbrains/plugins/ideavim/ex/handler/MapCommandTest.kt
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jetbrains.plugins.ideavim.ex.handler
|
||||
|
||||
import com.maddyhome.idea.vim.command.CommandState
|
||||
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser
|
||||
import com.maddyhome.idea.vim.helper.StringHelper
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
class MapCommandTest : VimTestCase() {
|
||||
fun testMapKtoJ() {
|
||||
configureByText("""
|
||||
${c}foo
|
||||
bar
|
||||
|
||||
""".trimIndent())
|
||||
typeText(commandToKeys("nmap k j"))
|
||||
assertPluginError(false)
|
||||
assertOffset(0)
|
||||
typeText(StringHelper.parseKeys("k"))
|
||||
assertOffset(4)
|
||||
}
|
||||
|
||||
fun testInsertMapJKtoEsc() {
|
||||
configureByText("${c}World!\n")
|
||||
typeText(commandToKeys("imap jk <Esc>"))
|
||||
assertPluginError(false)
|
||||
typeText(StringHelper.parseKeys("i", "Hello, ", "jk"))
|
||||
myFixture.checkResult("Hello, World!\n")
|
||||
assertMode(CommandState.Mode.COMMAND)
|
||||
assertOffset(6)
|
||||
}
|
||||
|
||||
fun testBackslashEscape() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("imap \\\\,\\<,\\n foo"))
|
||||
assertPluginError(false)
|
||||
typeText(StringHelper.stringToKeys("i\\,<,\\n"))
|
||||
myFixture.checkResult("foo\n")
|
||||
}
|
||||
|
||||
fun testBackslashAtEnd() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("imap foo\\ bar"))
|
||||
assertPluginError(false)
|
||||
typeText(StringHelper.stringToKeys("ifoo\\"))
|
||||
myFixture.checkResult("bar\n")
|
||||
}
|
||||
|
||||
fun testUnfinishedSpecialKey() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("imap <Esc foo"))
|
||||
typeText(StringHelper.stringToKeys("i<Esc"))
|
||||
myFixture.checkResult("foo\n")
|
||||
}
|
||||
|
||||
fun testUnknownSpecialKey() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("imap <foo> bar"))
|
||||
typeText(StringHelper.stringToKeys("i<foo>"))
|
||||
myFixture.checkResult("bar\n")
|
||||
}
|
||||
|
||||
fun testMapTable() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("map <C-Down> gt"))
|
||||
typeText(commandToKeys("imap foo bar"))
|
||||
typeText(commandToKeys("imap bar <Esc>"))
|
||||
typeText(commandToKeys("imap <C-Down> <C-O>gt"))
|
||||
typeText(commandToKeys("nmap ,f <Plug>Foo"))
|
||||
typeText(commandToKeys("nmap <Plug>Foo iHello<Esc>"))
|
||||
typeText(commandToKeys("imap"))
|
||||
assertExOutput("""
|
||||
i <C-Down> <C-O>gt
|
||||
i bar <Esc>
|
||||
i foo bar
|
||||
|
||||
""".trimIndent())
|
||||
typeText(commandToKeys("map"))
|
||||
assertExOutput(""" <C-Down> gt
|
||||
n <Plug>Foo iHello<Esc>
|
||||
n ,f <Plug>Foo
|
||||
""")
|
||||
}
|
||||
|
||||
fun testRecursiveMapping() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("imap foo bar"))
|
||||
typeText(commandToKeys("imap bar baz"))
|
||||
typeText(commandToKeys("imap baz quux"))
|
||||
typeText(StringHelper.parseKeys("i", "foo"))
|
||||
myFixture.checkResult("quux\n")
|
||||
}
|
||||
|
||||
fun testNonRecursiveMapping() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("inoremap a b"))
|
||||
assertPluginError(false)
|
||||
typeText(commandToKeys("inoremap b a"))
|
||||
typeText(StringHelper.parseKeys("i", "ab"))
|
||||
myFixture.checkResult("ba\n")
|
||||
}
|
||||
|
||||
fun testNonRecursiveMapTable() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("inoremap jj <Esc>"))
|
||||
typeText(commandToKeys("imap foo bar"))
|
||||
typeText(commandToKeys("imap"))
|
||||
assertExOutput("""
|
||||
i foo bar
|
||||
i jj * <Esc>
|
||||
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun testNop() {
|
||||
configureByText("""
|
||||
${c}foo
|
||||
bar
|
||||
|
||||
""".trimIndent())
|
||||
typeText(commandToKeys("noremap <Right> <nop>"))
|
||||
assertPluginError(false)
|
||||
typeText(StringHelper.parseKeys("l", "<Right>"))
|
||||
assertPluginError(false)
|
||||
myFixture.checkResult("""
|
||||
foo
|
||||
bar
|
||||
|
||||
""".trimIndent())
|
||||
assertOffset(1)
|
||||
typeText(commandToKeys("nmap"))
|
||||
assertExOutput("n <Right> * <Nop>\n")
|
||||
}
|
||||
|
||||
fun testIgnoreModifiers() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("nmap <buffer> ,a /a<CR>"))
|
||||
typeText(commandToKeys("nmap <nowait> ,b /b<CR>"))
|
||||
typeText(commandToKeys("nmap <silent> ,c /c<CR>"))
|
||||
typeText(commandToKeys("nmap <special> ,d /d<CR>"))
|
||||
typeText(commandToKeys("nmap <script> ,e /e<CR>"))
|
||||
typeText(commandToKeys("nmap <expr> ,f /f<CR>"))
|
||||
typeText(commandToKeys("nmap <unique> ,g /g<CR>"))
|
||||
typeText(commandToKeys("nmap"))
|
||||
assertExOutput("""
|
||||
n ,a /a<CR>
|
||||
n ,b /b<CR>
|
||||
n ,c /c<CR>
|
||||
n ,d /d<CR>
|
||||
n ,g /g<CR>
|
||||
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
// VIM-645 |:nmap|
|
||||
fun testMapSpace() {
|
||||
configureByText("foo\n")
|
||||
typeText(commandToKeys("nmap <space> dw"))
|
||||
typeText(StringHelper.parseKeys(" "))
|
||||
myFixture.checkResult("\n")
|
||||
typeText(StringHelper.parseKeys("i", " ", "<Esc>"))
|
||||
myFixture.checkResult(" \n")
|
||||
}
|
||||
|
||||
// VIM-661 |:noremap| |r|
|
||||
fun testNoMappingInReplaceCharacterArgument() {
|
||||
configureByText("${c}foo\n")
|
||||
typeText(commandToKeys("noremap A Z"))
|
||||
typeText(StringHelper.parseKeys("rA"))
|
||||
myFixture.checkResult("Aoo\n")
|
||||
}
|
||||
|
||||
// VIM-661 |:omap| |d| |t|
|
||||
fun testNoMappingInNonFirstCharOfOperatorPendingMode() {
|
||||
configureByText("${c}foo, bar\n")
|
||||
typeText(commandToKeys("omap , ?"))
|
||||
typeText(StringHelper.parseKeys("dt,"))
|
||||
myFixture.checkResult(", bar\n")
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
fun testIgnoreEverythingAfterBar() {
|
||||
configureByText("${c}foo\n")
|
||||
typeText(commandToKeys("imap a b |c \" Something else"))
|
||||
typeText(StringHelper.parseKeys("ia"))
|
||||
myFixture.checkResult("b foo\n")
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
fun testBarEscaped() {
|
||||
configureByText("${c}foo\n")
|
||||
typeText(commandToKeys("imap a b \\| c"))
|
||||
typeText(StringHelper.parseKeys("ia"))
|
||||
myFixture.checkResult("b | cfoo\n")
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
fun testBarEscapedSeveralSpaces() {
|
||||
configureByText("${c}foo\n")
|
||||
typeText(commandToKeys("imap a b \\| c |"))
|
||||
typeText(StringHelper.parseKeys("ia"))
|
||||
myFixture.checkResult("b | c foo\n")
|
||||
}
|
||||
|
||||
// VIM-670 |:map|
|
||||
fun testFirstCharIsNonRecursive() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("map ab abcd"))
|
||||
typeText(StringHelper.parseKeys("ab"))
|
||||
myFixture.checkResult("bcd\n")
|
||||
}
|
||||
|
||||
// VIM-676 |:map|
|
||||
fun testBackspaceCharacterInVimRc() {
|
||||
configureByText("\n")
|
||||
VimScriptParser.executeText("inoremap # X\u0008#\n")
|
||||
typeText(StringHelper.parseKeys("i", "#", "<Esc>"))
|
||||
myFixture.checkResult("#\n")
|
||||
assertMode(CommandState.Mode.COMMAND)
|
||||
typeText(commandToKeys("imap"))
|
||||
assertExOutput("i # * X<C-H>#\n")
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
fun testCancelCharacterInVimRc() {
|
||||
configureByText("""
|
||||
${c}foo
|
||||
bar
|
||||
|
||||
""".trimIndent())
|
||||
VimScriptParser.executeText("map \u0018i dd\n")
|
||||
typeText(StringHelper.parseKeys("i", "#", "<Esc>"))
|
||||
myFixture.checkResult("""
|
||||
#foo
|
||||
bar
|
||||
|
||||
""".trimIndent())
|
||||
assertMode(CommandState.Mode.COMMAND)
|
||||
typeText(commandToKeys("map"))
|
||||
assertExOutput(" <C-X>i dd\n")
|
||||
typeText(StringHelper.parseKeys("<C-X>i"))
|
||||
myFixture.checkResult("bar\n")
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
fun testBarCtrlVEscaped() {
|
||||
configureByText("${c}foo\n")
|
||||
VimScriptParser.executeText("imap a b \u0016|\u0016| c |\n")
|
||||
typeText(StringHelper.parseKeys("ia"))
|
||||
myFixture.checkResult("b || c foo\n")
|
||||
}
|
||||
|
||||
// VIM-679 |:map|
|
||||
fun testCtrlMCtrlLAsNewLine() {
|
||||
configureByText("${c}foo\n")
|
||||
VimScriptParser.executeText("map A :%s/foo/bar/g\r\u000C\n")
|
||||
typeText(StringHelper.parseKeys("A"))
|
||||
myFixture.checkResult("bar\n")
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
fun testRemappingZero() {
|
||||
configureByText("x${c}yz\n")
|
||||
VimScriptParser.executeText("map 0 ~")
|
||||
typeText(StringHelper.parseKeys("0"))
|
||||
myFixture.checkResult("xYz\n")
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
fun testRemappingZeroStillAllowsZeroToBeUsedInCount() {
|
||||
configureByText("a${c}bcdefghijklmnop\n")
|
||||
VimScriptParser.executeText("map 0 ^")
|
||||
typeText(StringHelper.parseKeys("10~"))
|
||||
myFixture.checkResult("aBCDEFGHIJKlmnop\n")
|
||||
}
|
||||
|
||||
// VIM-700 |:map|
|
||||
fun testRemappingDeleteOverridesRemovingLastDigitFromCount() {
|
||||
configureByText("a${c}bcdefghijklmnop\n")
|
||||
VimScriptParser.executeText("map <Del> ~")
|
||||
typeText(StringHelper.parseKeys("10<Del>"))
|
||||
myFixture.checkResult("aBCDEFGHIJKlmnop\n")
|
||||
}
|
||||
|
||||
// VIM-650 |mapleader|
|
||||
fun testMapLeader() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let mapleader = \",\""))
|
||||
typeText(commandToKeys("nmap <Leader>z izzz<Esc>"))
|
||||
typeText(StringHelper.parseKeys(",z"))
|
||||
myFixture.checkResult("zzz\n")
|
||||
}
|
||||
|
||||
fun testAmbiguousMapping() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("nmap ,f iHello<Esc>"))
|
||||
typeText(commandToKeys("nmap ,fc iBye<Esc>"))
|
||||
typeText(StringHelper.parseKeys(",fdh"))
|
||||
myFixture.checkResult("Helo\n")
|
||||
typeText(StringHelper.parseKeys("diw"))
|
||||
myFixture.checkResult("\n")
|
||||
typeText(StringHelper.parseKeys(",fch"))
|
||||
myFixture.checkResult("Bye\n")
|
||||
}
|
||||
|
||||
fun testLongAmbiguousMapping() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("nmap ,foo iHello<Esc>"))
|
||||
typeText(commandToKeys("nmap ,fooc iBye<Esc>"))
|
||||
typeText(StringHelper.parseKeys(",foodh"))
|
||||
myFixture.checkResult("Helo\n")
|
||||
typeText(StringHelper.parseKeys("diw"))
|
||||
myFixture.checkResult("\n")
|
||||
typeText(StringHelper.parseKeys(",fooch"))
|
||||
myFixture.checkResult("Bye\n")
|
||||
}
|
||||
|
||||
fun testPlugMapping() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("nmap ,f <Plug>Foo"))
|
||||
typeText(commandToKeys("nmap <Plug>Foo iHello<Esc>"))
|
||||
typeText(StringHelper.parseKeys(",fa!<Esc>"))
|
||||
myFixture.checkResult("Hello!\n")
|
||||
}
|
||||
|
||||
fun testIntersectingCommands() {
|
||||
configureByText("123${c}4567890")
|
||||
typeText(commandToKeys("map ds h"))
|
||||
typeText(commandToKeys("map I 3l"))
|
||||
typeText(StringHelper.parseKeys("dI"))
|
||||
myFixture.checkResult("123${c}7890")
|
||||
}
|
||||
|
||||
fun testIncompleteMapping() {
|
||||
configureByText("123${c}4567890")
|
||||
typeText(commandToKeys("map <Plug>(Hi)l lll"))
|
||||
typeText(commandToKeys("map I <Plug>(Hi)"))
|
||||
typeText(StringHelper.parseKeys("Ih"))
|
||||
myFixture.checkResult("12${c}34567890")
|
||||
}
|
||||
|
||||
fun testIntersectingCommands2() {
|
||||
configureByText("123${c}4567890")
|
||||
typeText(commandToKeys("map as x"))
|
||||
typeText(StringHelper.parseKeys("gas"))
|
||||
myFixture.checkResult("123${c}567890")
|
||||
}
|
||||
|
||||
fun testMapZero() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap 0 w"))
|
||||
typeText(StringHelper.parseKeys("0"))
|
||||
assertOffset(14)
|
||||
}
|
||||
|
||||
fun testMapZeroIgnoredInCount() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap 0 w"))
|
||||
typeText(StringHelper.parseKeys("10w"))
|
||||
assertOffset(51)
|
||||
}
|
||||
|
||||
fun testMapNonZeroDigit() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap 2 w"))
|
||||
typeText(StringHelper.parseKeys("2"))
|
||||
assertOffset(14)
|
||||
}
|
||||
|
||||
fun testMapNonZeroDigitNotIncludedInCount() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap 2 w"))
|
||||
typeText(StringHelper.parseKeys("92"))
|
||||
assertOffset(45)
|
||||
}
|
||||
|
||||
fun testShiftSpace() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap <S-Space> w"))
|
||||
typeText(StringHelper.parseKeys("<S-Space>"))
|
||||
myFixture.checkResult("A quick brown ${c}fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
}
|
||||
|
||||
fun testShiftLetter() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap <S-D> w"))
|
||||
typeText(StringHelper.parseKeys("<S-D>"))
|
||||
myFixture.checkResult("A quick brown ${c}fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
}
|
||||
|
||||
fun testUppercaseLetter() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap D w"))
|
||||
typeText(StringHelper.parseKeys("D"))
|
||||
myFixture.checkResult("A quick brown ${c}fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
}
|
||||
|
||||
fun `test shift letter doesn't break insert mode`() {
|
||||
configureByText("A quick ${c}brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
typeText(commandToKeys("nmap <S-D> w"))
|
||||
typeText(StringHelper.parseKeys("<S-D>"))
|
||||
myFixture.checkResult("A quick brown ${c}fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
|
||||
typeText(StringHelper.parseKeys("iD<Esc>"))
|
||||
myFixture.checkResult("A quick brown ${c}Dfox jumps over the lazy dog. A quick brown fox jumps over the lazy dog")
|
||||
}
|
||||
}
|
@@ -37,6 +37,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
||||
|
||||
fun `test replace with empty register`() {
|
||||
val text = "one ${c}two three"
|
||||
VimPlugin.getRegister().resetRegisters()
|
||||
|
||||
configureByText(text)
|
||||
typeText(parseKeys("griw"))
|
||||
|
@@ -24,7 +24,6 @@ import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -32,7 +31,7 @@ import java.util.List;
|
||||
*/
|
||||
public class StringHelperTest extends VimTestCase {
|
||||
public void testParseKeyModifiers() {
|
||||
assertTypedKeyStroke('C', "<S-C>");
|
||||
assertTypedKeyStroke('C', "C");
|
||||
assertTypedKeyStroke('c', "c");
|
||||
|
||||
assertPressedKeyStroke("control C", "<C-C>");
|
||||
@@ -113,13 +112,8 @@ public class StringHelperTest extends VimTestCase {
|
||||
}
|
||||
|
||||
private void assertTypedKeyStroke(char expected, @NotNull String actual) {
|
||||
if (Character.isUpperCase(expected)) {
|
||||
assertEquals(KeyStroke.getKeyStroke(expected, KeyEvent.SHIFT_DOWN_MASK), parseKeyStroke(actual));
|
||||
}
|
||||
else {
|
||||
assertEquals(KeyStroke.getKeyStroke(expected), parseKeyStroke(actual));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KeyStroke parseKeyStroke(@NotNull String s) {
|
||||
|
Reference in New Issue
Block a user