mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
65 Commits
0.61
...
0.61.2-EAP
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4926d2554e | ||
![]() |
eae135acba | ||
![]() |
8ce3801b87 | ||
![]() |
0c7c11f817 | ||
![]() |
b3a39c05d7 | ||
![]() |
7370012667 | ||
![]() |
412838fd4b | ||
![]() |
273a614389 | ||
![]() |
3944c80ae2 | ||
![]() |
726ab3f91b | ||
![]() |
ab307dd78f | ||
![]() |
e3079912ae | ||
![]() |
52da3ed0e4 | ||
![]() |
cda85169ea | ||
![]() |
978d1df598 | ||
![]() |
f90d22cc20 | ||
![]() |
bae69d92ae | ||
![]() |
b910239825 | ||
![]() |
6421a5969a | ||
![]() |
5c9faba7f4 | ||
![]() |
c1af738cc5 | ||
![]() |
23a80a9260 | ||
![]() |
d9d92f7eee | ||
![]() |
c8be6c203e | ||
![]() |
612c599d9b | ||
![]() |
1292c7d1ae | ||
![]() |
69f07967b5 | ||
![]() |
aedd427c07 | ||
![]() |
9b6c3dc511 | ||
![]() |
b4fa7f4317 | ||
![]() |
f053d305d5 | ||
![]() |
1d95b7ddf7 | ||
![]() |
01a6964d68 | ||
![]() |
d661f96a9b | ||
![]() |
c79fae8ab3 | ||
![]() |
121f130893 | ||
![]() |
da9a0a414a | ||
![]() |
e0732e041b | ||
![]() |
6fc5b3189a | ||
![]() |
2a0c9cb749 | ||
![]() |
7ad131b448 | ||
![]() |
3e7186bd60 | ||
![]() |
132f8cce53 | ||
![]() |
5c07f42afb | ||
![]() |
1f7a2594c8 | ||
![]() |
ec64d19a36 | ||
![]() |
5cb67470d5 | ||
![]() |
c03f01a96a | ||
![]() |
26b67a43ae | ||
![]() |
a93ca3a205 | ||
![]() |
dcc647ba3c | ||
![]() |
fe44f59239 | ||
![]() |
80dba0babf | ||
![]() |
34acf9a91e | ||
![]() |
cb859dbb7b | ||
![]() |
20c04b1e62 | ||
![]() |
69eaf8ed0c | ||
![]() |
62c828d722 | ||
![]() |
251e8e8ff4 | ||
![]() |
acc41ec72e | ||
![]() |
f9ebcf2ee4 | ||
![]() |
f3df231dc2 | ||
![]() |
75a1bb7cc5 | ||
![]() |
7d6a64315a | ||
![]() |
2758071d31 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,8 @@
|
||||
!/.idea/copyright
|
||||
!/.idea/icon.png
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/fileTemplates
|
||||
!/.idea/runConfigurations
|
||||
|
||||
/build/
|
||||
/out/
|
||||
|
1
.idea/fileTemplates/code/I18nized Concatenation.java
generated
Normal file
1
.idea/fileTemplates/code/I18nized Concatenation.java
generated
Normal file
@@ -0,0 +1 @@
|
||||
com.maddyhome.idea.vim.helper.MessageHelper.message("${PROPERTY_KEY}", ${PARAMETERS})
|
1
.idea/fileTemplates/code/I18nized Expression.java
generated
Normal file
1
.idea/fileTemplates/code/I18nized Expression.java
generated
Normal file
@@ -0,0 +1 @@
|
||||
com.maddyhome.idea.vim.helper.MessageHelper.message("${PROPERTY_KEY}")
|
26
.idea/inspectionProfiles/Project_Default.xml
generated
26
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -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>
|
25
.idea/inspectionProfiles/Qodana.xml
generated
25
.idea/inspectionProfiles/Qodana.xml
generated
@@ -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>
|
@@ -323,6 +323,14 @@ Contributors:
|
||||
[![icon][github]](https://github.com/i-e-b)
|
||||
|
||||
Iain Ballard
|
||||
* [![icon][mail]](mailto:brandoncc@gmail.com)
|
||||
[![icon][github]](https://github.com/brandoncc)
|
||||
|
||||
Brandon Conway
|
||||
* [![icon][mail]](mailto:ga@anadoxin.org)
|
||||
[![icon][github]](https://github.com/antekone)
|
||||
|
||||
Grzegorz Antoniak
|
||||
|
||||
If you are a contributor and your name is not listed here, feel free to
|
||||
contact the maintainers.
|
||||
|
18
CHANGES.md
18
CHANGES.md
@@ -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
|
||||
|
||||
|
28
README.md
28
README.md
@@ -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
|
||||
------------
|
||||
|
||||
|
24
build.gradle
24
build.gradle
@@ -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
|
||||
|
@@ -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]"/>
|
||||
|
@@ -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"/>
|
||||
|
@@ -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>
|
||||
<h3>Features:</h3>
|
||||
<br/>
|
||||
<ul><li>Ability to map IDE actions via the <code>&lt;Action&gt;</code> keyword. E.g.
|
||||
<code>map &lt;C-K&gt; &lt;Action&gt;(CommentByLineComment)</code>.
|
||||
Check out <code>README.md</code> for the details.</li><li><code>IdeaVim: track action
|
||||
Ids</code> command to find action ids for the <code>:action</code> command.
|
||||
Enable this option in &quot;Search everywhere&quot; (double shift).</li><li>Ability to enable
|
||||
extensions using <code>vim-plug</code> or <code>vundle</code> syntax.<br />
|
||||
E.g. to enable commentary extension you can use one of the following commands:<pre><code
|
||||
class="language-vim">set commentary
|
||||
Plug 'tpope/vim-commentary'
|
||||
Plug 'https://github.com/tpope/vim-commentary'
|
||||
Plugin 'tpope/vim-commentary'
|
||||
...
|
||||
</code></pre><p>This approach is especially handy if you have <code>.vimrc</code> with
|
||||
plugins registered via <code>vim-plug</code> or <code>vundle</code>.</p></li></ul>
|
||||
<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>
|
||||
|
||||
<br/>
|
||||
<h3>Changes:</h3>
|
||||
<br/>
|
||||
<ul><li>Fix <code>&lt;Esc&gt;</code> for dialogs. Now <code>&lt;Esc&gt;</code>
|
||||
will exit insert / visual mode and close the dialog from normal mode.</li><li>Add option to disable
|
||||
IdeaVim in dialogs / single line editors. <a href="https://youtrack.jetbrains.com/issue/VIM-765">VIM-765</a><br
|
||||
/>
|
||||
Use <code>set ideavimsupport=</code> to disable IdeaVim in dialog editors. </li><li>Reposition
|
||||
cursor when <code>scrolloff</code> changes</li></ul>
|
||||
|
||||
<br/>
|
||||
<h3>Fixes:</h3>
|
||||
<br/>
|
||||
<ul><li><a href="https://youtrack.jetbrains.com/issue/VIM-2150">VIM-2150</a> <code>Shift-D</code>
|
||||
should not delete an empty line</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2157">VIM-2157</a>
|
||||
Fix tab with an active template</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2156">VIM-2156</a>
|
||||
Correct up/down motions with inlays</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2144">VIM-2144</a>
|
||||
Correct text position after block insert with inlays</li><li><a
|
||||
href="https://youtrack.jetbrains.com/issue/VIM-2158">VIM-2158</a> Fix scrolling when <code>scrolloff</code>
|
||||
is over half screen height, but less than full height</li></ul>
|
||||
<br/>
|
||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||
<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>
|
||||
|
@@ -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
|
@@ -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,8 +936,10 @@ public class KeyHandler {
|
||||
editorState.popModes();
|
||||
}
|
||||
|
||||
if (editorState.getCommandBuilder().isDone()) {
|
||||
KeyHandler.getInstance().reset(editor);
|
||||
}
|
||||
}
|
||||
|
||||
private final Editor editor;
|
||||
private final DataContext context;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
||||
|
@@ -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:"))
|
||||
|
@@ -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
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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 ""
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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())
|
||||
|
@@ -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=")
|
||||
|
||||
|
@@ -60,7 +60,7 @@ class MigrationComponents(
|
||||
@Service
|
||||
class ApplicationConfigurationMigrator(migrationComponents: MigrationComponents) {
|
||||
|
||||
@Suppress("unused")
|
||||
@Suppress("unused", "HardCodedStringLiteral")
|
||||
constructor() : this(productionMigrationComponents)
|
||||
|
||||
private val migrators = migrationComponents.groupedMigrators
|
||||
|
@@ -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")
|
||||
|
@@ -18,8 +18,6 @@
|
||||
|
||||
package com.maddyhome.idea.vim.ex
|
||||
|
||||
import java.util.*
|
||||
|
||||
class CommandNode(command: ExBeanClass? = null) {
|
||||
|
||||
var commandHandler: ExBeanClass? = command
|
||||
|
@@ -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;
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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 ")
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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() {
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
31
src/com/maddyhome/idea/vim/ex/handler/mapping/CommandInfo.kt
Normal file
31
src/com/maddyhome/idea/vim/ex/handler/mapping/CommandInfo.kt
Normal 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]"
|
||||
}
|
@@ -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())
|
||||
}
|
||||
}
|
@@ -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 commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) } ?: return false
|
||||
val argument = cmd.argument
|
||||
val modes = commandInfo.mappingModes
|
||||
if (argument.isEmpty()) {
|
||||
return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
|
||||
} else {
|
||||
|
||||
if (argument.isEmpty()) return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
|
||||
|
||||
val arguments = try {
|
||||
parseCommandArguments(argument)
|
||||
parseCommandArguments(argument) ?: return false
|
||||
} catch (ignored: IllegalArgumentException) {
|
||||
return false
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
VimPlugin.getKey()
|
||||
.putKeyMapping(modes, arguments.fromKeys, MappingOwner.IdeaVim, arguments.toKeys, commandInfo.isRecursive)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@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(
|
@@ -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())
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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("'([^']*)'")
|
||||
|
@@ -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
|
||||
|
@@ -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() {
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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")
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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');
|
||||
|
@@ -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 = "!"
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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()) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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 + "'";
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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.*
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
@@ -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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
35
src/com/maddyhome/idea/vim/helper/MessageHelper.kt
Normal file
35
src/com/maddyhome/idea/vim/helper/MessageHelper.kt
Normal 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)
|
||||
}
|
@@ -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,6 +542,8 @@ public class SearchHelper {
|
||||
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
|
||||
@@ -552,6 +555,7 @@ public class SearchHelper {
|
||||
// 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) {
|
||||
return new TextRange(openingTag.getStartOffset(), closingTagTextRange.getEndOffset());
|
||||
|
@@ -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";
|
||||
|
25
src/com/maddyhome/idea/vim/helper/VimNlsSafe.kt
Normal file
25
src/com/maddyhome/idea/vim/helper/VimNlsSafe.kt
Normal 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
|
@@ -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 -> {
|
||||
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) {
|
||||
|
@@ -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)
|
||||
|
@@ -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";
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
|
@@ -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;
|
||||
|
@@ -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 {
|
||||
|
@@ -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));
|
||||
|
@@ -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;
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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(" ");
|
||||
|
@@ -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| ...
|
||||
|
@@ -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:]",
|
||||
|
@@ -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(':');
|
||||
|
@@ -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
Reference in New Issue
Block a user