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

Compare commits

...

65 Commits

Author SHA1 Message Date
Alex Plate
4926d2554e Revert "VIM-1475: Respect the "use block caret" when in insert mode"
Reverting this commit due to VIM-2182

This reverts commit 62c828d7
2020-12-02 09:45:08 +03:00
Alex Plate
eae135acba Fix detekt issues 2020-12-01 12:19:08 +03:00
Alex Plate
8ce3801b87 [VIM-1913] Improve interaction with AppCode templates 2020-12-01 11:55:47 +03:00
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
147 changed files with 2667 additions and 1082 deletions

2
.gitignore vendored
View File

@@ -6,6 +6,8 @@
!/.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

@@ -1,9 +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>

View File

@@ -8,6 +8,30 @@
<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>
@@ -19,5 +43,6 @@
</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

@@ -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,7 +24,23 @@ 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

View File

@@ -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,10 +183,8 @@ Emulated Vim Plugins
See [doc/emulated-plugins.md](doc/emulated-plugins.md)
Changes to the IDE
------------------
### Executing IDE Actions
Executing IDE Actions
---------------------
IdeaVim adds various commands for listing and executing arbitrary IDE actions as
Ex commands or via `:map` command mappings:
@@ -205,7 +203,7 @@ Ex commands or via `:map` command mappings:
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>
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
<img src="resources/readme/track_action_id.gif" alt="track action ids"/>
</details>
@@ -222,24 +220,6 @@ Examples:
: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.2'
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

@@ -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

@@ -1,47 +1,64 @@
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
<name>IdeaVim</name>
<id>IdeaVIM</id>
<change-notes>
&lt;h3&gt;Features:&lt;/h3&gt;
&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;Ability to map IDE actions via the &lt;code&gt;&amp;lt;Action&amp;gt;&lt;/code&gt; keyword. E.g.
&lt;code&gt;map &amp;lt;C-K&amp;gt; &amp;lt;Action&amp;gt;(CommentByLineComment)&lt;/code&gt;.
Check out &lt;code&gt;README.md&lt;/code&gt; for the details.&lt;/li&gt;&lt;li&gt;&lt;code&gt;IdeaVim: track action
Ids&lt;/code&gt; command to find action ids for the &lt;code&gt;:action&lt;/code&gt; command.
Enable this option in &amp;quot;Search everywhere&amp;quot; (double shift).&lt;/li&gt;&lt;li&gt;Ability to enable
extensions using &lt;code&gt;vim-plug&lt;/code&gt; or &lt;code&gt;vundle&lt;/code&gt; syntax.&lt;br /&gt;
E.g. to enable commentary extension you can use one of the following commands:&lt;pre&gt;&lt;code
class="language-vim"&gt;set commentary
Plug 'tpope/vim-commentary'
Plug 'https://github.com/tpope/vim-commentary'
Plugin 'tpope/vim-commentary'
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This approach is especially handy if you have &lt;code&gt;.vimrc&lt;/code&gt; with
plugins registered via &lt;code&gt;vim-plug&lt;/code&gt; or &lt;code&gt;vundle&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
<change-notes><![CDATA[
<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>
&lt;br/&gt;
&lt;h3&gt;Changes:&lt;/h3&gt;
&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;Fix &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; for dialogs. Now &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;
will exit insert / visual mode and close the dialog from normal mode.&lt;/li&gt;&lt;li&gt;Add option to disable
IdeaVim in dialogs / single line editors. &lt;a href="https://youtrack.jetbrains.com/issue/VIM-765"&gt;VIM-765&lt;/a&gt;&lt;br
/&gt;
Use &lt;code&gt;set ideavimsupport=&lt;/code&gt; to disable IdeaVim in dialog editors. &lt;/li&gt;&lt;li&gt;Reposition
cursor when &lt;code&gt;scrolloff&lt;/code&gt; changes&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;
&lt;h3&gt;Fixes:&lt;/h3&gt;
&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2150"&gt;VIM-2150&lt;/a&gt; &lt;code&gt;Shift-D&lt;/code&gt;
should not delete an empty line&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2157"&gt;VIM-2157&lt;/a&gt;
Fix tab with an active template&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2156"&gt;VIM-2156&lt;/a&gt;
Correct up/down motions with inlays&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2144"&gt;VIM-2144&lt;/a&gt;
Correct text position after block insert with inlays&lt;/li&gt;&lt;li&gt;&lt;a
href="https://youtrack.jetbrains.com/issue/VIM-2158"&gt;VIM-2158&lt;/a&gt; Fix scrolling when &lt;code&gt;scrolloff&lt;/code&gt;
is over half screen height, but less than full height&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;
&lt;p&gt;See also the complete &lt;a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md"&gt;changelog&lt;/a&gt;.&lt;/p&gt;
<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 plugin for IntelliJ Platform-based IDEs.</p>
@@ -60,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>
@@ -111,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>
@@ -137,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;
@@ -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

@@ -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

@@ -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

@@ -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
@@ -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;
@@ -36,6 +37,7 @@ public interface VimExtension {
*/
@Deprecated
@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;

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

@@ -41,10 +41,11 @@ import com.maddyhome.idea.vim.group.visual.VisualGroupKt;
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.listener.IdeaSpecifics;
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;
@@ -318,6 +319,8 @@ public class MotionGroup {
else {
ModeHelper.exitVisualMode(editor);
}
IdeaSpecifics.AppCodeTemplates.onMovement(editor, caret, oldOffset < offset);
}
private @Nullable Editor selectEditor(@NotNull Editor editor, @NotNull Mark mark) {

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

@@ -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;

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) {

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

@@ -32,12 +32,14 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.actionSystem.EditorActionManager
import com.intellij.openapi.editor.event.CaretEvent
import com.intellij.openapi.editor.event.CaretListener
import com.intellij.openapi.project.DumbAwareToggleAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.util.PlatformUtils
import com.maddyhome.idea.vim.EventFacade
import com.maddyhome.idea.vim.KeyHandler
@@ -47,9 +49,12 @@ import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl
import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.fileSize
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 org.jetbrains.annotations.NotNull
import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener
@@ -66,6 +71,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
@@ -189,6 +195,87 @@ object IdeaSpecifics {
.javaClass.name.startsWith("org.acejump.")
}
//endregion
//region AppCode templates
/**
* A collection of hacks to improve the interaction with fancy AppCode templates
*/
object AppCodeTemplates {
private val facedAppCodeTemplate = Key.create<IntRange>("FacedAppCodeTemplate")
private const val TEMPLATE_START = "<#T##"
private const val TEMPLATE_END = "#>"
@JvmStatic
fun onMovement(
editor: @NotNull Editor,
caret: @NotNull Caret,
toRight: Boolean
) {
if (!PlatformUtils.isAppCode()) return
val offset = caret.offset
val offsetRightEnd = offset + TEMPLATE_START.length
val offsetLeftEnd = offset - 1
val templateRange = caret.getUserData(facedAppCodeTemplate)
if (templateRange == null) {
if (offsetRightEnd < editor.fileSize
&& editor.document.charsSequence.subSequence(offset, offsetRightEnd).toString() == TEMPLATE_START) {
caret.shake()
val templateEnd = editor.findTemplateEnd(offset) ?: return
caret.putUserData(facedAppCodeTemplate, offset..templateEnd)
}
if (offsetLeftEnd >= 0
&& editor.document.charsSequence.subSequence(offsetLeftEnd, offset + 1).toString() == TEMPLATE_END) {
caret.shake()
val templateStart = editor.findTemplateStart(offsetLeftEnd) ?: return
caret.putUserData(facedAppCodeTemplate, templateStart..offset)
}
} else {
if (offset in templateRange) {
if (toRight) {
caret.moveToOffset(templateRange.last + 1)
} else {
caret.moveToOffset(templateRange.first)
}
}
caret.putUserData(facedAppCodeTemplate, null)
caret.shake()
}
}
private fun Caret.shake() {
moveCaretRelatively(1, 0, false, false)
moveCaretRelatively(-1, 0, false, false)
}
private fun Editor.findTemplateEnd(start: Int): Int? {
val charSequence = this.document.charsSequence
val length = charSequence.length
for (i in start until length - 1) {
if (charSequence[i] == TEMPLATE_END[0] && charSequence[i+1] == TEMPLATE_END[1]) {
return i + 1
}
}
return null
}
private fun Editor.findTemplateStart(start: Int): Int? {
val charSequence = this.document.charsSequence
val templateLastIndex = TEMPLATE_START.length
for (i in start downTo templateLastIndex) {
if (charSequence.subSequence(i - templateLastIndex, i + 1).toString() == TEMPLATE_START) {
return i - templateLastIndex
}
}
return null
}
}
//endregion
}
//region Find action ID

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

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;

View File

@@ -19,6 +19,7 @@
package com.maddyhome.idea.vim.option;
import org.apache.commons.lang.math.NumberUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,12 +31,13 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
public final class KeywordOption extends ListOption {
@NonNls private static final String allLettersRegex = "\\p{L}";
private final @NotNull Pattern validationPattern;
// KeywordSpecs are the option values in reverse order
private @NotNull List<KeywordSpec> keywordSpecs = new ArrayList<>();
public KeywordOption(@NotNull String name, @NotNull String abbrev, @NotNull String[] defaultValue) {
public KeywordOption(@NotNull @NonNls String name, @NotNull @NonNls String abbrev, @NotNull String[] defaultValue) {
super(name, abbrev, defaultValue,
"(\\^?(([^0-9^]|[0-9]{1,3})-([^0-9]|[0-9]{1,3})|([^0-9^]|[0-9]{1,3})),)*\\^?(([^0-9^]|[0-9]{1,3})-([^0-9]|[0-9]{1,3})|([^0-9]|[0-9]{1,3})),?$");
validationPattern = Pattern.compile(pattern);
@@ -209,7 +211,7 @@ public final class KeywordOption extends ListOption {
public List<String> toRegex() {
return keywordSpecs.stream().map(spec -> {
if (spec.isAllLetters) {
return "\\p{L}";
return allLettersRegex;
} else if (spec.isRange) {
return "[" + (char)spec.rangeLow.intValue() + "-" + (char)spec.rangeHigh.intValue() + "]";
} else {

View File

@@ -19,6 +19,8 @@
package com.maddyhome.idea.vim.option;
import com.intellij.util.ArrayUtil;
import com.maddyhome.idea.vim.helper.VimNlsSafe;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -69,7 +71,7 @@ public class ListOption extends TextOption {
* @param val A comma separated list of values to look for
* @return True if all the supplied values are set in this option, false if not
*/
public boolean contains(String val) {
public boolean contains(@NonNls String val) {
final List<String> vals = parseVals(val);
return vals != null && value.containsAll(vals);
}
@@ -178,7 +180,7 @@ public class ListOption extends TextOption {
* @param dflt The option's default values
* @param pattern A regular expression that is used to validate new values. null if no check needed
*/
ListOption(String name, String abbrev, String[] dflt, String pattern) {
ListOption(@VimNlsSafe String name, @VimNlsSafe String abbrev, @VimNlsSafe String[] dflt, @VimNlsSafe String pattern) {
super(name, abbrev);
this.dflt = new ArrayList<>(Arrays.asList(dflt));

View File

@@ -18,6 +18,8 @@
package com.maddyhome.idea.vim.option;
import com.maddyhome.idea.vim.helper.VimNlsSafe;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,7 +34,7 @@ public class NumberOption extends TextOption {
* @param abbrev The short name
* @param dflt The default value
*/
NumberOption(String name, String abbrev, int dflt) {
NumberOption(@NonNls String name, @NonNls String abbrev, int dflt) {
this(name, abbrev, dflt, 0, Integer.MAX_VALUE);
}
@@ -45,7 +47,7 @@ public class NumberOption extends TextOption {
* @param min The option's minimum value
* @param max The option's maximum value
*/
NumberOption(String name, String abbrev, int dflt, int min, int max) {
NumberOption(@VimNlsSafe String name, @VimNlsSafe String abbrev, int dflt, int min, int max) {
super(name, abbrev);
this.dflt = dflt;
this.value = dflt;

View File

@@ -36,8 +36,8 @@ import com.maddyhome.idea.vim.helper.isBlockCaret
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Contract
import org.jetbrains.annotations.NonNls
import java.util.*
import kotlin.math.ceil
import kotlin.math.min
@@ -366,6 +366,7 @@ object OptionsManager {
}
}
@NonNls
object KeyModelOptionData {
const val name = "keymodel"
private const val abbr = "km"
@@ -382,6 +383,7 @@ object KeyModelOptionData {
val option = BoundListOption(name, abbr, default, options)
}
@NonNls
object SelectModeOptionData {
const val name = "selectmode"
private const val abbr = "slm"
@@ -402,6 +404,7 @@ object SelectModeOptionData {
}
}
@NonNls
object ClipboardOptionsData {
const val name = "clipboard"
const val abbr = "cb"
@@ -431,6 +434,7 @@ object ClipboardOptionsData {
}
}
@NonNls
object IdeaJoinOptionsData {
const val name = "ideajoin"
private const val defaultValue = false
@@ -438,6 +442,7 @@ object IdeaJoinOptionsData {
val option = ToggleOption(name, name, defaultValue)
}
@NonNls
object IdeaMarkskOptionsData {
const val name = "ideamarks"
private const val defaultValue = true
@@ -445,16 +450,19 @@ object IdeaMarkskOptionsData {
val option = ToggleOption(name, name, defaultValue)
}
@NonNls
object SmartCaseOptionsData {
const val name = "smartcase"
const val abbr = "scs"
}
@NonNls
object IgnoreCaseOptionsData {
const val name = "ignorecase"
const val abbr = "ic"
}
@NonNls
object IdeaRefactorMode {
const val name = "idearefactormode"
@@ -513,6 +521,7 @@ object IdeaRefactorMode {
}
}
@NonNls
object LookupKeysData {
const val name = "lookupkeys"
val defaultValues = arrayOf(
@@ -527,6 +536,7 @@ object LookupKeysData {
)
}
@NonNls
object IdeaStatusIcon {
const val enabled = "enabled"
const val gray = "gray"
@@ -536,10 +546,12 @@ object IdeaStatusIcon {
val allValues = arrayOf(enabled, gray, disabled)
}
@NonNls
object ScrollOffData {
const val name = "scrolloff"
}
@NonNls
object ScrollJumpData {
const val name = "scrolljump"
}
@@ -548,11 +560,13 @@ object StrictMode {
val on: Boolean
get() = OptionsManager.ideastrictmode.isSet
fun fail(message: String) {
@NonNls
fun fail(message: @NonNls String) {
if (on) error(message)
}
}
@NonNls
object VirtualEditData {
const val name = "virtualedit"
@@ -560,6 +574,7 @@ object VirtualEditData {
val allValues = arrayOf("block", "insert", "all", onemore)
}
@NonNls
object IdeaWriteData {
const val all = "all"

View File

@@ -18,12 +18,17 @@
package com.maddyhome.idea.vim.option;
import com.maddyhome.idea.vim.helper.VimNlsSafe;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* Represents a boolean option
*/
public class ToggleOption extends Option<Boolean> {
private static final @NonNls String NO_PREFIX = "no";
/**
* Creates the option
*
@@ -31,7 +36,7 @@ public class ToggleOption extends Option<Boolean> {
* @param abbrev The short name
* @param dflt The default value
*/
public ToggleOption(String name, String abbrev, boolean dflt) {
public ToggleOption(@VimNlsSafe String name, @VimNlsSafe String abbrev, boolean dflt) {
super(name, abbrev);
this.dflt = dflt;
@@ -89,7 +94,7 @@ public class ToggleOption extends Option<Boolean> {
public @NotNull String toString() {
StringBuilder res = new StringBuilder();
if (!value) {
res.append("no");
res.append(NO_PREFIX);
}
else {
res.append(" ");

View File

@@ -612,20 +612,20 @@
*
* |c_CTRL-A| TO BE IMPLEMENTED
* |c_CTRL-B| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
* |c_CTRL-C| {@link com.maddyhome.idea.vim.ui.ExEditorKit.CancelEntryAction}
* |c_CTRL-C| {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
* |c_CTRL-D| TO BE IMPLEMENTED
* |c_CTRL-E| {@link javax.swing.text.DefaultEditorKit#endLineAction}
* |c_CTRL-G| TO BE IMPLEMENTED
* |c_CTRL-H| {@link com.maddyhome.idea.vim.ui.ExEditorKit.DeletePreviousCharAction}
* |c_CTRL-H| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
* |c_CTRL-I| TO BE IMPLEMENTED
* |c_CTRL-J| {@link com.maddyhome.idea.vim.ui.ExEditorKit.CompleteEntryAction}
* |c_CTRL-K| {@link com.maddyhome.idea.vim.ui.ExEditorKit.StartDigraphAction}
* |c_CTRL-J| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_CTRL-K| Handled by KeyHandler
* |c_CTRL-L| TO BE IMPLEMENTED
* |c_CTRL-M| {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
* |c_CTRL-N| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryDownAction}
* |c_CTRL-P| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryUpAction}
* |c_CTRL-Q| {@link com.maddyhome.idea.vim.ui.ExEditorKit.StartDigraphAction}
* |c_CTRL-R| {@link com.maddyhome.idea.vim.ui.ExEditorKit.InsertRegisterAction}
* |c_CTRL-N| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_CTRL-P| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_CTRL-Q| Handled by KeyHandler
* |c_CTRL-R| {@link com.maddyhome.idea.vim.ui.ex.InsertRegisterAction}
* |c_CTRL-R_CTRL-A| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-F| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-L| TO BE IMPLEMENTED
@@ -634,9 +634,9 @@
* |c_CTRL-R_CTRL-R| TO BE IMPLEMENTED
* |c_CTRL-R_CTRL-W| TO BE IMPLEMENTED
* |c_CTRL-T| TO BE IMPLEMENTED
* |c_CTRL-U| {@link com.maddyhome.idea.vim.ui.ExEditorKit.DeleteToCursorAction}
* |c_CTRL-V| {@link com.maddyhome.idea.vim.ui.ExEditorKit.StartDigraphAction}
* |c_CTRL-W| {@link com.maddyhome.idea.vim.ui.ExEditorKit.DeletePreviousWordAction}
* |c_CTRL-U| {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
* |c_CTRL-V| Handled by KeyHandler
* |c_CTRL-W| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
* |c_CTRL-Y| TO BE IMPLEMENTED
* |c_CTRL-\_e| TO BE IMPLEMENTED
* |c_CTRL-\_CTRL-G| TO BE IMPLEMENTED
@@ -644,32 +644,32 @@
* |c_CTRL-_| not applicable
* |c_CTRL-^| not applicable
* |c_CTRL-]| TO BE IMPLEMENTED
* |c_CTRL-[| {@link com.maddyhome.idea.vim.ui.ExEditorKit.EscapeCharAction}
* |c_<BS>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.DeletePreviousCharAction}
* |c_<CR>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.CompleteEntryAction}
* |c_CTRL-[| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
* |c_<BS>| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
* |c_<CR>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_<C-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
* |c_<C-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
* |c_<Del>| {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
* |c_<Down>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryDownFilterAction}
* |c_<Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
* |c_<End>| {@link javax.swing.text.DefaultEditorKit#endLineAction}
* |c_<Esc>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.EscapeCharAction}
* |c_<Esc>| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
* |c_<Home>| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
* |c_<Insert>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.ToggleInsertReplaceAction}
* |c_<Insert>| {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
* |c_<Left>| {@link javax.swing.text.DefaultEditorKit#backwardAction}
* |c_<LeftMouse>| not applicable
* |c_<MiddleMouse>| TO BE IMPLEMENTED
* |c_<NL>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.CompleteEntryAction}
* |c_<PageUp>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryUpAction}
* |c_<PageDown>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryDownAction}
* |c_<NL>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
* |c_<PageUp>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_<PageDown>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_<Right>| {@link javax.swing.text.DefaultEditorKit#forwardAction}
* |c_<S-Down>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryDownAction}
* |c_<S-Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
* |c_<S-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
* |c_<S-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
* |c_<S-Tab>| TO BE IMPLEMENTED
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryUpAction}
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_<Tab>| TO BE IMPLEMENTED
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ExEditorKit.HistoryUpFilterAction}
* |c_digraph| {char1} <BS> {char2} {@link com.maddyhome.idea.vim.ui.ExEditorKit.StartDigraphAction}
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
* |c_digraph| {char1} <BS> {char2} {@link com.maddyhome.idea.vim.ui.ex.StartDigraphAction}
* |c_wildchar| TO BE IMPLEMENTED
* |'cedit'| TO BE IMPLEMENTED
*
@@ -679,7 +679,7 @@
* tag handler
* -------------------------------------------------------------------------------------------------------------------
*
* |:map| {@link com.maddyhome.idea.vim.ex.handler.MapHandler}
* |:map| {@link com.maddyhome.idea.vim.ex.handler.mapping.MapHandler}
* |:nmap| ...
* |:vmap| ...
* |:omap| ...

View File

@@ -18,11 +18,13 @@
package com.maddyhome.idea.vim.regexp;
import org.jetbrains.annotations.NonNls;
public final class CharacterClasses {
private CharacterClasses() {
}
public static final String[] CLASS_NAMES = new String[]{
public static final String @NonNls [] CLASS_NAMES = new String[]{
"alnum:]",
"alpha:]",
"blank:]",

View File

@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.Msg;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -4273,8 +4274,8 @@ public class RegExp {
/*
* regprop - printable representation of opcode
*/
private @NotNull String regprop(@NotNull CharPointer op) {
String p;
private @NotNull @NonNls String regprop(@NotNull CharPointer op) {
@NonNls String p;
StringBuilder buf = new StringBuilder();
buf.append(':');

View File

@@ -1,565 +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.ui;
import com.intellij.openapi.diagnostic.Logger;
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.DigraphResult;
import com.maddyhome.idea.vim.helper.DigraphSequence;
import com.maddyhome.idea.vim.helper.SearchHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class ExEditorKit extends DefaultEditorKit {
public static ExEditorKit getInstance() {
if (instance == null) {
instance = new ExEditorKit();
}
return instance;
}
/**
* Gets the MIME type of the data that this
* kit represents support for.
*
* @return the type
*/
@Override
public @NotNull String getContentType() {
return "text/ideavim";
}
/**
* Fetches the set of commands that can be used
* on a text component that is using a model and
* view produced by this kit.
*
* @return the set of actions
*/
@Override
public Action[] getActions() {
Action[] res = TextAction.augmentList(super.getActions(), this.exActions);
if (logger.isDebugEnabled()) logger.debug("res.length=" + res.length);
return res;
}
/**
* Creates an uninitialized text storage model
* that is appropriate for this type of editor.
*
* @return the model
*/
@Override
public @NotNull Document createDefaultDocument() {
return new ExDocument();
}
private static @Nullable KeyStroke convert(@NotNull ActionEvent event) {
String cmd = event.getActionCommand();
int mods = event.getModifiers();
if (cmd != null && cmd.length() > 0) {
char ch = cmd.charAt(0);
if (ch < ' ') {
if ((mods & ActionEvent.CTRL_MASK) != 0) {
return KeyStroke.getKeyStroke(KeyEvent.VK_A + ch - 1, mods);
}
}
else {
return KeyStroke.getKeyStroke(Character.valueOf(ch), mods);
}
}
return null;
}
static final String CancelEntry = "cancel-entry";
static final String CompleteEntry = "complete-entry";
static final String EscapeChar = "escape";
static final String DeleteToCursor = "delete-to-cursor";
static final String ToggleInsertReplace = "toggle-insert";
static final String InsertRegister = "insert-register";
static final String HistoryUp = "history-up";
static final String HistoryDown = "history-down";
static final String HistoryUpFilter = "history-up-filter";
static final String HistoryDownFilter = "history-down-filter";
static final String StartDigraph = "start-digraph";
static final String StartLiteral = "start-literal";
private final @NotNull Action[] exActions = new Action[]{
new CancelEntryAction(),
new CompleteEntryAction(),
new EscapeCharAction(),
new DeleteNextCharAction(),
new DeletePreviousCharAction(),
new DeletePreviousWordAction(),
new DeleteToCursorAction(),
new HistoryUpAction(),
new HistoryDownAction(),
new HistoryUpFilterAction(),
new HistoryDownFilterAction(),
new ToggleInsertReplaceAction(),
new StartDigraphAction(),
new StartLiteralAction(),
new InsertRegisterAction(),
};
public static class DefaultExKeyHandler extends DefaultKeyTypedAction {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
final Action currentAction = target.getCurrentAction();
if (currentAction != null) {
currentAction.actionPerformed(e);
}
else {
KeyStroke key = convert(e);
if (key != null) {
final char c = key.getKeyChar();
if (c > 0) {
ActionEvent event = new ActionEvent(e.getSource(), e.getID(), String.valueOf(c), e.getWhen(), e.getModifiers());
super.actionPerformed(event);
target.saveLastEntry();
}
}
else {
super.actionPerformed(e);
target.saveLastEntry();
}
}
}
}
public interface MultiStepAction extends Action {
void reset();
}
public static class HistoryUpAction extends TextAction {
HistoryUpAction() {
super(HistoryUp);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
ExTextField target = (ExTextField)getTextComponent(actionEvent);
target.selectHistory(true, false);
}
}
public static class HistoryDownAction extends TextAction {
HistoryDownAction() {
super(HistoryDown);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
ExTextField target = (ExTextField)getTextComponent(actionEvent);
target.selectHistory(false, false);
}
}
public static class HistoryUpFilterAction extends TextAction {
HistoryUpFilterAction() {
super(HistoryUpFilter);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
ExTextField target = (ExTextField)getTextComponent(actionEvent);
target.selectHistory(true, true);
}
}
public static class HistoryDownFilterAction extends TextAction {
HistoryDownFilterAction() {
super(HistoryDownFilter);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
ExTextField target = (ExTextField)getTextComponent(actionEvent);
target.selectHistory(false, true);
}
}
public static class InsertRegisterAction extends TextAction implements MultiStepAction {
private enum State {
SKIP_CTRL_R,
WAIT_REGISTER,
}
private @NotNull State state = State.SKIP_CTRL_R;
InsertRegisterAction() {
super(InsertRegister);
}
@Override
public void actionPerformed(@NotNull ActionEvent e) {
final ExTextField target = (ExTextField)getTextComponent(e);
final KeyStroke key = convert(e);
if (key != null) {
switch (state) {
case SKIP_CTRL_R:
state = State.WAIT_REGISTER;
target.setCurrentAction(this, '\"');
break;
case WAIT_REGISTER:
state = State.SKIP_CTRL_R;
target.clearCurrentAction();
final char c = key.getKeyChar();
if (c != KeyEvent.CHAR_UNDEFINED) {
final Register register = VimPlugin.getRegister().getRegister(c);
if (register != null) {
final String oldText = target.getActualText();
final String text = register.getText();
if (text != null) {
final int offset = target.getCaretPosition();
target.setText(oldText.substring(0, offset) + text + oldText.substring(offset));
target.setCaretPosition(offset + text.length());
}
}
} else if ((key.getModifiers() & KeyEvent.CTRL_DOWN_MASK) != 0 && key.getKeyCode() == KeyEvent.VK_C) {
// Eat any unused keys, unless it's <C-C>, in which case forward on and cancel entry
target.handleKey(key);
}
}
}
}
@Override
public void reset() {
state = State.SKIP_CTRL_R;
}
}
public static class CompleteEntryAction extends TextAction {
CompleteEntryAction() {
super(CompleteEntry);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
logger.debug("complete entry");
KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
// We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
// We do this for a couple of reasons:
// * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
// write action
// * The key handler routines get the chance to clean up and reset state
final ExTextField entry = ExEntryPanel.getInstance().getEntry();
KeyHandler.getInstance().handleKey(entry.getEditor(), stroke, entry.getContext());
}
}
public static class CancelEntryAction extends TextAction {
CancelEntryAction() {
super(CancelEntry);
}
@Override
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.cancel();
}
}
public static class EscapeCharAction extends TextAction {
EscapeCharAction() {
super(EscapeChar);
}
@Override
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.escape();
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private abstract static class DeleteCharAction extends TextAction {
DeleteCharAction(String name) {
super(name);
}
boolean deleteSelection(Document doc, int dot, int mark) throws BadLocationException {
if (dot != mark) {
doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
return true;
}
return false;
}
boolean deleteNextChar(Document doc, int dot) throws BadLocationException {
if (dot < doc.getLength()) {
int delChars = 1;
if (dot < doc.getLength() - 1) {
final String dotChars = doc.getText(dot, 2);
final char c0 = dotChars.charAt(0);
final char c1 = dotChars.charAt(1);
if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
c1 >= '\uDC00' && c1 <= '\uDFFF') {
delChars = 2;
}
}
doc.remove(dot, delChars);
return true;
}
return false;
}
boolean deletePrevChar(Document doc, int dot) throws BadLocationException {
if (dot > 0) {
int delChars = 1;
if (dot > 1) {
final String dotChars = doc.getText(dot - 2, 2);
final char c0 = dotChars.charAt(0);
final char c1 = dotChars.charAt(1);
if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
c1 >= '\uDC00' && c1 <= '\uDFFF') {
delChars = 2;
}
}
doc.remove(dot - delChars, delChars);
return true;
}
return false;
}
}
public static class DeleteNextCharAction extends DeleteCharAction {
DeleteNextCharAction() {
super(deleteNextCharAction);
}
@Override
public void actionPerformed(ActionEvent e) {
final ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
try {
final Document doc = target.getDocument();
final Caret caret = target.getCaret();
final int dot = caret.getDot();
final int mark = caret.getMark();
if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
target.cancel();
}
} catch (BadLocationException ex) {
// ignore
}
}
}
public static class DeletePreviousCharAction extends DeleteCharAction {
DeletePreviousCharAction() {
super(deletePrevCharAction);
}
@Override
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
try {
Document doc = target.getDocument();
Caret caret = target.getCaret();
int dot = caret.getDot();
int mark = caret.getMark();
if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
if (dot == 0 && doc.getLength() == 0) {
target.cancel();
}
}
}
catch (BadLocationException bl) {
// ignore
}
}
}
public static class DeletePreviousWordAction extends TextAction {
DeletePreviousWordAction() {
super(deletePrevWordAction);
}
/**
* Invoked when an action occurs.
*/
@Override
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
Document doc = target.getDocument();
Caret caret = target.getCaret();
int offset = SearchHelper.findNextWord(target.getActualText(), caret.getDot(), target.getActualText().length(),
-1, false, false);
if (logger.isDebugEnabled()) logger.debug("offset=" + offset);
try {
int pos = caret.getDot();
doc.remove(offset, pos - offset);
}
catch (BadLocationException ex) {
// ignore
}
}
}
public static class DeleteToCursorAction extends TextAction {
DeleteToCursorAction() {
super(DeleteToCursor);
}
/**
* Invoked when an action occurs.
*/
@Override
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
Document doc = target.getDocument();
Caret caret = target.getCaret();
try {
doc.remove(0, caret.getDot());
}
catch (BadLocationException ex) {
// ignore
}
}
}
public static class ToggleInsertReplaceAction extends TextAction {
ToggleInsertReplaceAction() {
super(ToggleInsertReplace);
logger.debug("ToggleInsertReplaceAction()");
}
/**
* Invoked when an action occurs.
*/
@Override
public void actionPerformed(ActionEvent e) {
logger.debug("actionPerformed");
ExTextField target = (ExTextField)getTextComponent(e);
target.toggleInsertReplace();
}
}
private abstract static class StartDigraphLiteralActionBase extends TextAction implements MultiStepAction {
private @Nullable DigraphSequence digraphSequence;
public StartDigraphLiteralActionBase(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
final ExTextField target = (ExTextField)getTextComponent(e);
final KeyStroke key = convert(e);
if (key != null && digraphSequence != null) {
DigraphResult res = digraphSequence.processKey(key, target.getEditor());
switch (res.getResult()) {
case DigraphResult.RES_HANDLED:
target.setCurrentActionPromptCharacter(res.getPromptCharacter());
break;
case DigraphResult.RES_BAD:
target.clearCurrentAction();
// Eat the character, unless it's <C-C>, in which case, forward on and cancel entry. Note that at some point
// we should support input of control characters
if ((key.getModifiers() & KeyEvent.CTRL_DOWN_MASK) != 0 && key.getKeyCode() == KeyEvent.VK_C) {
target.handleKey(key);
}
break;
case DigraphResult.RES_DONE:
final KeyStroke digraph = res.getStroke();
digraphSequence = null;
target.clearCurrentAction();
if (digraph != null) {
target.handleKey(digraph);
}
break;
}
}
else if (key != null) {
digraphSequence = new DigraphSequence();
DigraphResult res = start(digraphSequence);
target.setCurrentAction(this, res.getPromptCharacter());
}
}
protected abstract DigraphResult start(@NotNull DigraphSequence digraphSequence);
@Override
public void reset() {
digraphSequence = null;
}
}
public static class StartDigraphAction extends StartDigraphLiteralActionBase {
StartDigraphAction() {
super(StartDigraph);
}
@Override
protected DigraphResult start(@NotNull DigraphSequence digraphSequence) {
return digraphSequence.startDigraphSequence();
}
}
public static class StartLiteralAction extends StartDigraphLiteralActionBase {
StartLiteralAction() {
super(StartLiteral);
}
@Override
protected DigraphResult start(@NotNull DigraphSequence digraphSequence) {
return digraphSequence.startLiteralSequence();
}
}
private static ExEditorKit instance;
private static final Logger logger = Logger.getInstance(ExEditorKit.class.getName());
}

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