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

Compare commits

..

90 Commits

Author SHA1 Message Date
Alex Plate
0c7c11f817 Ignore ui test 2020-12-01 10:02:53 +03:00
Alex Plate
b3a39c05d7 Update plugin.xml 2020-12-01 09:56:05 +03:00
Alex Plate
7370012667 Add getUnreleasedChangelog task to build.gradle 2020-12-01 09:52:56 +03:00
Alex Plate
412838fd4b Remove implemented manual tests 2020-11-27 12:05:00 +03:00
Alex Plate
273a614389 Add gutter ui test 2020-11-27 12:03:28 +03:00
Alex Plate
3944c80ae2 Update gradle intellij plugin 2020-11-27 10:54:22 +03:00
Alex Plate
726ab3f91b Add test with mouse dragging 2020-11-26 12:12:54 +03:00
Alex Plate
ab307dd78f Injecting text instead of typing it 2020-11-26 11:53:07 +03:00
Alex Plate
e3079912ae Remove unused handlers 2020-11-26 10:24:22 +03:00
Alex Plate
52da3ed0e4 Update info file 2020-11-26 09:44:48 +03:00
Alex Plate
cda85169ea Add new line for ExEditorKit.kt 2020-11-25 17:22:26 +03:00
Alex Plate
978d1df598 Disable internationalization inspections 2020-11-25 17:13:25 +03:00
Alex Plate
f90d22cc20 Refactoring of ex actions 2020-11-25 10:49:50 +03:00
Alex Plate
bae69d92ae Rename .java to .kt 2020-11-25 10:49:50 +03:00
Alex Plate
b910239825 Put ex panels into the separate package 2020-11-25 10:49:50 +03:00
Alex Plate
6421a5969a Update changes 2020-11-25 10:05:43 +03:00
sumoooru2
5c9faba7f4 Implement cmap 2020-11-25 10:00:15 +03:00
Alex Plate
c1af738cc5 Add another ui test 2020-11-24 12:47:10 +03:00
Alex Plate
23a80a9260 [VIM-2170] Fix alternative range format for s command 2020-11-23 11:49:30 +03:00
Alex Plate
d9d92f7eee Add another ui test 2020-11-20 20:18:19 +03:00
Alex Plate
c8be6c203e Update intellij plugin version 2020-11-20 12:39:00 +03:00
Alex Plate
612c599d9b Update compatibility a bit 2020-11-20 11:38:22 +03:00
Alex Plate
1292c7d1ae Remove unused import 2020-11-20 11:17:40 +03:00
Alex Plate
69f07967b5 Fix compilation issus for <203 2020-11-20 11:00:29 +03:00
Alex Plate
aedd427c07 Optimize imports 2020-11-20 10:45:26 +03:00
Alex Plate
9b6c3dc511 Fix unresolved references 2020-11-20 10:17:52 +03:00
Alex Plate
b4fa7f4317 Replace @NlsSafe annotation from utils with our own 2020-11-20 09:58:43 +03:00
Alex Plate
f053d305d5 Remove neovim from implementation 2020-11-20 09:35:48 +03:00
Alex Plate
1d95b7ddf7 Move run configurations to the .idea 2020-11-19 16:43:27 +03:00
Alex Plate
01a6964d68 Use neovim for tests only 2020-11-19 11:59:41 +03:00
Alex Plate
d661f96a9b Reformat for MessageHelper.kt 2020-11-19 11:26:27 +03:00
Alex Plate
c79fae8ab3 [i18n] Mark some strings as @NonNls 2020-11-19 11:22:11 +03:00
Alex Plate
121f130893 Ignore toString localization 2020-11-19 05:55:35 +03:00
Alex Plate
da9a0a414a [i18n] Extract more starting for localization 2020-11-19 00:26:17 +03:00
Alex Plate
e0732e041b Start with UI tests in the project 2020-11-18 22:03:46 +03:00
Alex Plate
6fc5b3189a [i18n] More extracted strings 2020-11-18 18:49:55 +03:00
Alex Plate
2a0c9cb749 [i18n] Add another file template 2020-11-18 14:22:39 +03:00
Alex Plate
7ad131b448 [i18n] More extracted strings 2020-11-18 13:03:35 +03:00
Alex Plate
3e7186bd60 [i18n] Update @Nls annotations 2020-11-18 13:03:35 +03:00
Alex Plate
132f8cce53 [i18n] Extract more strings 2020-11-18 13:03:35 +03:00
Alex Plate
5c07f42afb Disable unstable api usage inspection 2020-11-18 12:33:51 +03:00
Alex Plate
1f7a2594c8 Convert some strings to properties 2020-11-18 11:26:03 +03:00
Alex Plate
ec64d19a36 Update JetBrains annotations 2020-11-18 11:25:39 +03:00
Alex Plate
5cb67470d5 Enable hardcoded string inspection 2020-11-18 11:25:39 +03:00
Alex Plate
c03f01a96a Update MessageHelper.kt 2020-11-18 03:09:57 +03:00
Alex Plate
26b67a43ae Fix formatting 2020-11-17 19:55:09 +03:00
Alex Plate
a93ca3a205 Support mapclear commands 2020-11-17 19:47:56 +03:00
Alex Plate
dcc647ba3c [VIM-1491] Support unmap 2020-11-17 19:38:22 +03:00
Alex Plate
fe44f59239 Refactor map handler 2020-11-17 19:36:41 +03:00
Alex Plate
80dba0babf Move MapHandler into the separate package 2020-11-17 19:36:17 +03:00
Yaohui Wang
34acf9a91e Add CJK characterType for delimiting caret movement
- Add unicode CJK Unified Ideographs type
- Stop caret movement for CJK chars (as VIM does). Similar to VIM-58
2020-11-17 10:21:49 +03:00
Alex Plate
cb859dbb7b Add Grzegorz Antoniak to the contributors list 2020-11-17 10:16:13 +03:00
Alex Plate
20c04b1e62 Add Brandon Conway to the contributors list 2020-11-17 10:09:21 +03:00
Alex Plate
69eaf8ed0c Jan Palus was already on the list 2020-11-17 10:09:21 +03:00
Grzegorz Antoniak
62c828d722 VIM-1475: Respect the "use block caret" when in insert mode
The "use block caret" IDEA option controls the style of the cursor: when
it's enabled, the cursor is drawn as a block, and when it's disabled,
it's drawn as a bar. However, after installing IdeaVIM, this option
isn't respected; the plugin always uses a block cursor when in command
mode, and always uses a bar cursor when in insert mode.

This commit changes the behavior so that when the "use block caret"
option is enabled, IdeaVIM's insert mode uses a block cursor instead of
a bar cursor. The cursor in normal mode is always drawn as a block
cursor. If the "use block caret" option is disabled, the behavior is the
same as in previous versions of IdeaVIM (block cursor in normal mode,
bar cursor in insert mode).

Fixes VIM-1475 (on YouTrack)
2020-11-17 10:06:32 +03:00
Brandon Conway
251e8e8ff4 Fix typo 2020-11-16 11:20:07 +03:00
Alex Plate
acc41ec72e Add warning to the info about ideavimrc file 2020-11-13 15:15:28 +03:00
Alex Plate
f9ebcf2ee4 Update readme section 2020-11-13 15:13:01 +03:00
Alex Plate
f3df231dc2 Update changes 2020-11-13 12:35:21 +03:00
Jan Palus
75a1bb7cc5 VIM-2114 Do not override registers when deleting empty range 2020-11-13 12:34:04 +03:00
Alex Plate
7d6a64315a Add Jan Palus to contributors list 2020-11-13 11:58:10 +03:00
Jan Palus
2758071d31 VIM-2113 Increase tag range only in visual mode 2020-11-13 11:54:08 +03:00
Alex Plate
3881b905be Update CHANGES.md 2020-11-12 10:51:57 +03:00
Alex Plate
073c62f868 Update version on TeamCity 2020-11-12 10:50:25 +03:00
Alex Plate
d8e0f26bea Revert "Unmute falling tests"
This reverts commit 0296cae7
2020-11-12 10:48:54 +03:00
Alex Plate
04c24ab5d0 Run manual tests 2020-11-12 10:38:02 +03:00
Alex Plate
bfb0ba1ab9 Update emulated plugins 2020-11-12 10:31:11 +03:00
Alex Plate
fb7d48af1f Update IDE actions section in README 2020-11-12 10:11:33 +03:00
Alex Plate
559989ce4b Remove all To Be Released labels 2020-11-12 10:03:56 +03:00
Alex Plate
81f59e3c18 Update plugin.xml 2020-11-12 10:03:04 +03:00
Alex Plate
b6adf9f7a9 Rename ideaenabledbufs to ideavimsupport 2020-11-12 09:45:29 +03:00
Alex Plate
b972a01cf0 Add merged PR to changes 2020-11-12 09:41:57 +03:00
Alex Plate
0296cae712 Unmute falling tests 2020-11-12 09:39:09 +03:00
Matt Ellis
c38b18e16b Prevent inlays causing scrolling to stick 2020-11-12 09:37:55 +03:00
Matt Ellis
8d65c3ed26 Limit how much of an inlay is shown when scrolling 2020-11-12 09:37:55 +03:00
Matt Ellis
995bb966ad Reposition cursor when scrolloff changes 2020-11-12 09:37:55 +03:00
Matt Ellis
dbda1a76ca [VIM-2158] Fix scrolling when scrolloff is greater than half screen height, but less than full screen height 2020-11-12 09:37:55 +03:00
Alex Plate
ed6f990d9a Remove some qodana inspections 2020-11-06 21:39:37 +03:00
Alex Plate
4f86d9cc77 Correct visual mode exiting when after line end 2020-11-06 20:26:26 +03:00
Alex Plate
d55774abab Use vimForEachCaret 2020-11-06 20:21:05 +03:00
Alex Plate
d5591ba08d Update qodana profile 2020-11-06 20:00:21 +03:00
Alex Plate
f67d483c4e Exclude next method from property based testing 2020-11-06 19:48:33 +03:00
Alex Plate
f26ddd4a27 Fix exception in aW 2020-11-06 19:12:40 +03:00
Alex Plate
dbbea642bc Add inspection profiles to the repository 2020-11-06 18:40:02 +03:00
Alex Plate
0539e39977 Fix <C-\><C-N> 2020-11-06 11:16:13 +03:00
Alex Plate
65235d32a1 Fix exception for ]b command 2020-11-06 10:36:03 +03:00
Alex Plate
ecfcdf5a8c Update intellij gradle plugin 2020-11-06 10:06:25 +03:00
Alex Plate
cf127ba7f9 Update plugin description 2020-11-06 09:37:01 +03:00
Alex Plate
1fba77d925 Update getName description 2020-11-05 11:31:41 +03:00
Alex Plate
5752b116f6 Fix plugin.xml 2020-11-04 13:04:36 +03:00
164 changed files with 3247 additions and 1139 deletions

3
.gitignore vendored
View File

@@ -5,6 +5,9 @@
!/.idea/scopes
!/.idea/copyright
!/.idea/icon.png
!/.idea/inspectionProfiles
!/.idea/fileTemplates
!/.idea/runConfigurations
/build/
/out/

View File

@@ -0,0 +1 @@
com.maddyhome.idea.vim.helper.MessageHelper.message("${PROPERTY_KEY}", ${PARAMETERS})

View File

@@ -0,0 +1 @@
com.maddyhome.idea.vim.helper.MessageHelper.message("${PROPERTY_KEY}")

View File

@@ -0,0 +1,35 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HardCodedStringLiteral" enabled="false" level="WARNING" enabled_by_default="false">
<scope name="Production" level="WARNING" enabled="false">
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="true" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</scope>
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="false" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</inspection_tool>
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool>
<inspection_tool class="PluginXmlI18n" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

48
.idea/inspectionProfiles/Qodana.xml generated Normal file
View File

@@ -0,0 +1,48 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<description>Inspections profile for Qodana</description>
<option name="myName" value="Qodana" />
<inspection_tool class="CanBeFinal" enabled="false" level="WARNING" enabled_by_default="false">
<option name="REPORT_CLASSES" value="false" />
<option name="REPORT_METHODS" value="false" />
<option name="REPORT_FIELDS" value="true" />
</inspection_tool>
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="HardCodedStringLiteral" enabled="false" level="WARNING" enabled_by_default="false">
<scope name="Production" level="WARNING" enabled="false">
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="true" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</scope>
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="false" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</inspection_tool>
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool>
<inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@@ -10,7 +10,7 @@ object Release : BuildType({
description = "Build and publish IdeaVim plugin"
artifactRules = "build/distributions/*"
buildNumberPattern = "0.60"
buildNumberPattern = "0.61"
params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")

View File

@@ -13,7 +13,7 @@ object ReleaseEap : BuildType({
description = "Build and publish EAP of IdeaVim plugin"
artifactRules = "build/distributions/*"
buildNumberPattern = "0.60.%build.counter%"
buildNumberPattern = "0.61.%build.counter%"
params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")

View File

@@ -323,6 +323,14 @@ Contributors:
[![icon][github]](https://github.com/i-e-b)
&nbsp;
Iain Ballard
* [![icon][mail]](mailto:brandoncc@gmail.com)
[![icon][github]](https://github.com/brandoncc)
&nbsp;
Brandon Conway
* [![icon][mail]](mailto:ga@anadoxin.org)
[![icon][github]](https://github.com/antekone)
&nbsp;
Grzegorz Antoniak
If you are a contributor and your name is not listed here, feel free to
contact the maintainers.

View File

@@ -24,6 +24,26 @@ usual beta standards.
## To Be Released
### Features:
* Support `unmap` and `mapclear` commands [VIM-1491](https://youtrack.jetbrains.com/issue/VIM-1491)
* Support mappings in ex panel (`cmap`) [VIM-1227](https://youtrack.jetbrains.com/issue/VIM-1227)
### Fixes:
* [VIM-2113](https://youtrack.jetbrains.com/issue/VIM-2113) Fix `cit` for empty tags
* [VIM-2114](https://youtrack.jetbrains.com/issue/VIM-2114) Unnamed register isn't changed after deleting empty tag
* [VIM-1475](https://youtrack.jetbrains.com/issue/VIM-1475) Enable block caret to be used in insert mode.
* [VIM-2170](https://youtrack.jetbrains.com/issue/VIM-2170) Fix an alternative range format for `s` command
### Merged PRs:
* [249](https://github.com/JetBrains/ideavim/pull/249) by [Jan Palus](https://github.com/jpalus): VIM-2113 Increase tag range only in visual mode
* [250](https://github.com/JetBrains/ideavim/pull/250) by [Jan Palus](https://github.com/jpalus): VIM-2114 Do not override registers when deleting empty range
* [256](https://github.com/JetBrains/ideavim/pull/256) by [Brandon Conway](https://github.com/brandoncc): Fix typo
* [254](https://github.com/JetBrains/ideavim/pull/254) by [Grzegorz Antoniak](https://github.com/antekone): VIM-1475: Add an option to use block caret in insert mode
* [225](https://github.com/JetBrains/ideavim/pull/225) by [sumoooru2](https://github.com/sumoooru2): Implement cmap
## 0.61, 2020-11-12
### Features:
* Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`.
Check out `README.md` for the details.
@@ -44,14 +64,18 @@ usual beta standards.
### Changes:
* Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode.
* Add option to disable IdeaVim in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors.
_Note for EAP users: the option name can be changed for the stable release_
Use `set ideavimsupport=` to disable IdeaVim in dialog editors.
* Reposition cursor when `scrolloff` changes
### Fixes:
* [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line
* [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template
* [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays
* [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays
* [VIM-2158](https://youtrack.jetbrains.com/issue/VIM-2158) Fix scrolling when `scrolloff` is over half screen height, but less than full height
### Merged PRs:
* [255](https://github.com/JetBrains/ideavim/pull/255) by [Matt Ellis](https://github.com/citizenmatt): Fix various scrolling issues
## 0.60, 2020-10-09

View File

@@ -11,7 +11,7 @@ IdeaVim
[![Gitter][gitter-svg]][gitter]
[![Twitter][twitter-svg]][twitter]
IdeaVim is a Vim emulation plugin for IDEs based on the IntelliJ Platform.
IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
##### Contact maintainers:
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
@@ -165,7 +165,7 @@ You can read your `~/.vimrc` file from `~/.ideavimrc` with this command:
source ~/.vimrc
Please note that IdeaVim currently parses `~/.ideavimrc` & `~/.vimrc` files via simple pattern-matching.
> :warning: Please note that IdeaVim currently parses `~/.ideavimrc` & `~/.vimrc` files via simple pattern-matching.
See [VIM-669](https://youtrack.jetbrains.com/issue/VIM-669) for proper parsing
of VimL files.
@@ -183,67 +183,43 @@ Emulated Vim Plugins
See [doc/emulated-plugins.md](doc/emulated-plugins.md)
Changes to the IDE
------------------
Executing IDE Actions
---------------------
### Executing IDE Actions
IdeaVim adds two commands for listing and executing arbitrary IDE actions as
IdeaVim adds various commands for listing and executing arbitrary IDE actions as
Ex commands or via `:map` command mappings:
**Executing actions:**
* `:action {action_id}`
* Execute an action by id. Works from Ex command line.
* `<Action>(*action_id*)`
* For the mappings you can use a special `<Action>` keyword. Don't forget the parentheses.
**Finding actions:**
* `:actionlist [pattern]`
* Find IDE actions by name or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
* `:action {name}`
* Execute an action named `NAME`
* Find IDE actions by id or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`). **[To Be Released]**
* In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`).
<details>
<summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary>
<img src="resources/readme/track_action_id.gif" alt="track actioin ids"/>
</details>
For the mappings you can use a special `<Action>` keyword. Use `<Action>(*action_id*)` to map keys to some action. Don't
forget the parentheses. This keyword works for insert mode as well. **[To Be Released]**
<details>
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
<img src="resources/readme/track_action_id.gif" alt="track action ids"/>
</details>
Examples:
```vim
" Map \r to the Reformat Code action
:map \r :action ReformatCode<CR>
" or
:map \r <Action>(ReformatCode) " [To Be Released]
:map \r <Action>(ReformatCode)
" Map <leader>d to start debug
:map <leader>d :action Debug<CR>
" or
:map <leader>d <Action>(Debug) " [To Be Released]
:map <leader>d <Action>(Debug)
" Map \b to toggle the breakpoint on the current line
:map \b :action ToggleLineBreakpoint<CR>
" or
:map \b <Action>(ToggleLineBreakpoint) " [To Be Released]
:map \b <Action>(ToggleLineBreakpoint)
```
### Undo/Redo
The IdeaVim plugin uses the undo/redo functionality of the IntelliJ Platform,
so the behavior of the `u` and `<C-R>` commands may differ from the original
Vim. Vim compatibility of undo/redo may be improved in future releases.
See also [unresolved undo issues](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+u).
### Escape
Using `<Esc>` in dialog windows remains problematic. For most dialog windows,
the Vim emulator is put into insert mode with `<Esc>` not working. You
should use `<C-c>` or `<C-[>` instead. In some dialog windows, the normal mode is
switched by default. The usage of the Vim emulator in dialog windows is an area for
improvement.
See also [unresolved escape issues](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+i_Esc).
:gem: Contributing
------------

View File

@@ -13,7 +13,7 @@ buildscript {
}
plugins {
id 'org.jetbrains.intellij' version '0.6.1'
id 'org.jetbrains.intellij' version '0.6.5'
id 'io.gitlab.arturbosch.detekt' version '1.14.1'
id "org.jetbrains.changelog" version "0.6.2"
}
@@ -45,6 +45,8 @@ intellij {
intellijRepo = "https://www.jetbrains.com/intellij-repository"
plugins = ['java']
downloadRobotServerPlugin.version = "0.10.0"
publishPlugin {
channels publishChannels.split(',')
username publishUsername
@@ -52,6 +54,10 @@ intellij {
}
}
runIdeForUiTests {
systemProperty "robot-server.port", "8082"
}
runPluginVerifier {
ideVersions = ["IC-2020.1.4", "IC-2020.2.3"]
downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
@@ -61,14 +67,18 @@ runPluginVerifier {
repositories {
mavenCentral()
jcenter()
maven { url = "https://jetbrains.bintray.com/intellij-third-party-dependencies" }
}
dependencies {
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
compileOnly "org.jetbrains:annotations:19.0.0"
compileOnly "org.jetbrains:annotations:20.1.0"
// https://mvnrepository.com/artifact/com.ensarsarajcic.neovim.java/neovim-api
compile group: 'com.ensarsarajcic.neovim.java', name: 'neovim-api', version: '0.1.16'
testImplementation("com.ensarsarajcic.neovim.java:neovim-api:0.1.16")
testImplementation("com.intellij.remoterobot:remote-robot:0.10.0")
testImplementation("com.intellij.remoterobot:remote-fixtures:1.1.18")
}
compileKotlin {
@@ -113,6 +123,14 @@ changelog {
// version = "0.60"
}
task getUnreleasedChangelog() {
group = "changelog"
doLast {
def log = changelog.getUnreleased().toHTML()
println log
}
}
tasks.register("slackEapNotification") {
doLast {
if (!slackUrl) return

View File

@@ -4,7 +4,15 @@ 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>
```
set <extension-name>
```
If you reuse your existing `.vimrc` file using `source ~/.vimrc`, IdeaVim can parse and enable plugins that are defined
using [vim-plug](https://github.com/junegunn/vim-plug) or [vundle](https://github.com/VundleVim/Vundle.vim).
No additional set commands in `~/.ideavimrc` are required.
If you'd like to disable some plugin that's enabled in `.vimrc`, you can use `set no<extension-name>`
in `~/.ideavimrc`.
Available extensions:
@@ -20,18 +28,52 @@ Available extensions:
## surround
* Setup: `set surround`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tpope/vim-surround'</code>
<br/>
<code>Plug 'tpope/vim-surround'</code>
<br/>
<code>Plug 'vim-surround'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1697'</code>
</details>
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
* Commands: `ys`, `cs`, `ds`, `S`
## multiple-cursors
* Setup: `set multiple-cursors`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/terryma/vim-multiple-cursors'</code>
<br/>
<code>Plug 'terryma/vim-multiple-cursors'</code>
<br/>
<code>Plug 'vim-multiple-cursors'</code>
</details>
* 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`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tpope/vim-commentary'</code>
<br/>
<code>Plug 'tpope/vim-commentary'</code>
<br/>
<code>Plug 'vim-commentary'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=3695'</code>
<br/>
<code>Plug 'tomtom/tcomment_vim'</code>
<br/>
<code>Plug 'tcomment_vim'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1173'</code>
</details>
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
* Commands: `gcc`, `gc + motion`, `v_gc`
* By [Daniel Leong](https://github.com/dhleong)
@@ -39,6 +81,22 @@ Available extensions:
## ReplaceWithRegister
* Setup: `set ReplaceWithRegister`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/vim-scripts/ReplaceWithRegister'</code>
<br/>
<code>Plug 'vim-scripts/ReplaceWithRegister'</code>
<br/>
<code>Plug 'ReplaceWithRegister'</code>
<br/>
<code>Plug 'https://github.com/inkarkat/vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'inkarkat/vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2703'</code>
</details>
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
* Commands: `gr`, `grr`
* By [igrekster](https://github.com/igrekster)
@@ -47,6 +105,16 @@ Available extensions:
* Setup:
* `set argtextobj`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/vim-scripts/argtextobj.vim'</code>
<br/>
<code>Plug 'vim-scripts/argtextobj.vim'</code>
<br/>
<code>Plug 'argtextobj.vim'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2699'</code>
</details>
* 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
@@ -59,6 +127,14 @@ Available extensions:
## exchange
* Setup: `set exchange`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tommcdo/vim-exchange'</code>
<br/>
<code>Plug 'tommcdo/vim-exchange'</code>
<br/>
<code>Plug 'vim-exchange'</code>
</details>
* Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange)
* Commands: `cx`, `cxx`, `X`, `cxc`
* By [fan-tom](https://github.com/fan-tom)
@@ -66,6 +142,16 @@ Available extensions:
## textobj-entire
* Setup: `set textobj-entire`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/kana/vim-textobj-entire'</code>
<br/>
<code>Plug 'kana/vim-textobj-entire'</code>
<br/>
<code>Plug 'vim-textobj-entire'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2610'</code>
</details>
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
* Additional text objects: `ae`, `ie`
* By [Alexandre Grison](https://github.com/agrison)
@@ -74,6 +160,14 @@ Available extensions:
* Setup:
* `set highlightedyank`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/machakann/vim-highlightedyank'</code>
<br/>
<code>Plug 'machakann/vim-highlightedyank'</code>
<br/>
<code>Plug 'vim-highlightedyank'</code>
</details>
* if you want to optimize highlight duration, assign a time in milliseconds:
`let g:highlightedyank_highlight_duration = "1000"`
A negative number makes the highlight persistent.

View File

@@ -125,7 +125,7 @@ The following `:set` commands can appear in `~/.ideavimrc` or be set manually in
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
"<C-J>", "<C-Q>"
`ideaenabledbufs` `ideaenabledbufs` List of strings (default "dialog") [To Be Released]
`ideavimsupport` `ideavimsupport` List of strings (default "dialog")
Define the list of additional buffers where IdeaVim is enabled.

View File

@@ -25,7 +25,9 @@
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.JoinLinesHandler" names="j[oin]"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.JumpsHandler" names="ju[mps]"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.LetHandler" names="let"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.MapHandler"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.mapping.MapHandler"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.mapping.UnMapHandler"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.mapping.MapClearHandler"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.MarkHandler" names="ma[rk],k"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.MarksHandler" names="marks"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.MoveTextHandler" names="m[ove]"/>

View File

@@ -1,6 +1,6 @@
<idea-plugin>
<applicationListeners>
<listener class="com.maddyhome.idea.vim.ui.ExEntryPanel$LafListener"
<listener class="com.maddyhome.idea.vim.ui.ex.ExEntryPanel$LafListener"
topic="com.intellij.ide.ui.LafManagerListener"/>
<listener class="com.maddyhome.idea.vim.extension.highlightedyank.HighlightColorResetter"
topic="com.intellij.ide.ui.LafManagerListener"/>

View File

@@ -2,18 +2,70 @@
<name>IdeaVim</name>
<id>IdeaVIM</id>
<change-notes><![CDATA[
<ul>
<li>Fix ESC in dialogs</li>
<li>Add option to disable IdeaVim in dialogs and single line editors</li>
<li>Ability to map IDE actions via the &lt;Action&gt; keyword.</li>
<li>"IdeaVim: track action Ids" command to find action ids for the :action command.
<li>Add new option to register IdeaVim extensions. Please read the changelog for details</li>
</ul>
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
]]></change-notes>
<h3>Features:</h3>
<ul>
<li>Support <code>unmap</code> and <code>mapclear</code> commands
<a href="https://youtrack.jetbrains.com/issue/VIM-1491">VIM-1491</a>
</li>
<li>Support mappings in ex panel (<code>cmap</code>)
<a href="https://youtrack.jetbrains.com/issue/VIM-1227">VIM-1227</a>
</li>
</ul>
<h3>Fixes:</h3>
<ul>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2113">VIM-2113</a>
Fix <code>cit</code> for empty tags
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2114">VIM-2114</a>
Unnamed register isn't changed after deleting empty tag
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-1475">VIM-1475</a>
Enable block caret to be used in insert mode.
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2170">VIM-2170</a>
Fix an alternative range format for <code>s</code> command
</li>
</ul>
<h3>Merged PRs:</h3>
<ul>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/249">249</a>
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2113 Increase tag range only in visual mode
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/250">250</a>
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2114 Do not override registers when deleting empty range
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/256">256</a>
by <a href="https://github.com/brandoncc">Brandon Conway</a>: Fix typo
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/254">254</a>
by <a href="https://github.com/antekone">Grzegorz Antoniak</a>: VIM-1475: Add an option to use block caret in insert
mode
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/225">225</a>
by <a href="https://github.com/sumoooru2">sumoooru2</a>: Implement cmap
</li>
</ul>
<br/>
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
]]>
</change-notes>
<description><![CDATA[
<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>Vim emulation plugin for IntelliJ Platform-based IDEs.</p>
<br/>
<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, Vim plugins, etc.</p>
<br/>
<p>See also:</p>
<ul>
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li>
@@ -25,11 +77,11 @@
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
<!-- Check for [Version Update] tag in YouTrack as well -->
<idea-version since-build="201.5985.32"/>
<idea-version since-build="201.5985.41"/>
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform -->
<depends>com.intellij.modules.lang</depends>
<resource-bundle xmlns="">messages</resource-bundle>
<resource-bundle>messages.IdeaVimBundle</resource-bundle>
<application-components>
<component>
@@ -76,7 +128,7 @@
<xi:include href="/META-INF/includes/VimExtensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/includes/VimListeners.xml" xpointer="xpointer(/idea-plugin/*)"/>
<actions>
<actions resource-bundle="messages.IdeaVimBundle">
<action id="VimPluginToggle" class="com.maddyhome.idea.vim.action.VimPluginToggleAction">
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
@@ -102,8 +154,6 @@
</action>
</group>
<action id="VimFindActionIdAction"
class="com.maddyhome.idea.vim.listener.FindActionIdAction" text="IdeaVim: Track Action Ids"
description="Starts tracking ids of executed actions"/>
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
</actions>
</idea-plugin>

View File

@@ -72,8 +72,54 @@ E475=E475: Invalid argument: {0}
E774=E774: 'operatorfunc' is empty
action.VimPluginToggle.text=Vim Emulator
description.VimPluginToggle.description=Toggle the vim plugin On/off
action.VimPluginToggle.description=Toggle the vim plugin On/Off
action.VimPluginToggle.enabled=Enabled
action.VimPluginToggle.enable=Enable
action.VimShortcutKeyAction.text=Shortcuts
action.VimActions.text=Vim Actions
action.not.found.0=Action not found: {0}
action.VimFindActionIdAction.text=IdeaVim: Track Action Ids
action.VimFindActionIdAction.description=Starts tracking ids of executed actions
ex.show.all.actions.0.1=--- Actions ---{0}{1}
e471.argument.required=E471: Argument required
buffer.0.does.not.exist=Buffer {0} does not exist
no.matching.buffer.for.0=No matching buffer for {0}
no.write.since.last.change.add.to.override=No write since last change (add ! to override)
more.than.one.match.for.0=More than one match for {0}
e176.invalid.number.of.arguments=E176: Invalid number of arguments
e183.user.defined.commands.must.start.with.an.uppercase.letter=E183: User defined commands must start with an uppercase letter
e841.reserved.name.cannot.be.used.for.user.defined.command=E841: Reserved name, cannot be used for user defined command
e174.command.already.exists.add.to.replace.it=E174: Command already exists: add ! to replace it
recursion.detected.maximum.alias.depth.reached=Recursion detected, maximum alias depth reached.
show.mode.recording=recording
e184.no.such.user.defined.command.0=E184: No such user-defined command: {0}
unable.to.find.0=Unable to find {0}
more.ret.line.space.page.d.half.page.q.quit=-- MORE -- (RET: line, SPACE: page, d: half page, q: quit)
hit.enter.or.type.command.to.continue=Hit ENTER or type command to continue
ex.output.panel.more=-- MORE --
command.name.vim.macro.playback=Vim Macro Playback
action.no.changes.text=No Changes
action.reload.text=Reload
replace.with.0=Replace with {0} (y/n/a/q/l)?
error.invalid.command.argument=Error: invalid command argument
argtextobj.invalid.value.of.g.argtextobj.pairs.0=argtextobj: Invalid value of g:argtextobj_pairs -- {0}
highlightedyank.invalid.value.of.0.1=highlightedyank: Invalid value of {0} -- {1}
could.not.find.file.0=Could not find file: {0}
popup.advertisement.version=Version {0}
action.eap.choice.active.text=EAP{0, choice, 0# (Active)|1#}
action.about.eap.text=About EAP...
action.contacts.help.text=Contacts && Help
action.contact.on.twitter.text=Contact on Twitter
action.create.issue.text=Create an Issue
action.contribute.on.github.text=Contribute on GitHub
action.settings.text=Settings...
action.finish.eap.text=Finish EAP
action.subscribe.to.eap.text=Subscribe to EAP
configurable.name.vim.emulation=Vim Emulation
border.title.shortcut.conflicts.for.active.keymap=Shortcut Conflicts for Active Keymap
message.no.more.matches=No more matches

View File

@@ -26,10 +26,8 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.ActionPlan;
import com.intellij.openapi.editor.actionSystem.CaretSpecificDataContext;
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.project.Project;
@@ -40,17 +38,14 @@ import com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction;
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction;
import com.maddyhome.idea.vim.action.macro.ToggleRecordingAction;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.group.ChangeGroup;
import com.maddyhome.idea.vim.group.RegisterGroup;
import com.maddyhome.idea.vim.group.visual.VimSelection;
import com.maddyhome.idea.vim.group.visual.VisualGroupKt;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.key.*;
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor;
import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ShowCmd;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
@@ -59,13 +54,12 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.intellij.openapi.actionSystem.CommonDataKeys.*;
import static com.intellij.openapi.actionSystem.PlatformDataKeys.PROJECT_FILE_DIRECTORY;
@@ -325,7 +319,7 @@ public class KeyHandler {
}
}
reset(editor);
ChangeGroup.resetCaret(editor, false);
ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor());
}
private boolean handleKeyMapping(final @NotNull Editor editor,
@@ -599,6 +593,22 @@ public class KeyHandler {
}
DigraphResult res = editorState.processDigraphKey(key, editor);
if (ExEntryPanel.getInstance().isActive()) {
switch (res.getResult()) {
case DigraphResult.RES_HANDLED:
setPromptCharacterEx(commandBuilder.isPuttingLiteral() ? '^' : key.getKeyChar());
break;
case DigraphResult.RES_DONE:
case DigraphResult.RES_BAD:
if (key.getKeyCode() == KeyEvent.VK_C && (key.getModifiers() & InputEvent.CTRL_DOWN_MASK) != 0) {
return false;
} else {
ExEntryPanel.getInstance().getEntry().clearCurrentAction();
}
break;
}
}
switch (res.getResult()) {
case DigraphResult.RES_HANDLED:
editorState.getCommandBuilder().addKey(key);
@@ -753,8 +763,10 @@ public class KeyHandler {
// the key handler when it's complete.
if (action instanceof InsertCompletedDigraphAction) {
editorState.startDigraphSequence();
setPromptCharacterEx('?');
} else if (action instanceof InsertCompletedLiteralAction) {
editorState.startLiteralSequence();
setPromptCharacterEx('^');
}
break;
case EX_STRING:
@@ -777,7 +789,7 @@ public class KeyHandler {
* @param name The name of the action to execute
* @param context The context to run it in
*/
public static boolean executeAction(@NotNull String name, @NotNull DataContext context) {
public static boolean executeAction(@NotNull @NonNls String name, @NotNull DataContext context) {
ActionManager aMgr = ActionManager.getInstance();
AnAction action = aMgr.getAction(name);
return action != null && executeAction(action, context);
@@ -849,6 +861,13 @@ public class KeyHandler {
}
private void setPromptCharacterEx(final char promptCharacter) {
final ExEntryPanel exEntryPanel = ExEntryPanel.getInstance();
if (exEntryPanel.isActive()) {
exEntryPanel.getEntry().setCurrentActionPromptCharacter(promptCharacter);
}
}
// This class is copied from com.intellij.openapi.editor.actionSystem.DialogAwareDataContext.DialogAwareDataContext
private static final class DialogAwareDataContext implements DataContext {
@SuppressWarnings("rawtypes")
@@ -917,7 +936,9 @@ public class KeyHandler {
editorState.popModes();
}
KeyHandler.getInstance().reset(editor);
if (editorState.getCommandBuilder().isDone()) {
KeyHandler.getInstance().reset(editor);
}
}
private final Editor editor;

View File

@@ -24,7 +24,10 @@ import com.intellij.notification.NotificationListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.keymap.Keymap;
@@ -50,7 +53,7 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
import com.maddyhome.idea.vim.listener.VimListenerManager;
import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
import com.maddyhome.idea.vim.ui.VimRcFileState;
@@ -324,7 +327,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
showMessage(msg);
}
public static void showMessage(@Nls @Nullable String msg) {
public static void showMessage(@Nls(capitalization = Nls.Capitalization.Sentence) @Nullable String msg) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
getInstance().message = msg;
}

View File

@@ -20,15 +20,29 @@ package com.maddyhome.idea.vim.action
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.vimForEachCaret
class ResetModeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_WRITABLE
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
val modeBeforeReset = editor.mode
KeyHandler.getInstance().fullReset(editor.getTopLevelEditor())
if (modeBeforeReset == CommandState.Mode.INSERT) {
editor.vimForEachCaret { caret ->
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
MotionGroup.moveCaret(editor, caret, position)
}
}
return true
}
}

View File

@@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.action
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.DumbAwareToggleAction
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.ui.VimActions
/**
@@ -38,7 +39,7 @@ class VimPluginToggleAction : DumbAwareToggleAction() {
super.update(e)
e.presentation.text = if (VimActions.actionPlace == e.place) {
if (VimPlugin.isEnabled()) "Enabled" else "Enable"
} else "Vim Emulator"
if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable")
} else MessageHelper.message("action.VimPluginToggle.text")
}
}

View File

@@ -128,7 +128,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
private fun isEnabledForEscape(editor: Editor): Boolean {
return editor.isPrimaryEditor()
|| EditorHelper.isFileEditor(editor) && !editor.inNormalMode
|| OptionsManager.ideaenabledbufs.contains("dialog") && !editor.inNormalMode
|| OptionsManager.ideavimsupport.contains("dialog") && !editor.inNormalMode
}
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.VimNlsSafe
import java.util.*
import kotlin.math.max
@@ -43,7 +44,10 @@ class AddInlineInlaysAction : AnAction() {
val lineLength = EditorHelper.getLineLength(editor, EditorHelper.visualLineToLogicalLine(editor, currentVisualLine))
while (i < lineLength) {
val relatesToPrecedingText = random.nextInt(10) > 7
@VimNlsSafe
val text = "a".repeat(max(1, random.nextInt(7)))
val offset = EditorHelper.visualPositionToOffset(editor, VisualPosition(currentVisualLine, i))
// We don't need a custom renderer, just use the standard parameter hint renderer
inlayModel.addInlineElement(offset, relatesToPrecedingText, HintRenderer(if (relatesToPrecedingText) ":$text" else "$text:"))

View File

@@ -23,10 +23,10 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.vimLastColumn
/**

View File

@@ -23,10 +23,10 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.vimLastColumn
/**

View File

@@ -23,10 +23,10 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.group.visual.updateCaretState
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
/**
* @author Alex Plate

View File

@@ -19,10 +19,14 @@ package com.maddyhome.idea.vim.action.motion.visual
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.vimForEachCaret
/**
* @author vlan
@@ -32,6 +36,16 @@ class VisualExitModeAction : VimActionHandler.SingleExecution() {
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
editor.getTopLevelEditor().exitVisualMode()
// Should it be in [exitVisualMode]?
editor.vimForEachCaret { caret ->
val lineEnd = EditorHelper.getLineEndForOffset(editor, caret.offset)
if (lineEnd == caret.offset) {
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
MotionGroup.moveCaret(editor, caret, position)
}
}
return true
}
}

View File

@@ -1,6 +1,9 @@
package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.action.ResetModeAction
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.key.Node
@@ -24,6 +27,9 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode) {
var expectedArgumentType: Argument.Type? = null
private set
var prevExpectedArgumentType: Argument.Type? = null
private set
val isReady get() = commandState == CurrentCommandState.READY
val isBad get() = commandState == CurrentCommandState.BAD_COMMAND
val isEmpty get() = commandParts.isEmpty()
@@ -38,6 +44,7 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode) {
fun pushCommandPart(action: EditorActionHandlerBase) {
commandParts.add(Command(count, action, action.type, action.flags))
prevExpectedArgumentType = expectedArgumentType
expectedArgumentType = action.argumentType
count = 0
}
@@ -106,6 +113,14 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode) {
return currentCommandPartNode !is RootNode
}
fun isPuttingLiteral(): Boolean {
return !commandParts.isEmpty() && commandParts.last.action is InsertCompletedLiteralAction
}
fun isDone(): Boolean {
return commandParts.isEmpty()
}
fun completeCommandPart(argument: Argument) {
commandParts.peekLast().argument = argument
commandState = CurrentCommandState.READY
@@ -121,6 +136,11 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode) {
}
fun buildCommand(): Command {
if (commandParts.last.action is InsertCompletedDigraphAction || commandParts.last.action is ResetModeAction) {
expectedArgumentType = prevExpectedArgumentType
prevExpectedArgumentType = null
return commandParts.removeLast()
}
var command: Command = commandParts.removeFirst()
while (commandParts.size > 0) {
@@ -147,6 +167,7 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode) {
commandParts.clear()
keyList.clear()
expectedArgumentType = null
prevExpectedArgumentType = null
}
fun resetInProgressCommandPart(commandPartNode: CommandPartNode) {

View File

@@ -23,6 +23,8 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.DigraphResult
import com.maddyhome.idea.vim.helper.DigraphSequence
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.VimNlsSafe
import com.maddyhome.idea.vim.helper.noneOfEnum
import com.maddyhome.idea.vim.helper.vimCommandState
import com.maddyhome.idea.vim.key.CommandPartNode
@@ -178,7 +180,7 @@ class CommandState private constructor() {
executingCommand = null
resetModes()
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
startDigraphSequence()
digraphSequence.reset()
updateStatus()
}
@@ -232,6 +234,7 @@ class CommandState private constructor() {
* be added. It's better not to compare the whole string but only
* the leading character(s).
*/
@VimNlsSafe
fun toVimNotation(): String {
return when (mode) {
Mode.COMMAND -> "n"
@@ -266,7 +269,7 @@ class CommandState private constructor() {
if (msg.isNotEmpty()) {
msg.append(" - ")
}
msg.append("recording")
msg.append(MessageHelper.message("show.mode.recording"))
}
VimPlugin.showMode(msg.toString())
}

View File

@@ -19,6 +19,8 @@
package com.maddyhome.idea.vim.common
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.MessageHelper
import org.jetbrains.annotations.NonNls
/**
* @author Elliot Courant
@@ -39,10 +41,10 @@ class Alias(
}
private companion object {
const val LessThan = "<lt>"
const val Count = "<count>"
const val Arguments = "<args>"
const val QuotedArguments = "<q-args>"
@NonNls const val LessThan = "<lt>"
@NonNls const val Count = "<count>"
@NonNls const val Arguments = "<args>"
@NonNls const val QuotedArguments = "<q-args>"
}
fun getCommand(input: String, count: Int): String {
@@ -52,7 +54,7 @@ class Alias(
var compiledCommand = this.command
val cleanedInput = input.trim().removePrefix(name).trim()
if (minimumNumberOfArguments > 0 && cleanedInput.isEmpty()) {
VimPlugin.showMessage("E471: Argument required")
VimPlugin.showMessage(MessageHelper.message("e471.argument.required"))
VimPlugin.indicateError()
return ""
}

View File

@@ -22,6 +22,7 @@ import com.intellij.ide.bookmarks.Bookmark
import com.intellij.ide.bookmarks.BookmarkManager
import com.intellij.openapi.project.Project
import com.maddyhome.idea.vim.group.MarkGroup
import org.jetbrains.annotations.NonNls
import java.lang.ref.WeakReference
interface Mark {
@@ -35,7 +36,7 @@ interface Mark {
fun clear()
object KeySorter : Comparator<Mark> {
private const val ORDER = "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"[]^.<>"
@NonNls private const val ORDER = "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"[]^.<>"
override fun compare(o1: Mark, o2: Mark): Int {
return ORDER.indexOf(o1.key) - ORDER.indexOf(o2.key)

View File

@@ -20,8 +20,8 @@ package com.maddyhome.idea.vim.common
import com.intellij.codeInsight.editorActions.TextBlockTransferableData
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.helper.StringHelper
import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent
import java.util.*
import javax.swing.KeyStroke
class Register {
@@ -81,7 +81,7 @@ class Register {
}
object KeySorter : Comparator<Register> {
private const val ORDER = "\"0123456789abcdefghijklmnopqrstuvwxyz-*+.:%#/="
@NonNls private const val ORDER = "\"0123456789abcdefghijklmnopqrstuvwxyz-*+.:%#/="
override fun compare(o1: Register, o2: Register): Int {
return ORDER.indexOf(o1.name.toLowerCase()) - ORDER.indexOf(o2.name.toLowerCase())

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.common
import org.jetbrains.annotations.Contract
import org.jetbrains.annotations.NonNls
import kotlin.math.max
import kotlin.math.min
@@ -85,7 +86,7 @@ class TextRange(val startOffsets: IntArray, val endOffsets: IntArray) {
operator fun contains(offset: Int): Boolean = if (isMultiple) false else offset in startOffset until endOffset
override fun toString(): String {
val sb = StringBuilder()
@NonNls val sb = StringBuilder()
sb.append("TextRange")
sb.append("{starts=")

View File

@@ -60,7 +60,7 @@ class MigrationComponents(
@Service
class ApplicationConfigurationMigrator(migrationComponents: MigrationComponents) {
@Suppress("unused")
@Suppress("unused", "HardCodedStringLiteral")
constructor() : this(productionMigrationComponents)
private val migrators = migrationComponents.groupedMigrators

View File

@@ -21,6 +21,7 @@
package com.maddyhome.idea.vim.config.migration
import com.intellij.openapi.application.PathManager
import org.jetbrains.annotations.NonNls
interface VersionDetector {
fun extractVersion(): Int?
@@ -28,7 +29,7 @@ interface VersionDetector {
object `Detect versions 3, 4, 5, 6` : VersionDetector {
val pattern = "state version=\"(.)\"".toRegex()
@NonNls val pattern = "state version=\"(.)\"".toRegex()
override fun extractVersion(): Int? {
val configFile = PathManager.getOptionsFile("vim_settings")

View File

@@ -18,8 +18,6 @@
package com.maddyhome.idea.vim.ex
import java.util.*
class CommandNode(command: ExBeanClass? = null) {
var commandHandler: ExBeanClass? = command

View File

@@ -150,7 +150,7 @@ public class CommandParser {
}
processCommand(editor, context, commandAlias, count, aliasCountdown - 1);
} else {
VimPlugin.showMessage("Recursion detected, maximum alias depth reached.");
VimPlugin.showMessage(MessageHelper.message("recursion.detected.maximum.alias.depth.reached"));
VimPlugin.indicateError();
logger.warn("Recursion detected, maximum alias depth reached. ");
}
@@ -307,6 +307,10 @@ public class CommandParser {
state = State.RANGE_SHORT_PATTERN;
reprocess = false;
}
else if (ch == ',') {
location.append('.');
state = State.RANGE_MAYBE_DONE;
}
else if (ch == '/' || ch == '?') {
location.append(ch);
patternType = ch;

View File

@@ -33,6 +33,7 @@ import com.maddyhome.idea.vim.ex.CommandHandler.RangeFlag.RANGE_OPTIONAL
import com.maddyhome.idea.vim.ex.CommandHandlerFlags
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.runAfterGotFocus
/**
@@ -45,7 +46,7 @@ class ActionHandler : CommandHandler.SingleExecution() {
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean {
val actionName = cmd.argument.trim()
val action = ActionManager.getInstance().getAction(actionName) ?: run {
VimPlugin.showMessage("Action not found: $actionName")
VimPlugin.showMessage(MessageHelper.message("action.not.found.0", actionName))
return false
}
val application = ApplicationManager.getApplication()

View File

@@ -30,6 +30,7 @@ import com.maddyhome.idea.vim.ex.CommandHandlerFlags
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.StringHelper
/**
@@ -55,7 +56,7 @@ class ActionListHandler : CommandHandler.SingleExecution() {
.joinToString(lineSeparator)
ExOutputModel.getInstance(editor).output("--- Actions ---$lineSeparator$actions")
ExOutputModel.getInstance(editor).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
return true
}
}

View File

@@ -27,6 +27,7 @@ import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper
/**
* Handles buffer, buf, bu, b.
@@ -47,7 +48,7 @@ class BufferHandler : CommandHandler.SingleExecution() {
val bufNum = buffer.toInt() - 1
if (!VimPlugin.getFile().selectFile(bufNum, context)) {
VimPlugin.showMessage("Buffer $bufNum does not exist")
VimPlugin.showMessage(MessageHelper.message("buffer.0.does.not.exist", bufNum))
result = false
}
} else {
@@ -55,12 +56,12 @@ class BufferHandler : CommandHandler.SingleExecution() {
when(editors.size) {
0 -> {
VimPlugin.showMessage("No matching buffer for $buffer")
VimPlugin.showMessage(MessageHelper.message("no.matching.buffer.for.0", buffer))
result = false
}
1 -> {
if (EditorHelper.hasUnsavedChanges(editor) && !overrideModified) {
VimPlugin.showMessage("No write since last change (add ! to override)")
VimPlugin.showMessage(MessageHelper.message("no.write.since.last.change.add.to.override"))
result = false
}
else {
@@ -68,7 +69,7 @@ class BufferHandler : CommandHandler.SingleExecution() {
}
}
else -> {
VimPlugin.showMessage("More than one match for $buffer")
VimPlugin.showMessage(MessageHelper.message("more.than.one.match.for.0", buffer))
result = false
}
}

View File

@@ -31,6 +31,7 @@ import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.helper.EditorHelper
import org.jetbrains.annotations.NonNls
import java.io.File
/**
@@ -115,7 +116,7 @@ class BufferListHandler : CommandHandler.SingleExecution() {
}
private fun getBufferStatus(editor: Editor, file: VirtualFile, currentFile: VirtualFile, previousFile: VirtualFile?): String {
val bufStatus = StringBuilder()
@NonNls val bufStatus = StringBuilder()
when(file) {
currentFile -> bufStatus.append("%a ")

View File

@@ -32,6 +32,8 @@ import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.vimscript.VimScriptCommandHandler
import com.maddyhome.idea.vim.group.CommandGroup.Companion.BLACKLISTED_ALIASES
import com.maddyhome.idea.vim.helper.MessageHelper
import org.jetbrains.annotations.NonNls
/**
* @author Elliot Courant
@@ -42,16 +44,13 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// Static definitions needed for aliases.
private companion object {
const val overridePrefix = "!"
const val argsPrefix = "-nargs"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls const val argsPrefix = "-nargs"
const val anyNumberOfArguments = "*"
const val zeroOrOneArguments = "?"
const val moreThanZeroArguments = "+"
const val errorInvalidNumberOfArguments = "E176: Invalid number of arguments"
const val errorCannotStartWithLowercase = "E183: User defined commands must start with an uppercase letter"
const val errorReservedName = "E841: Reserved name, cannot be used for user defined command"
const val errorCommandAlreadyExists = "E174: Command already exists: add ! to replace it"
}
override fun execute(cmd: ExCommand) {
@@ -95,7 +94,7 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// in the actual alias being created, and we don't want to parse that one.
val trimmedInput = argument.takeWhile { it != ' ' }
val pattern = Regex("(?>-nargs=((|[-])\\d+|[?]|[+]|[*]))").find(trimmedInput) ?: run {
VimPlugin.showMessage(errorInvalidNumberOfArguments)
VimPlugin.showMessage(MessageHelper.message("e176.invalid.number.of.arguments"))
return false
}
val nargForTrim = pattern.groupValues[0]
@@ -118,7 +117,7 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// I missed something, since the regex limits the value to be ? + * or
// a valid number, its not possible (as far as I know) to have another value
// that regex would accept that is not valid.
VimPlugin.showMessage(errorInvalidNumberOfArguments)
VimPlugin.showMessage(MessageHelper.message("e176.invalid.number.of.arguments"))
return false
}
}
@@ -126,7 +125,7 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// Not sure why this isn't documented, but if you try to create a command in vim
// with an explicit number of arguments greater than 1 it returns this error.
if (argNum > 1 || argNum < 0) {
VimPlugin.showMessage(errorInvalidNumberOfArguments)
VimPlugin.showMessage(MessageHelper.message("e176.invalid.number.of.arguments"))
return false
}
minNumberOfArgs = argNum
@@ -148,12 +147,12 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// User-aliases need to begin with an uppercase character.
if (!alias[0].isUpperCase()) {
VimPlugin.showMessage(errorCannotStartWithLowercase)
VimPlugin.showMessage(MessageHelper.message("e183.user.defined.commands.must.start.with.an.uppercase.letter"))
return false
}
if (alias in BLACKLISTED_ALIASES) {
VimPlugin.showMessage(errorReservedName)
VimPlugin.showMessage(MessageHelper.message("e841.reserved.name.cannot.be.used.for.user.defined.command"))
return false
}
@@ -169,7 +168,7 @@ class CmdHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
// If we are not over-writing existing aliases, and an alias with the same command
// already exists then we want to do nothing.
if (!overrideAlias && VimPlugin.getCommand().hasAlias(alias)) {
VimPlugin.showMessage(errorCommandAlreadyExists)
VimPlugin.showMessage(MessageHelper.message("e174.command.already.exists.add.to.replace.it"))
return false
}

View File

@@ -24,12 +24,13 @@ 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.flags
import com.maddyhome.idea.vim.helper.MessageHelper
class DelCmdHandler : CommandHandler.SingleExecution() {
override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY)
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean {
if (!VimPlugin.getCommand().hasAlias(cmd.argument)) {
VimPlugin.showMessage("E184: No such user-defined command: ${cmd.argument}")
VimPlugin.showMessage(MessageHelper.message("e184.no.such.user.defined.command.0", cmd.argument))
return false
}

View File

@@ -24,6 +24,7 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.flags
import org.jetbrains.annotations.NonNls
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
@@ -37,6 +38,7 @@ class HelpHandler : CommandHandler.SingleExecution() {
return true
}
@NonNls
private fun helpTopicUrl(topic: String): String {
if (topic.isBlank()) return HELP_ROOT_URL

View File

@@ -36,7 +36,6 @@ import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.Msg
import com.maddyhome.idea.vim.helper.fileSize
import java.util.*
import kotlin.math.min
class MoveTextHandler : CommandHandler.SingleExecution() {

View File

@@ -28,9 +28,8 @@ import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.ranges.LineRange
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.inBlockSubMode
import java.util.*
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
/**
* @author Alex Selesse

View File

@@ -24,11 +24,14 @@ 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.flags
import org.jetbrains.annotations.NonNls
class SplitHandler : CommandHandler.SingleExecution() {
override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY)
@NonNls private val visualSplitPrefix = "v"
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean {
if (cmd.command.startsWith("v")) {
if (cmd.command.startsWith(visualSplitPrefix)) {
VimPlugin.getWindow().splitWindowVertical(context, cmd.argument)
} else {
VimPlugin.getWindow().splitWindowHorizontal(context, cmd.argument)

View File

@@ -26,6 +26,7 @@ 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.flags
import com.maddyhome.idea.vim.helper.MessageHelper
/**
* @author Rieon Ke
@@ -51,7 +52,7 @@ class TabCloseHandler : CommandHandler.SingleExecution() {
val select = if (index == current) index + 1 else current
tabbedPane.removeTabAt(index, select)
} else {
VimPlugin.showMessage("Error: invalid command argument")
VimPlugin.showMessage(MessageHelper.message("error.invalid.command.argument"))
}
return true

View File

@@ -0,0 +1,31 @@
/*
* 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.ex.handler.mapping
import com.maddyhome.idea.vim.command.MappingMode
import org.jetbrains.annotations.NonNls
internal class CommandInfo(
@NonNls val prefix: String,
@NonNls suffix: String,
val mappingModes: Set<MappingMode>,
val isRecursive: Boolean
) {
val command = if (suffix.isBlank()) prefix else "$prefix[$suffix]"
}

View File

@@ -0,0 +1,69 @@
/*
* 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.ex.handler.mapping
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.CommandHandler.Access.READ_ONLY
import com.maddyhome.idea.vim.ex.CommandHandler.ArgumentFlag.ARGUMENT_FORBIDDEN
import com.maddyhome.idea.vim.ex.CommandHandler.RangeFlag.RANGE_FORBIDDEN
import com.maddyhome.idea.vim.ex.CommandHandlerFlags
import com.maddyhome.idea.vim.ex.CommandName
import com.maddyhome.idea.vim.ex.ComplicatedNameExCommand
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.commands
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.vimscript.VimScriptCommandHandler
class MapClearHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler, ComplicatedNameExCommand {
override val argFlags: CommandHandlerFlags = flags(RANGE_FORBIDDEN, ARGUMENT_FORBIDDEN, READ_ONLY)
override val names: Array<CommandName> = COMMAND_NAMES
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean = executeCommand(cmd)
override fun execute(cmd: ExCommand) {
executeCommand(cmd)
}
private fun executeCommand(cmd: ExCommand): Boolean {
val commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) } ?: return false
VimPlugin.getKey().removeKeyMapping(commandInfo.mappingModes)
return true
}
companion object {
private val COMMAND_INFOS = arrayOf(
CommandInfo("mapc", "lear", MappingMode.NVO, false),
CommandInfo("nmapc", "lear", MappingMode.N, false),
CommandInfo("vmapc", "lear", MappingMode.V, false),
CommandInfo("xmapc", "lear", MappingMode.X, false),
CommandInfo("smapc", "lear", MappingMode.S, false),
CommandInfo("omapc", "lear", MappingMode.O, false),
CommandInfo("imapc", "lear", MappingMode.I, false),
CommandInfo("cmapc", "lear", MappingMode.C, false)
)
val COMMAND_NAMES = commands(*COMMAND_INFOS.map { it.command }.toTypedArray())
}
}

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.ex.handler
package com.maddyhome.idea.vim.ex.handler.mapping
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
@@ -30,11 +30,12 @@ import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.commands
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.handler.MapHandler.SpecialArgument.EXPR
import com.maddyhome.idea.vim.ex.handler.MapHandler.SpecialArgument.SCRIPT
import com.maddyhome.idea.vim.ex.handler.mapping.MapHandler.SpecialArgument.EXPR
import com.maddyhome.idea.vim.ex.handler.mapping.MapHandler.SpecialArgument.SCRIPT
import com.maddyhome.idea.vim.ex.vimscript.VimScriptCommandHandler
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.key.MappingOwner
import org.jetbrains.annotations.NonNls
import java.util.*
import javax.swing.KeyStroke
@@ -57,34 +58,32 @@ class MapHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler, Co
@Throws(ExException::class)
private fun executeCommand(cmd: ExCommand, editor: Editor?): Boolean {
val commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) }
if (commandInfo != null) {
val argument = cmd.argument
val modes = commandInfo.mappingModes
if (argument.isEmpty()) {
return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
} else {
val arguments = try {
parseCommandArguments(argument)
} catch (ignored: IllegalArgumentException) {
return false
}
val commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) } ?: return false
val argument = cmd.argument
val modes = commandInfo.mappingModes
if (arguments != null) {
for (unsupportedArgument in UNSUPPORTED_SPECIAL_ARGUMENTS) {
if (unsupportedArgument in arguments.specialArguments) {
throw ExException("Unsupported map argument: $unsupportedArgument")
}
}
VimPlugin.getKey().putKeyMapping(modes, arguments.fromKeys, MappingOwner.IdeaVim, arguments.toKeys, commandInfo.isRecursive)
return true
}
if (argument.isEmpty()) return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
val arguments = try {
parseCommandArguments(argument) ?: return false
} catch (ignored: IllegalArgumentException) {
return false
}
for (unsupportedArgument in UNSUPPORTED_SPECIAL_ARGUMENTS) {
if (unsupportedArgument in arguments.specialArguments) {
throw ExException("Unsupported map argument: $unsupportedArgument")
}
}
return false
VimPlugin.getKey()
.putKeyMapping(modes, arguments.fromKeys, MappingOwner.IdeaVim, arguments.toKeys, commandInfo.isRecursive)
return true
}
@Suppress("unused")
@NonNls
private enum class SpecialArgument(val myName: String) {
BUFFER("<buffer>"),
NOWAIT("<nowait>"),
@@ -113,10 +112,6 @@ class MapHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler, Co
private class CommandArguments(val specialArguments: Set<SpecialArgument>, val fromKeys: List<KeyStroke>,
val toKeys: List<KeyStroke>)
private class CommandInfo(val prefix: String, suffix: String, val mappingModes: Set<MappingMode>, val isRecursive: Boolean) {
val command = if (suffix.isBlank()) prefix else "$prefix[$suffix]"
}
companion object {
private const val CTRL_V = '\u0016'
private val COMMAND_INFOS = arrayOf(

View File

@@ -0,0 +1,75 @@
/*
* 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.ex.handler.mapping
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.CommandHandler.Access.READ_ONLY
import com.maddyhome.idea.vim.ex.CommandHandler.ArgumentFlag.ARGUMENT_REQUIRED
import com.maddyhome.idea.vim.ex.CommandHandler.RangeFlag.RANGE_FORBIDDEN
import com.maddyhome.idea.vim.ex.CommandHandlerFlags
import com.maddyhome.idea.vim.ex.CommandName
import com.maddyhome.idea.vim.ex.ComplicatedNameExCommand
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.commands
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.vimscript.VimScriptCommandHandler
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
class UnMapHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler, ComplicatedNameExCommand {
override val argFlags: CommandHandlerFlags = flags(RANGE_FORBIDDEN, ARGUMENT_REQUIRED, READ_ONLY)
override val names: Array<CommandName> = COMMAND_NAMES
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean = executeCommand(cmd)
override fun execute(cmd: ExCommand) {
executeCommand(cmd)
}
private fun executeCommand(cmd: ExCommand): Boolean {
val commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) } ?: return false
val argument = cmd.argument
if (argument.isEmpty()) return false
val parsedKeys = parseKeys(argument.trimStart())
VimPlugin.getKey().removeKeyMapping(commandInfo.mappingModes, parsedKeys)
return true
}
companion object {
private val COMMAND_INFOS = arrayOf(
CommandInfo("unm", "ap", MappingMode.NVO, false),
CommandInfo("nun", "map", MappingMode.N, false),
CommandInfo("vu", "nmap", MappingMode.V, false),
CommandInfo("xu", "nmap", MappingMode.X, false),
CommandInfo("sunm", "ap", MappingMode.S, false),
CommandInfo("ou", "nmap", MappingMode.O, false),
CommandInfo("iu", "nmap", MappingMode.I, false),
CommandInfo("cu", "nmap", MappingMode.C, false)
)
val COMMAND_NAMES = commands(*COMMAND_INFOS.map { it.command }.toTypedArray())
}
}

View File

@@ -24,6 +24,7 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import org.jetbrains.annotations.NonNls
import kotlin.math.min
/**
@@ -179,6 +180,7 @@ class Ranges {
count = 0
}
@NonNls
override fun toString(): String = "Ranges[ranges=$ranges]"
private var startLine = 0

View File

@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.ex.vimscript
import com.maddyhome.idea.vim.ex.CommandParser
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ui.VimRcFileState
import org.jetbrains.annotations.NonNls
import java.io.File
import java.io.IOException
import java.nio.file.Paths
@@ -30,8 +31,14 @@ import java.util.regex.Pattern
* @author vlan
*/
object VimScriptParser {
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val VIMRC_FILE_NAME = "ideavimrc"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private val HOME_VIMRC_PATHS = arrayOf(".$VIMRC_FILE_NAME", "_$VIMRC_FILE_NAME")
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private val XDG_VIMRC_PATH = "ideavim" + File.separator + VIMRC_FILE_NAME
private val DOUBLE_QUOTED_STRING = Pattern.compile("\"([^\"]*)\"")
private val SINGLE_QUOTED_STRING = Pattern.compile("'([^']*)'")

View File

@@ -21,7 +21,6 @@ package com.maddyhome.idea.vim.extension
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.util.xmlb.annotations.Attribute
import com.intellij.util.xmlb.annotations.CollectionBean
import com.intellij.util.xmlb.annotations.Tag
import com.intellij.util.xmlb.annotations.XCollection
import java.util.concurrent.atomic.AtomicBoolean

View File

@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.extension;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.helper.VimNlsSafe;
import com.maddyhome.idea.vim.key.MappingOwner;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -31,10 +32,12 @@ public interface VimExtension {
@NotNull ExtensionPointName<ExtensionBeanClass> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension");
/**
* @deprecated Please set extension name in <vimExtension> tag
* @deprecated This property is not used anymore, but we'll remove it much later to keep the compatibility of IdeaVim
* extensions with previous versions of IdeaVim.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "0.63")
@ApiStatus.ScheduledForRemoval(inVersion = "0.65")
@VimNlsSafe
@NotNull String getName();
default MappingOwner getOwner() {

View File

@@ -30,7 +30,7 @@ import com.maddyhome.idea.vim.helper.TestInputModel
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.ui.ExEntryPanel
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
import com.maddyhome.idea.vim.ui.ModalEntry
import java.awt.event.KeyEvent
import javax.swing.KeyStroke

View File

@@ -12,12 +12,16 @@ import com.maddyhome.idea.vim.extension.VimExtension;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.InlayHelperKt;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor;
import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.EnumSet;
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
@@ -183,7 +187,8 @@ public class VimArgTextObjExtension implements VimExtension {
try {
bracketPairs = BracketPairs.fromBracketPairList(bracketPairsVar);
} catch (BracketPairs.ParseException parseException) {
VimPlugin.showMessage("argtextobj: Invalid value of g:argtextobj_pairs -- " + parseException.getMessage());
VimPlugin.showMessage(
MessageHelper.message("argtextobj.invalid.value.of.g.argtextobj.pairs.0", parseException.getMessage()));
VimPlugin.indicateError();
return null;
}
@@ -259,7 +264,7 @@ public class VimArgTextObjExtension implements VimExtension {
private int rightBound = Integer.MIN_VALUE;
private int leftBracket;
private int rightBracket;
private String error = null;
private @Nls String error = null;
private static final String QUOTES = "\"'";
private static final int MAX_SEARCH_LINES = 10;

View File

@@ -51,6 +51,7 @@ import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.key.OperatorFunction
import org.jetbrains.annotations.NonNls
/**
* This emulation misses:
@@ -80,8 +81,11 @@ class VimExchangeExtension : VimExtension {
}
companion object {
@NonNls
const val EXCHANGE_CMD = "<Plug>(Exchange)"
@NonNls
const val EXCHANGE_CLEAR_CMD = "<Plug>(ExchangeClear)"
@NonNls
const val EXCHANGE_LINE_CMD = "<Plug>(ExchangeLine)"
val EXCHANGE_KEY = Key<Exchange>("exchange")

View File

@@ -35,16 +35,21 @@ import com.maddyhome.idea.vim.VimProjectService
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.vimscript.VimScriptGlobalEnvironment
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.listener.VimInsertListener
import com.maddyhome.idea.vim.listener.VimYankListener
import com.maddyhome.idea.vim.option.StrictMode
import org.jetbrains.annotations.NonNls
import java.awt.Color
import java.awt.Font
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
const val DEFAULT_HIGHLIGHT_DURATION: Long = 300
@NonNls
private const val HIGHLIGHT_DURATION_VARIABLE_NAME = "g:highlightedyank_highlight_duration"
@NonNls
private const val HIGHLIGHT_COLOR_VARIABLE_NAME = "g:highlightedyank_highlight_color"
private var defaultHighlightTextColor: Color? = null
@@ -197,7 +202,13 @@ class VimHighlightedYank: VimExtension, VimYankListener, VimInsertListener {
extractFun(value)
}
catch (e: Exception){
VimPlugin.showMessage("highlightedyank: Invalid value of $variableName -- ${e.message}")
VimPlugin.showMessage(
MessageHelper.message(
"highlightedyank.invalid.value.of.0.1",
variableName,
e.message ?: ""
)
)
default
}

View File

@@ -34,21 +34,34 @@ import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.vimSetSelection
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.SearchHelper.findWordUnderCursor
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.helper.endOffsetInclusive
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.option.OptionsManager
import org.jetbrains.annotations.NonNls
import java.lang.Integer.min
import java.util.*
import kotlin.Comparator
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val NEXT_WHOLE_OCCURRENCE = "<Plug>NextWholeOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val NEXT_OCCURRENCE = "<Plug>NextOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val SKIP_OCCURRENCE = "<Plug>SkipOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val REMOVE_OCCURRENCE = "<Plug>RemoveOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val ALL_WHOLE_OCCURRENCES = "<Plug>AllWholeOccurrences"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls
private const val ALL_OCCURRENCES = "<Plug>AllOccurrences"
/**
@@ -97,7 +110,7 @@ class VimMultipleCursorsExtension : VimExtension {
if (range.startOffset > caret.offset) return
val nextOffset = findNextOccurrence(editor, caret, range, whole)
if (nextOffset == caret.selectionStart) VimPlugin.showMessage("No more matches")
if (nextOffset == caret.selectionStart) VimPlugin.showMessage(MessageHelper.message("message.no.more.matches"))
} else {
val newPositions = arrayListOf<VisualPosition>()
val patterns = sortedSetOf(patternComparator)
@@ -140,7 +153,7 @@ class VimMultipleCursorsExtension : VimExtension {
caretModel.allCarets.forEach {
if (it.selectionStart == nextOffset) {
VimPlugin.showMessage("No more matches")
VimPlugin.showMessage(MessageHelper.message("message.no.more.matches"))
return
}
}
@@ -194,7 +207,7 @@ class VimMultipleCursorsExtension : VimExtension {
editor.caretModel.allCarets.forEach {
if (it.selectionStart == nextOffset) {
VimPlugin.showMessage("No more matches")
VimPlugin.showMessage(MessageHelper.message("message.no.more.matches"))
return
}
}

View File

@@ -42,6 +42,7 @@ import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.vimForEachCaret
import com.maddyhome.idea.vim.key.OperatorFunction
import org.jetbrains.annotations.NonNls
class ReplaceWithRegister : VimExtension {
@@ -123,8 +124,11 @@ class ReplaceWithRegister : VimExtension {
}
companion object {
@NonNls
private const val RWR_OPERATOR = "<Plug>ReplaceWithRegisterOperator"
@NonNls
private const val RWR_LINE = "<Plug>ReplaceWithRegisterLine"
@NonNls
private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
private fun doReplace(editor: Editor, visualSelection: PutData.VisualSelection) {

View File

@@ -69,6 +69,7 @@ import com.maddyhome.idea.vim.option.BoundListOption;
import com.maddyhome.idea.vim.option.OptionsManager;
import kotlin.Pair;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -93,6 +94,9 @@ public class ChangeGroup {
private static final ImmutableSet<String> wordMotions =
ImmutableSet.of(VIM_MOTION_WORD_RIGHT, VIM_MOTION_BIG_WORD_RIGHT, VIM_MOTION_CAMEL_RIGHT);
@NonNls private static final String HEX_START = "0x";
@NonNls private static final String MAX_HEX_INTEGER = "ffffffffffffffff";
private @Nullable Command lastInsert;
private List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList();
@@ -1940,7 +1944,7 @@ public class ChangeGroup {
char ch = text.charAt(0);
if (hex && SearchHelper.NumberType.HEX.equals(numberType)) {
if (!text.toLowerCase().startsWith("0x")) throw new RuntimeException("Hex number should start with 0x: " + text);
if (!text.toLowerCase().startsWith(HEX_START)) throw new RuntimeException("Hex number should start with 0x: " + text);
for (int i = text.length() - 1; i >= 2; i--) {
int index = "abcdefABCDEF".indexOf(text.charAt(i));
if (index >= 0) {
@@ -1952,7 +1956,7 @@ public class ChangeGroup {
BigInteger num = new BigInteger(text.substring(2), 16);
num = num.add(BigInteger.valueOf(count));
if (num.compareTo(BigInteger.ZERO) < 0) {
num = new BigInteger("ffffffffffffffff", 16).add(BigInteger.ONE).add(num);
num = new BigInteger(MAX_HEX_INTEGER, 16).add(BigInteger.ONE).add(num);
}
number = num.toString(16);
number = StringsKt.padStart(number, text.length() - 2, '0');

View File

@@ -19,13 +19,14 @@
package com.maddyhome.idea.vim.group
import com.maddyhome.idea.vim.common.Alias
import org.jetbrains.annotations.NonNls
/**
* @author Elliot Courant
*/
class CommandGroup {
companion object {
val BLACKLISTED_ALIASES = arrayOf("X", "Next", "Print")
@NonNls val BLACKLISTED_ALIASES = arrayOf("X", "Next", "Print")
private const val overridePrefix = "!"
}

View File

@@ -35,6 +35,7 @@ import com.maddyhome.idea.vim.option.OptionChangeListener;
import com.maddyhome.idea.vim.option.OptionsManager;
import org.jdom.Element;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +45,7 @@ import org.jetbrains.annotations.Nullable;
@State(name = "VimEditorSettings", storages = {@Storage(value = "$APP_CONFIG$/vim_settings.xml")})
public class EditorGroup implements PersistentStateComponent<Element> {
private static final boolean REFRAIN_FROM_SCROLLING_VIM_VALUE = true;
public static final String EDITOR_STORE_ELEMENT = "editor";
public static final @NonNls String EDITOR_STORE_ELEMENT = "editor";
private boolean isBlockCursor = false;
private boolean isRefrainFromScrolling = false;
@@ -203,6 +204,10 @@ public class EditorGroup implements PersistentStateComponent<Element> {
}
}
public boolean isBarCursor() {
return !isBlockCursor;
}
public void editorCreated(@NotNull Editor editor) {
isBlockCursor = editor.getSettings().isBlockCursor();
isRefrainFromScrolling = editor.getSettings().isRefrainFromScrolling();
@@ -217,7 +222,7 @@ public class EditorGroup implements PersistentStateComponent<Element> {
VimPlugin.getChange().insertBeforeCursor(editor, new EditorDataContext(editor, null));
KeyHandler.getInstance().reset(editor);
}
editor.getSettings().setBlockCursor(!CommandStateHelper.inInsertMode(editor));
editor.getSettings().setBlockCursor(!CommandStateHelper.inInsertMode(editor) || isBlockCursor);
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
}

View File

@@ -44,6 +44,7 @@ import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.helper.EditorHelperRt;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.SearchHelper;
import com.maddyhome.idea.vim.option.IdeaWriteData;
import com.maddyhome.idea.vim.option.OptionsManager;
@@ -85,7 +86,7 @@ public class FileGroup {
}
}
else {
VimPlugin.showMessage("Unable to find " + filename);
VimPlugin.showMessage(MessageHelper.message("unable.to.find.0", filename));
return false;
}

View File

@@ -27,6 +27,7 @@ import com.maddyhome.idea.vim.helper.StringHelper;
import com.maddyhome.idea.vim.option.NumberOption;
import com.maddyhome.idea.vim.option.OptionsManager;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,10 +40,10 @@ import java.util.Map;
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)
})
public class HistoryGroup implements PersistentStateComponent<Element> {
public static final String SEARCH = "search";
public static final String COMMAND = "cmd";
public static final String EXPRESSION = "expr";
public static final String INPUT = "input";
public static final @NonNls String SEARCH = "search";
public static final @NonNls String COMMAND = "cmd";
public static final @NonNls String EXPRESSION = "expr";
public static final @NonNls String INPUT = "input";
public void addEntry(String key, @NotNull String text) {
if (logger.isDebugEnabled()) {

View File

@@ -47,6 +47,7 @@ import com.maddyhome.idea.vim.key.*;
import kotlin.Pair;
import kotlin.text.StringsKt;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -65,9 +66,9 @@ import static java.util.stream.Collectors.toList;
*/
@State(name = "VimKeySettings", storages = {@Storage(value = "$APP_CONFIG$/vim_settings.xml")})
public class KeyGroup implements PersistentStateComponent<Element> {
public static final String SHORTCUT_CONFLICTS_ELEMENT = "shortcut-conflicts";
private static final String SHORTCUT_CONFLICT_ELEMENT = "shortcut-conflict";
private static final String OWNER_ATTRIBUTE = "owner";
public static final @NonNls String SHORTCUT_CONFLICTS_ELEMENT = "shortcut-conflicts";
private static final @NonNls String SHORTCUT_CONFLICT_ELEMENT = "shortcut-conflict";
private static final @NonNls String OWNER_ATTRIBUTE = "owner";
private static final String TEXT_ELEMENT = "text";
private static final Logger logger = Logger.getInstance(KeyGroup.class);
@@ -117,6 +118,14 @@ public class KeyGroup implements PersistentStateComponent<Element> {
unregisterKeyMapping(owner);
}
public void removeKeyMapping(@NotNull Set<MappingMode> modes, @NotNull List<KeyStroke> keys) {
modes.stream().map(this::getKeyMapping).forEach(o -> o.delete(keys));
}
public void removeKeyMapping(@NotNull Set<MappingMode> modes) {
modes.stream().map(this::getKeyMapping).forEach(KeyMapping::delete);
}
public void putKeyMapping(@NotNull Set<MappingMode> modes,
@NotNull List<KeyStroke> fromKeys,
@NotNull MappingOwner owner,
@@ -467,7 +476,7 @@ public class KeyGroup implements PersistentStateComponent<Element> {
return rows;
}
private static @NotNull String getModesStringCode(@NotNull Set<MappingMode> modes) {
private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
if (modes.equals(MappingMode.NVO)) {
return "";
}
@@ -525,7 +534,7 @@ public class KeyGroup implements PersistentStateComponent<Element> {
@Nullable
@Override
public Element getState() {
Element element = new Element("key");
@NonNls Element element = new Element("key");
saveData(element);
return element;
}

View File

@@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project;
import com.maddyhome.idea.vim.KeyHandler;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.StringHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -130,7 +131,8 @@ public class MacroGroup {
};
ApplicationManager.getApplication().invokeLater(
() -> CommandProcessor.getInstance().executeCommand(project, run, "Vim Macro Playback", keys.get(pos)));
() -> CommandProcessor.getInstance()
.executeCommand(project, run, MessageHelper.message("command.name.vim.macro.playback"), keys.get(pos)));
}
public void postKey(@NotNull KeyStroke stroke, @NotNull Editor editor) {

View File

@@ -48,6 +48,7 @@ import com.maddyhome.idea.vim.helper.SearchHelper;
import com.maddyhome.idea.vim.option.OptionsManager;
import org.jdom.Element;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -811,7 +812,7 @@ public class MarkGroup implements PersistentStateComponent<Element> {
private static final int SAVE_JUMP_COUNT = 100;
public static final String WR_GLOBAL_MARKS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String WR_REGULAR_FILE_MARKS = "abcdefghijklmnopqrstuvwxyz";
public static final @NonNls String WR_REGULAR_FILE_MARKS = "abcdefghijklmnopqrstuvwxyz";
/** Marks: abcdefghijklmnopqrstuvwxyz' */
private static final String WR_FILE_MARKS = WR_REGULAR_FILE_MARKS + "'";

View File

@@ -42,10 +42,12 @@ import com.maddyhome.idea.vim.handler.MotionActionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.option.NumberOption;
import com.maddyhome.idea.vim.option.OptionChangeListener;
import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import kotlin.Pair;
import kotlin.ranges.IntProgression;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -184,7 +186,7 @@ public class MotionGroup {
if (caretVisualLine < topVisualLine + scrollOffset) {
newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset);
}
else if (caretVisualLine >= bottomVisualLine - scrollOffset) {
else if (caretVisualLine > bottomVisualLine - scrollOffset) {
newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
}
else {
@@ -631,10 +633,10 @@ public class MotionGroup {
private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) {
// TODO: Make this work with soft wraps
// Vim's algorithm works counts line heights for wrapped lines. We're using visual lines, which handles collapsed
// folds, but treats soft wrapped lines as individual lines.
// Ironically, after figuring out how Vim's algorithm works (although not *why*), it looks likely to be rewritten as
// a dumb line for line reimplementation.
// Vim's algorithm works by counting line heights for wrapped lines. We're using visual lines, which handles
// collapsed folds, but treats soft wrapped lines as individual lines.
// Ironically, after figuring out how Vim's algorithm works (although not *why*) and reimplementing, it looks likely
// that this needs to be replaced as a more or less dumb line for line rewrite.
final int topLine = getVisualLineAtTopOfScreen(editor);
final int bottomLine = getVisualLineAtBottomOfScreen(editor);
@@ -642,7 +644,7 @@ public class MotionGroup {
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
final int topBound = topLine + scrollOffset;
final int bottomBound = Math.max(topBound + 1, bottomLine - scrollOffset);
final int bottomBound = Math.max(topBound, bottomLine - scrollOffset);
// If we need to scroll the current line more than half a screen worth of lines then we just centre the new
// current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line
@@ -650,7 +652,6 @@ public class MotionGroup {
// Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if
// the number of lines is less. I'm not sure what impact this has.
final int height = bottomLine - topLine + 1;
final int halfHeight = Math.max(2, (height / 2) - 1);
// Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean
// newLine = caretLine +/- MAX(sj, so)
@@ -663,7 +664,7 @@ public class MotionGroup {
// (See move.c:scroll_cursor_top)
//
// When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again
// expands lines above and below the new bottom line, but calcualtes things a little differently. The total number
// expands lines above and below the new bottom line, but calculates things a little differently. The total number
// of lines expanded is at least scrolljump and there must be at least scrolloff lines below.
// Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line.
// If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra
@@ -678,10 +679,26 @@ public class MotionGroup {
// out correct scroll locations
final int scrollJump = getScrollJump(editor, height);
if (caretLine < topBound) {
// Unavoidable fudge value. Multiline rendered doc comments can mean we have very few actual lines, and scrolling
// can get stuck in a loop as we re-centre the cursor instead of actually moving it. But if we ignore all inlays
// and use the approximate screen height instead of the actual screen height (in lines), we make incorrect
// assumptions about the top/bottom line numbers and can scroll to the wrong location. E.g. if there are enough doc
// comments (String.java) it's possible to get 12 lines of actual code on screen. Given scrolloff=5, it's very easy
// to hit problems, and have (scrolloffset > height / 2) and scroll to the middle of the screen. We'll use this
// fudge value to make sure we're working with sensible values. Note that this problem doesn't affect code without
// block inlays as positioning the cursor in the middle of the screen always positions it in a deterministic manner,
// relative to other text in the file.
final int inlayAwareMinHeightFudge = getApproximateScreenHeight(editor) / 2;
// Note that while these calculations do the same thing that Vim does, it processes them differently. E.g. it
// optionally checks and moves the top line, then optionally checks the bottom line. This gives us the same results
// via the tests.
if (height > inlayAwareMinHeightFudge && scrollOffset > height / 2) {
scrollVisualLineToMiddleOfScreen(editor, caretLine);
} else if (caretLine < topBound) {
// Scrolling up, put the cursor at the top of the window (minus scrolloff)
// Initial approximation in move.c:update_topline
if (topLine + scrollOffset - caretLine >= halfHeight) {
// Initial approximation in move.c:update_topline (including same calculation for halfHeight)
if (topLine + scrollOffset - caretLine >= Math.max(2, (height / 2) - 1)) {
scrollVisualLineToMiddleOfScreen(editor, caretLine);
}
else {
@@ -692,9 +709,12 @@ public class MotionGroup {
final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset);
final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine);
// Used is set to the line height of caretLine, and then incremented by line height of the lines above and
// below caretLine (up to scrolloff or end of file)
final int used = 1 + (newTopLine - topLine) + Math.min(scrollOffset, getVisualLineCount(editor) - topLine);
// Used is set to the line height of caretLine (1 or how many lines soft wraps take up), and then incremented by
// the line heights of the lines above and below caretLine (up to scrolloff or end of file).
// Our implementation ignores soft wrap line heights. Folds already have a line height of 1.
final int usedAbove = caretLine - newTopLine;
final int usedBelow = Math.min(scrollOffset, getVisualLineCount(editor) - caretLine);
final int used = 1 + usedAbove + usedBelow;
if (used > height) {
scrollVisualLineToMiddleOfScreen(editor, caretLine);
}
@@ -1374,4 +1394,21 @@ public class MotionGroup {
return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd);
}
}
public static class ScrollOptionsChangeListener implements OptionChangeListener<String> {
public static ScrollOptionsChangeListener INSTANCE = new ScrollOptionsChangeListener();
@Contract(pure = true)
private ScrollOptionsChangeListener() {
}
@Override
public void valueChange(String oldValue, String newValue) {
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
if (UserDataManager.getVimEditorGroup(editor)) {
MotionGroup.scrollCaretIntoView(editor);
}
}
}
}
}

View File

@@ -31,7 +31,7 @@ import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.ex.CommandParser;
import com.maddyhome.idea.vim.ex.ExException;
import com.maddyhome.idea.vim.helper.UiHelper;
import com.maddyhome.idea.vim.ui.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -62,6 +62,7 @@ import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ClipboardHandler;
import kotlin.Pair;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -80,9 +81,9 @@ import java.util.stream.Collectors;
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)
})
public class RegisterGroup implements PersistentStateComponent<Element> {
private static final String WRITABLE_REGISTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-*+_/\"";
private static final @NonNls String WRITABLE_REGISTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-*+_/\"";
private static final String READONLY_REGISTERS = ":.%#=/";
private static final String RECORDABLE_REGISTER = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final @NonNls 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('*', '+');
@@ -179,6 +180,11 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
int start = range.getStartOffset();
int end = range.getEndOffset();
if (isDelete && start == end) {
return true;
}
// Normalize the start and end
if (start > end) {
int t = start;

View File

@@ -49,11 +49,12 @@ import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.regexp.CharPointer;
import com.maddyhome.idea.vim.regexp.CharacterClasses;
import com.maddyhome.idea.vim.regexp.RegExp;
import com.maddyhome.idea.vim.ui.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ModalEntry;
import kotlin.jvm.functions.Function1;
import org.jdom.Element;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -209,7 +210,7 @@ public class SearchGroup implements PersistentStateComponent<Element> {
else {
// XXX: The Ex entry panel is used only for UI here, its logic might be inappropriate for this method
final ExEntryPanel exEntryPanel = ExEntryPanel.getInstanceWithoutShortcuts();
exEntryPanel.activate(editor, new EditorDataContext(editor, null), "Replace with " + match + " (y/n/a/q/l)?", "", 1);
exEntryPanel.activate(editor, new EditorDataContext(editor, null), MessageHelper.message("replace.with.0", match), "", 1);
MotionGroup.moveCaret(editor, caret, startoff);
ModalEntry.INSTANCE.activate(keyStrokeProcessor);
exEntryPanel.deactivate(true, false);
@@ -983,7 +984,7 @@ public class SearchGroup implements PersistentStateComponent<Element> {
@RWLockLabel.SelfSynchronized
public boolean searchAndReplace(@NotNull Editor editor, @NotNull Caret caret, @NotNull LineRange range,
@NotNull String excmd, String exarg) {
@NotNull @NonNls String excmd, @NonNls String exarg) {
// Explicitly exit visual mode here, so that visual mode marks don't change when we move the cursor to a match.
if (CommandStateHelper.inVisualMode(editor)) {
ModeHelper.exitVisualMode(editor);

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.RWLockLabel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -158,7 +159,7 @@ public class WindowGroup {
if (filename.length() > 0) {
virtualFile = VimPlugin.getFile().findFile(filename, project);
if (virtualFile == null) {
VimPlugin.showMessage("Could not find file: " + filename);
VimPlugin.showMessage(MessageHelper.message("could.not.find.file.0", filename));
return;
}
}

View File

@@ -46,9 +46,9 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MarkGroup
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.option.ClipboardOptionsData
import com.maddyhome.idea.vim.option.OptionsManager
import java.util.*

View File

@@ -32,7 +32,6 @@ import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.listener.VimYankListener
import org.jetbrains.annotations.Contract
import java.util.*
import kotlin.math.min
class YankGroup {

View File

@@ -27,6 +27,7 @@ import com.maddyhome.idea.vim.command.SelectionType.CHARACTER_WISE
import com.maddyhome.idea.vim.command.SelectionType.LINE_WISE
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.EditorHelper
import org.jetbrains.annotations.NonNls
import kotlin.math.max
import kotlin.math.min
@@ -68,6 +69,7 @@ sealed class VimSelection {
}
}
@NonNls
override fun toString(): String {
val startLogPosition = editor.offsetToLogicalPosition(vimStart)
val endLogPosition = editor.offsetToLogicalPosition(vimEnd)

View File

@@ -163,7 +163,7 @@ fun updateCaretState(editor: Editor) {
fun CommandState.Mode.resetShape(editor: Editor) = when (this) {
CommandState.Mode.COMMAND, CommandState.Mode.VISUAL, CommandState.Mode.REPLACE -> ChangeGroup.resetCaret(editor, false)
CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, true)
CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor)
CommandState.Mode.CMD_LINE, CommandState.Mode.OP_PENDING -> Unit
}

View File

@@ -32,6 +32,7 @@ import com.maddyhome.idea.vim.helper.StringHelper
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.noneOfEnum
import org.jetbrains.annotations.NonNls
import java.util.*
import javax.swing.KeyStroke
@@ -103,14 +104,17 @@ abstract class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
fun parseKeysSet(keyStrings: List<String>) = keyStrings.map { StringHelper.parseKeys(it) }.toSet()
@JvmStatic
fun parseKeysSet(vararg keyStrings: String): Set<List<KeyStroke>> = List(keyStrings.size) {
fun parseKeysSet(@NonNls vararg keyStrings: String): Set<List<KeyStroke>> = List(keyStrings.size) {
StringHelper.parseKeys(keyStrings[it])
}.toSet()
@NonNls private const val VimActionPrefix = "Vim"
@NonNls
fun getActionId(classFullName: String): String {
return classFullName
.takeLastWhile { it != '.' }
.let { if (it.startsWith("Vim", true)) it else "Vim$it" }
.let { if (it.startsWith(VimActionPrefix, true)) it else "$VimActionPrefix$it" }
}
}
}

View File

@@ -50,6 +50,8 @@ object CharacterHelper {
CharacterType.KATAKANA
} else if (isHalfWidthKatakanaLetter(ch)) {
CharacterType.HALF_WIDTH_KATAKANA
} else if (block == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
CharacterType.CJK_UNIFIED_IDEOGRAPHS
} else if (punctuationAsLetters || iskeyword.isKeyword(ch)) {
CharacterType.KEYWORD
} else {
@@ -89,6 +91,6 @@ object CharacterHelper {
}
enum class CharacterType {
KEYWORD, HIRAGANA, KATAKANA, HALF_WIDTH_KATAKANA, PUNCTUATION, WHITESPACE
KEYWORD, HIRAGANA, KATAKANA, HALF_WIDTH_KATAKANA, CJK_UNIFIED_IDEOGRAPHS, PUNCTUATION, WHITESPACE
}
}

View File

@@ -24,6 +24,7 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.option.OptionsManager
@get:VimNlsSafe
val usesVirtualSpace
get() = OptionsManager.virtualedit.value == "onemore"

View File

@@ -27,7 +27,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightVirtualFile;
import com.maddyhome.idea.vim.common.IndentConfig;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.ui.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,6 +43,12 @@ import static java.lang.Integer.max;
* This is a set of helper methods for working with editors. All line and column values are zero based.
*/
public class EditorHelper {
// Set a max height on block inlays to be made visible at the top/bottom of a line when scrolling up/down. This
// mitigates the visible area bouncing around too much and even pushing the cursor line off screen with large
// multiline rendered doc comments, while still providing some visibility of the block inlay (e.g. Rider's single line
// Code Vision)
private static final int BLOCK_INLAY_MAX_LINE_HEIGHT = 3;
public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) {
return editor.getScrollingModel().getVisibleAreaOnScrollingFinished();
}
@@ -201,7 +207,7 @@ public class EditorHelper {
* @param editor The editor
* @return The number of screen lines
*/
private static int getApproximateScreenHeight(final @NotNull Editor editor) {
public static int getApproximateScreenHeight(final @NotNull Editor editor) {
return getVisibleArea(editor).height / editor.getLineHeight();
}
@@ -641,7 +647,10 @@ public class EditorHelper {
* @return Returns true if the window was moved
*/
public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) {
int y = EditorUtil.getVisualLineAreaStartY(editor, normalizeVisualLine(editor, visualLine));
final int inlayHeight = EditorUtil.getInlaysHeight(editor, visualLine, true);
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * editor.getLineHeight();
int y = editor.visualLineToY(visualLine) - Math.min(inlayHeight, maxInlayHeight);
// Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this,
// but when we ask for the target location to move the caret to match, we'll get the incorrect value.
@@ -653,7 +662,7 @@ public class EditorHelper {
// Get the max line number that can sit at the top of the screen
final int editorHeight = getVisibleArea(editor).height;
final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight();
final int yLastLine = editor.visualLineToY(EditorHelper.getLineCount(editor)); // last line + 1
final int yLastLine = editor.visualLineToY(getLineCount(editor)); // last line + 1
y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight);
}
return scrollVertically(editor, y);
@@ -662,21 +671,25 @@ public class EditorHelper {
/**
* Scrolls the editor to place the given visual line in the middle of the current window.
*
* <p>Snaps the line to the nearest standard line height grid, which gives a good position for both an odd and even
* number of lines and mimics what Vim does.</p>
*
* @param editor The editor to scroll
* @param visualLine The visual line to place in the middle of the current window
*/
public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) {
int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
int lineHeight = editor.getLineHeight();
int height = getVisibleArea(editor).height;
scrollVertically(editor, y - ((height - lineHeight) / 2));
final int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
final int screenHeight = getVisibleArea(editor).height;
final int lineHeight = editor.getLineHeight();
scrollVertically(editor, y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight));
}
/**
* Scrolls the editor to place the given visual line at the bottom of the screen.
*
* When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to place a
* line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll to.
* <p>When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to
* place a line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll
* to.</p>
*
* @param editor The editor to scroll
* @param visualLine The visual line to place at the bottom of the current window
@@ -690,7 +703,12 @@ public class EditorHelper {
if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) {
exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight();
}
final int y = EditorUtil.getVisualLineAreaEndY(editor, normalizeVisualLine(editor, visualLine)) + exPanelHeight;
final int normalizedVisualLine = normalizeVisualLine(editor, visualLine);
final int lineHeight = editor.getLineHeight();
final int inlayHeight = EditorUtil.getInlaysHeight(editor, normalizedVisualLine, false);
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * lineHeight;
final int y = editor.visualLineToY(normalizedVisualLine) + lineHeight + Math.min(inlayHeight, maxInlayHeight) + exPanelHeight;
final Rectangle visibleArea = getVisibleArea(editor);
return scrollVertically(editor, max(0, y - visibleArea.height));
}
@@ -714,19 +732,19 @@ public class EditorHelper {
}
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
EditorHelper.scrollHorizontally(editor, columnLeftX);
scrollHorizontally(editor, columnLeftX);
}
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
final int screenWidth = getVisibleArea(editor).width;
// Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number
// of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth);
EditorHelper.scrollHorizontally(editor, x);
scrollHorizontally(editor, x);
}
public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
@@ -751,8 +769,8 @@ public class EditorHelper {
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
EditorHelper.scrollHorizontally(editor, targetColumnRightX - screenWidth);
final int screenWidth = getVisibleArea(editor).width;
scrollHorizontally(editor, targetColumnRightX - screenWidth);
}
/**

View File

@@ -46,11 +46,11 @@ val Editor.isIdeaVimDisabledHere: Boolean
val timeForCalculation = measureTimeMillis {
res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|| (!OptionsManager.ideavimsupport.contains("singleline")
.apply { times += System.currentTimeMillis() to "first single line check" }
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|| (!OptionsManager.ideavimsupport.contains("singleline")
.apply { times += System.currentTimeMillis() to "second single line check" }
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
)
@@ -68,7 +68,7 @@ private fun Editor.isDatabaseCell(times: MutableList<Pair<Long, String>>): Boole
}
private val Editor.disabledInDialog: Boolean
get() = (!OptionsManager.ideaenabledbufs.contains("dialog") && !OptionsManager.ideaenabledbufs.contains("dialoglegacy"))
get() = (!OptionsManager.ideavimsupport.contains("dialog") && !OptionsManager.ideavimsupport.contains("dialoglegacy"))
&& (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this))
/**

View File

@@ -19,6 +19,7 @@
package com.maddyhome.idea.vim.helper;
import com.google.common.io.CharStreams;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,15 +31,19 @@ import java.io.InputStreamReader;
* @author vlan
*/
public class MacKeyRepeat {
public static final String FMT = "defaults %s -globalDomain ApplePressAndHoldEnabled";
private static final @NotNull MacKeyRepeat INSTANCE = new MacKeyRepeat();
@VimNlsSafe public static final String FMT = "defaults %s -globalDomain ApplePressAndHoldEnabled";
@NotNull private static final MacKeyRepeat INSTANCE = new MacKeyRepeat();
@NonNls private static final String EXEC_COMMAND = "launchctl stop com.apple.SystemUIServer.agent";
@NonNls private static final String delete = "delete";
@NonNls private static final String write = "write";
@NonNls private static final String read = "read";
public static @NotNull MacKeyRepeat getInstance() {
return INSTANCE;
}
public @Nullable Boolean isEnabled() {
final String command = String.format(FMT, "read");
final String command = String.format(FMT, read);
try {
final Process process = Runtime.getRuntime().exec(command);
final String data = read(process.getInputStream()).trim();
@@ -56,17 +61,17 @@ public class MacKeyRepeat {
public void setEnabled(@Nullable Boolean value) {
final String command;
if (value == null) {
command = String.format(FMT, "delete");
command = String.format(FMT, delete);
}
else {
final String arg = value ? "0" : "1";
command = String.format(FMT, "write") + " " + arg;
command = String.format(FMT, write) + " " + arg;
}
try {
final Runtime runtime = Runtime.getRuntime();
final Process defaults = runtime.exec(command);
defaults.waitFor();
final Process restartSystemUI = runtime.exec("launchctl stop com.apple.SystemUIServer.agent");
final Process restartSystemUI = runtime.exec(EXEC_COMMAND);
restartSystemUI.waitFor();
}
catch (IOException | InterruptedException ignored) {

View File

@@ -1,61 +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 com.maddyhome.idea.vim.helper;
import com.intellij.CommonBundle;
import com.intellij.reference.SoftReference;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
import java.lang.ref.Reference;
import java.util.ResourceBundle;
public class MessageHelper {
private static @Nullable Reference<ResourceBundle> ourBundle;
@NonNls
private static final String BUNDLE = "messages";
private MessageHelper() {
}
public static @NotNull String message(@NotNull @PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
return CommonBundle.message(getBundle(), key, params);
}
/*
* This method added for jruby access
*/
public static @NotNull String message(@NotNull @PropertyKey(resourceBundle = BUNDLE)String key) {
return CommonBundle.message(getBundle(), key);
}
protected static @NotNull ResourceBundle getBundle() {
ResourceBundle bundle = null;
if (ourBundle != null) bundle = ourBundle.get();
if (bundle == null) {
bundle = ResourceBundle.getBundle(BUNDLE);
ourBundle = new SoftReference<>(bundle);
}
return bundle;
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.helper
import com.intellij.AbstractBundle
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
@NonNls
private const val BUNDLE = "messages.IdeaVimBundle"
object MessageHelper : AbstractBundle(BUNDLE) {
@JvmStatic
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = getMessage(key, *params)
@JvmStatic
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String) = getMessage(key)
}

View File

@@ -29,6 +29,7 @@ import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.option.ListOption;
import com.maddyhome.idea.vim.option.OptionsManager;
@@ -541,16 +542,19 @@ public class SearchHelper {
selectionEndWithoutNewline++;
}
if (closingTagTextRange.getStartOffset() == selectionEndWithoutNewline &&
final CommandState.Mode mode = CommandState.getInstance(editor).getMode();
if (mode == CommandState.Mode.VISUAL) {
if (closingTagTextRange.getStartOffset() == selectionEndWithoutNewline &&
openingTag.getEndOffset() == selectionStart) {
// Special case: if the inner tag is already selected we should like isOuter is active
// Note that we need to ignore newlines, because their selection is lost between multiple "it" invocations
isOuter = true;
}
else if (openingTag.getEndOffset() == closingTagTextRange.getStartOffset() &&
selectionStart == openingTag.getEndOffset()) {
// Special case: for an empty tag pair (e.g. <a></a>) the whole tag is selected if the caret is in the middle.
isOuter = true;
// Special case: if the inner tag is already selected we should like isOuter is active
// Note that we need to ignore newlines, because their selection is lost between multiple "it" invocations
isOuter = true;
}
else if (openingTag.getEndOffset() == closingTagTextRange.getStartOffset() &&
selectionStart == openingTag.getEndOffset()) {
// Special case: for an empty tag pair (e.g. <a></a>) the whole tag is selected if the caret is in the middle.
isOuter = true;
}
}
if (isOuter) {
@@ -786,7 +790,7 @@ public class SearchHelper {
if (pos == size - 1 ||
!Character.isLetter(chars.charAt(pos + 1)) ||
(Character.isUpperCase(chars.charAt(pos + 1)) &&
pos <= size - 2 &&
pos < size - 2 &&
Character.isLowerCase(chars.charAt(pos + 2)))) {
res = pos;
found++;
@@ -1375,7 +1379,7 @@ public class SearchHelper {
}
if (goForward && anyNonWhitespace(editor, end, 1)) {
while (end < max &&
while (end + 1 < max &&
CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) {
end++;
}

View File

@@ -22,6 +22,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.maddyhome.idea.vim.ex.vimscript.VimScriptGlobalEnvironment;
import org.apache.commons.codec.binary.Base64;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -59,7 +60,7 @@ public class StringHelper {
return null;
}
public static @NotNull List<KeyStroke> stringToKeys(@NotNull String s) {
public static @NotNull List<KeyStroke> stringToKeys(@NotNull @NonNls String s) {
// The following if is a dirty hack to finally support `let mapleader = "\<space>"`
if ("\\<SPACE>".equalsIgnoreCase(s)) return Collections.singletonList(getKeyStroke(' '));
final List<KeyStroke> res = new ArrayList<>();
@@ -83,7 +84,7 @@ public class StringHelper {
* @throws java.lang.IllegalArgumentException if the mapping doesn't make sense for Vim emulation
* @see :help <>
*/
public static @NotNull List<KeyStroke> parseKeys(@NotNull String... strings) {
public static @NotNull List<KeyStroke> parseKeys(@NotNull @NonNls String... strings) {
final List<KeyStroke> result = new ArrayList<>();
for (String s : strings) {
KeyParserState state = KeyParserState.INIT;
@@ -404,7 +405,7 @@ public class StringHelper {
}
}
private static Integer getVimKeyName(String lower) {
private static Integer getVimKeyName(@NonNls String lower) {
switch (lower) {
case "cr":
case "enter":
@@ -472,7 +473,7 @@ public class StringHelper {
}
}
private static String getVimKeyValue(int c) {
private static @NonNls String getVimKeyValue(int c) {
switch (c) {
case VK_ENTER:
return "cr";

View File

@@ -0,0 +1,25 @@
/*
* 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.helper
import org.jetbrains.annotations.NonNls
// [VERSION UPDATE] 203+ replace this annotation with @VimNlsSafe
@NonNls
annotation class VimNlsSafe

View File

@@ -108,14 +108,28 @@ public class KeyMapping implements Iterable<List<KeyStroke>> {
myKeys.entrySet().stream().filter(o -> o.getValue().getOwner().equals(owner)).collect(Collectors.toList());
toRemove.forEach(o -> myKeys.remove(o.getKey(), o.getValue()));
toRemove.stream().map(Map.Entry::getKey).forEach(keys -> {
List<KeyStroke> prefix = new ArrayList<>();
final int prefixLength = keys.size() - 1;
for (int i = 0; i < prefixLength; i++) {
prefix.add(keys.get(i));
myPrefixes.remove(prefix);
}
});
toRemove.stream().map(Map.Entry::getKey).forEach(this::removePrefixes);
}
public void delete(@NotNull List<KeyStroke> keys) {
MappingInfo removed = myKeys.remove(keys);
if (removed == null) return;
removePrefixes(keys);
}
public void delete() {
myKeys.clear();
myPrefixes.clear();
}
private void removePrefixes(@NotNull List<KeyStroke> keys) {
List<KeyStroke> prefix = new ArrayList<>();
final int prefixLength = keys.size() - 1;
for (int i = 0; i < prefixLength; i++) {
prefix.add(keys.get(i));
myPrefixes.remove(prefix);
}
}
public List<Pair<List<KeyStroke>, MappingInfo>> getByOwner(@NotNull MappingOwner owner) {

View File

@@ -36,11 +36,11 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.group.visual.VimSelection.Companion.create
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.StringHelper.toKeyNotation
import com.maddyhome.idea.vim.helper.VimNlsSafe
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import java.awt.event.KeyEvent
import java.util.*
import javax.swing.KeyStroke
import kotlin.math.min
@@ -49,6 +49,7 @@ import kotlin.math.min
*/
sealed class MappingInfo(val fromKeys: List<KeyStroke>, val isRecursive: Boolean, val owner: MappingOwner) : Comparable<MappingInfo> {
@VimNlsSafe
abstract fun getPresentableString(): String
abstract fun execute(editor: Editor, context: DataContext)

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.key;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
@@ -25,13 +26,13 @@ import org.jetbrains.annotations.NotNull;
*/
public enum ShortcutOwner {
UNDEFINED("undefined", "Undefined"),
IDE("ide", "IDE"),
VIM("vim", "Vim");
IDE(Constants.IDE_STRING, "IDE"),
VIM(Constants.VIM_STRING, "Vim");
private final @NotNull String name;
private final @NotNull String title;
private final @NotNull @NonNls String name;
private final @NotNull @NonNls String title;
ShortcutOwner(@NotNull String name, @NotNull String title) {
ShortcutOwner(@NotNull @NonNls String name, @NotNull @NonNls String title) {
this.name = name;
this.title = title;
}
@@ -46,12 +47,17 @@ public enum ShortcutOwner {
}
public static @NotNull ShortcutOwner fromString(@NotNull String s) {
if ("ide".equals(s)) {
if (Constants.IDE_STRING.equals(s)) {
return IDE;
}
else if ("vim".equals(s)) {
else if (Constants.VIM_STRING.equals(s)) {
return VIM;
}
return UNDEFINED;
}
private static class Constants {
@NonNls private static final String IDE_STRING = "ide";
@NonNls private static final String VIM_STRING = "vim";
}
}

View File

@@ -50,6 +50,7 @@ import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.option.IdeaRefactorMode
import org.jetbrains.annotations.NonNls
import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener
@@ -66,6 +67,7 @@ object IdeaSpecifics {
}
class VimActionListener : AnActionListener {
@NonNls
private val surrounderItems = listOf("if", "if / else", "for")
private val surrounderAction = "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null

View File

@@ -68,7 +68,7 @@ import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.remove
import com.maddyhome.idea.vim.option.OptionsManager
import com.maddyhome.idea.vim.option.StrictMode
import com.maddyhome.idea.vim.ui.ExEntryPanel
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
import com.maddyhome.idea.vim.ui.ShowCmdOptionChangeListener
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
@@ -106,6 +106,7 @@ object VimListenerManager {
OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.scrolloff.addOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener)
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
@@ -116,6 +117,7 @@ object VimListenerManager {
OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.scrolloff.removeOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener)
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
@@ -251,11 +253,11 @@ object VimListenerManager {
if (onLineEnd(caret)) {
// UX protection for case when user performs a small dragging while putting caret on line end
caret.removeSelection()
ChangeGroup.resetCaret(e.editor, true)
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor)
}
}
if (mouseDragging && e.editor.caretModel.primaryCaret.hasSelection()) {
ChangeGroup.resetCaret(e.editor, true)
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor)
if (!cutOffFixed && ComponentMouseListener.cutOffEnd) {
cutOffFixed = true

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.option;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -26,7 +27,7 @@ import java.util.List;
public class BoundListOption extends ListOption {
BoundListOption(String name, String abbrev, String[] dflt, String[] values) {
BoundListOption(@NonNls String name, @NonNls String abbrev, @NonNls String[] dflt, @NonNls String[] values) {
super(name, abbrev, dflt, null);
this.values = new ArrayList<>(Arrays.asList(values));

View File

@@ -18,10 +18,11 @@
package com.maddyhome.idea.vim.option;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class BoundStringOption extends StringOption {
BoundStringOption(String name, String abbrev, String dflt, String[] values) {
BoundStringOption(@NonNls String name, @NonNls String abbrev, @NonNls String dflt, String[] values) {
super(name, abbrev, dflt);
this.values = values;

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