mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
90 Commits
0.60.3-EAP
...
0.61.1-EAP
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
3881b905be | ||
![]() |
073c62f868 | ||
![]() |
d8e0f26bea | ||
![]() |
04c24ab5d0 | ||
![]() |
bfb0ba1ab9 | ||
![]() |
fb7d48af1f | ||
![]() |
559989ce4b | ||
![]() |
81f59e3c18 | ||
![]() |
b6adf9f7a9 | ||
![]() |
b972a01cf0 | ||
![]() |
0296cae712 | ||
![]() |
c38b18e16b | ||
![]() |
8d65c3ed26 | ||
![]() |
995bb966ad | ||
![]() |
dbda1a76ca | ||
![]() |
ed6f990d9a | ||
![]() |
4f86d9cc77 | ||
![]() |
d55774abab | ||
![]() |
d5591ba08d | ||
![]() |
f67d483c4e | ||
![]() |
f26ddd4a27 | ||
![]() |
dbbea642bc | ||
![]() |
0539e39977 | ||
![]() |
65235d32a1 | ||
![]() |
ecfcdf5a8c | ||
![]() |
cf127ba7f9 | ||
![]() |
1fba77d925 | ||
![]() |
5752b116f6 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,9 @@
|
||||
!/.idea/scopes
|
||||
!/.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}")
|
35
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
35
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="HardCodedStringLiteral" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<scope name="Production" level="WARNING" enabled="false">
|
||||
<option name="ignoreForAssertStatements" value="true" />
|
||||
<option name="ignoreForExceptionConstructors" value="true" />
|
||||
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
|
||||
<option name="ignoreForJUnitAsserts" value="true" />
|
||||
<option name="ignoreForClassReferences" value="true" />
|
||||
<option name="ignoreForPropertyKeyReferences" value="true" />
|
||||
<option name="ignoreForNonAlpha" value="true" />
|
||||
<option name="ignoreAssignedToConstants" value="false" />
|
||||
<option name="ignoreToString" value="true" />
|
||||
<option name="nonNlsCommentPattern" value="NON-NLS" />
|
||||
</scope>
|
||||
<option name="ignoreForAssertStatements" value="true" />
|
||||
<option name="ignoreForExceptionConstructors" value="true" />
|
||||
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
|
||||
<option name="ignoreForJUnitAsserts" value="true" />
|
||||
<option name="ignoreForClassReferences" value="true" />
|
||||
<option name="ignoreForPropertyKeyReferences" value="true" />
|
||||
<option name="ignoreForNonAlpha" value="true" />
|
||||
<option name="ignoreAssignedToConstants" value="false" />
|
||||
<option name="ignoreToString" value="false" />
|
||||
<option name="nonNlsCommentPattern" value="NON-NLS" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_requireAnnotationsFirst" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PluginXmlI18n" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
48
.idea/inspectionProfiles/Qodana.xml
generated
Normal file
48
.idea/inspectionProfiles/Qodana.xml
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<description>Inspections profile for Qodana</description>
|
||||
<option name="myName" value="Qodana" />
|
||||
<inspection_tool class="CanBeFinal" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="REPORT_CLASSES" value="false" />
|
||||
<option name="REPORT_METHODS" value="false" />
|
||||
<option name="REPORT_FIELDS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HardCodedStringLiteral" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<scope name="Production" level="WARNING" enabled="false">
|
||||
<option name="ignoreForAssertStatements" value="true" />
|
||||
<option name="ignoreForExceptionConstructors" value="true" />
|
||||
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
|
||||
<option name="ignoreForJUnitAsserts" value="true" />
|
||||
<option name="ignoreForClassReferences" value="true" />
|
||||
<option name="ignoreForPropertyKeyReferences" value="true" />
|
||||
<option name="ignoreForNonAlpha" value="true" />
|
||||
<option name="ignoreAssignedToConstants" value="false" />
|
||||
<option name="ignoreToString" value="true" />
|
||||
<option name="nonNlsCommentPattern" value="NON-NLS" />
|
||||
</scope>
|
||||
<option name="ignoreForAssertStatements" value="true" />
|
||||
<option name="ignoreForExceptionConstructors" value="true" />
|
||||
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
|
||||
<option name="ignoreForJUnitAsserts" value="true" />
|
||||
<option name="ignoreForClassReferences" value="true" />
|
||||
<option name="ignoreForPropertyKeyReferences" value="true" />
|
||||
<option name="ignoreForNonAlpha" value="true" />
|
||||
<option name="ignoreAssignedToConstants" value="false" />
|
||||
<option name="ignoreToString" value="false" />
|
||||
<option name="nonNlsCommentPattern" value="NON-NLS" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_requireAnnotationsFirst" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
2
.teamcity/_Self/buildTypes/Release.kt
vendored
2
.teamcity/_Self/buildTypes/Release.kt
vendored
@@ -10,7 +10,7 @@ object Release : BuildType({
|
||||
description = "Build and publish IdeaVim plugin"
|
||||
|
||||
artifactRules = "build/distributions/*"
|
||||
buildNumberPattern = "0.60"
|
||||
buildNumberPattern = "0.61"
|
||||
|
||||
params {
|
||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||
|
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
@@ -13,7 +13,7 @@ object ReleaseEap : BuildType({
|
||||
description = "Build and publish EAP of IdeaVim plugin"
|
||||
|
||||
artifactRules = "build/distributions/*"
|
||||
buildNumberPattern = "0.60.%build.counter%"
|
||||
buildNumberPattern = "0.61.%build.counter%"
|
||||
|
||||
params {
|
||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||
|
@@ -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.
|
||||
|
28
CHANGES.md
28
CHANGES.md
@@ -24,6 +24,26 @@ usual beta standards.
|
||||
|
||||
## To Be Released
|
||||
|
||||
### Features:
|
||||
|
||||
* Support `unmap` and `mapclear` commands [VIM-1491](https://youtrack.jetbrains.com/issue/VIM-1491)
|
||||
* Support mappings in ex panel (`cmap`) [VIM-1227](https://youtrack.jetbrains.com/issue/VIM-1227)
|
||||
|
||||
### Fixes:
|
||||
* [VIM-2113](https://youtrack.jetbrains.com/issue/VIM-2113) Fix `cit` for empty tags
|
||||
* [VIM-2114](https://youtrack.jetbrains.com/issue/VIM-2114) Unnamed register isn't changed after deleting empty tag
|
||||
* [VIM-1475](https://youtrack.jetbrains.com/issue/VIM-1475) Enable block caret to be used in insert mode.
|
||||
* [VIM-2170](https://youtrack.jetbrains.com/issue/VIM-2170) Fix an alternative range format for `s` command
|
||||
|
||||
### Merged PRs:
|
||||
* [249](https://github.com/JetBrains/ideavim/pull/249) by [Jan Palus](https://github.com/jpalus): VIM-2113 Increase tag range only in visual mode
|
||||
* [250](https://github.com/JetBrains/ideavim/pull/250) by [Jan Palus](https://github.com/jpalus): VIM-2114 Do not override registers when deleting empty range
|
||||
* [256](https://github.com/JetBrains/ideavim/pull/256) by [Brandon Conway](https://github.com/brandoncc): Fix typo
|
||||
* [254](https://github.com/JetBrains/ideavim/pull/254) by [Grzegorz Antoniak](https://github.com/antekone): VIM-1475: Add an option to use block caret in insert mode
|
||||
* [225](https://github.com/JetBrains/ideavim/pull/225) by [sumoooru2](https://github.com/sumoooru2): Implement cmap
|
||||
|
||||
## 0.61, 2020-11-12
|
||||
|
||||
### Features:
|
||||
* Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`.
|
||||
Check out `README.md` for the details.
|
||||
@@ -44,14 +64,18 @@ usual beta standards.
|
||||
### Changes:
|
||||
* Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode.
|
||||
* Add option to disable IdeaVim in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
|
||||
Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors.
|
||||
_Note for EAP users: the option name can be changed for the stable release_
|
||||
Use `set ideavimsupport=` to disable IdeaVim in dialog editors.
|
||||
* Reposition cursor when `scrolloff` changes
|
||||
|
||||
### Fixes:
|
||||
* [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line
|
||||
* [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template
|
||||
* [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays
|
||||
* [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays
|
||||
* [VIM-2158](https://youtrack.jetbrains.com/issue/VIM-2158) Fix scrolling when `scrolloff` is over half screen height, but less than full height
|
||||
|
||||
### Merged PRs:
|
||||
* [255](https://github.com/JetBrains/ideavim/pull/255) by [Matt Ellis](https://github.com/citizenmatt): Fix various scrolling issues
|
||||
|
||||
## 0.60, 2020-10-09
|
||||
|
||||
|
68
README.md
68
README.md
@@ -11,7 +11,7 @@ IdeaVim
|
||||
[![Gitter][gitter-svg]][gitter]
|
||||
[![Twitter][twitter-svg]][twitter]
|
||||
|
||||
IdeaVim is a Vim emulation plugin for IDEs based on the IntelliJ Platform.
|
||||
IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
|
||||
|
||||
##### Contact maintainers:
|
||||
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
|
||||
@@ -165,7 +165,7 @@ You can read your `~/.vimrc` file from `~/.ideavimrc` with this command:
|
||||
|
||||
source ~/.vimrc
|
||||
|
||||
Please note that IdeaVim currently parses `~/.ideavimrc` & `~/.vimrc` files via simple pattern-matching.
|
||||
> :warning: Please note that IdeaVim currently parses `~/.ideavimrc` & `~/.vimrc` files via simple pattern-matching.
|
||||
See [VIM-669](https://youtrack.jetbrains.com/issue/VIM-669) for proper parsing
|
||||
of VimL files.
|
||||
|
||||
@@ -183,67 +183,43 @@ Emulated Vim Plugins
|
||||
|
||||
See [doc/emulated-plugins.md](doc/emulated-plugins.md)
|
||||
|
||||
Changes to the IDE
|
||||
------------------
|
||||
Executing IDE Actions
|
||||
---------------------
|
||||
|
||||
### Executing IDE Actions
|
||||
|
||||
IdeaVim adds two commands for listing and executing arbitrary IDE actions as
|
||||
IdeaVim adds various commands for listing and executing arbitrary IDE actions as
|
||||
Ex commands or via `:map` command mappings:
|
||||
|
||||
**Executing actions:**
|
||||
* `:action {action_id}`
|
||||
* Execute an action by id. Works from Ex command line.
|
||||
* `<Action>(*action_id*)`
|
||||
* For the mappings you can use a special `<Action>` keyword. Don't forget the parentheses.
|
||||
|
||||
**Finding actions:**
|
||||
* `:actionlist [pattern]`
|
||||
* Find IDE actions by name or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
||||
* `:action {name}`
|
||||
* Execute an action named `NAME`
|
||||
* Find IDE actions by id or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
||||
|
||||
In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
|
||||
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`). **[To Be Released]**
|
||||
* In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
|
||||
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`).
|
||||
|
||||
<details>
|
||||
<summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary>
|
||||
<img src="resources/readme/track_action_id.gif" alt="track actioin ids"/>
|
||||
</details>
|
||||
|
||||
For the mappings you can use a special `<Action>` keyword. Use `<Action>(*action_id*)` to map keys to some action. Don't
|
||||
forget the parentheses. This keyword works for insert mode as well. **[To Be Released]**
|
||||
<details>
|
||||
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
|
||||
<img src="resources/readme/track_action_id.gif" alt="track action ids"/>
|
||||
</details>
|
||||
|
||||
Examples:
|
||||
|
||||
```vim
|
||||
" Map \r to the Reformat Code action
|
||||
:map \r :action ReformatCode<CR>
|
||||
" or
|
||||
:map \r <Action>(ReformatCode) " [To Be Released]
|
||||
:map \r <Action>(ReformatCode)
|
||||
|
||||
" Map <leader>d to start debug
|
||||
:map <leader>d :action Debug<CR>
|
||||
" or
|
||||
:map <leader>d <Action>(Debug) " [To Be Released]
|
||||
:map <leader>d <Action>(Debug)
|
||||
|
||||
" Map \b to toggle the breakpoint on the current line
|
||||
:map \b :action ToggleLineBreakpoint<CR>
|
||||
" or
|
||||
:map \b <Action>(ToggleLineBreakpoint) " [To Be Released]
|
||||
:map \b <Action>(ToggleLineBreakpoint)
|
||||
```
|
||||
|
||||
### Undo/Redo
|
||||
|
||||
The IdeaVim plugin uses the undo/redo functionality of the IntelliJ Platform,
|
||||
so the behavior of the `u` and `<C-R>` commands may differ from the original
|
||||
Vim. Vim compatibility of undo/redo may be improved in future releases.
|
||||
|
||||
See also [unresolved undo issues](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+u).
|
||||
|
||||
### Escape
|
||||
|
||||
Using `<Esc>` in dialog windows remains problematic. For most dialog windows,
|
||||
the Vim emulator is put into insert mode with `<Esc>` not working. You
|
||||
should use `<C-c>` or `<C-[>` instead. In some dialog windows, the normal mode is
|
||||
switched by default. The usage of the Vim emulator in dialog windows is an area for
|
||||
improvement.
|
||||
|
||||
See also [unresolved escape issues](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+Help+topic%3A+i_Esc).
|
||||
|
||||
:gem: Contributing
|
||||
------------
|
||||
|
||||
|
24
build.gradle
24
build.gradle
@@ -13,7 +13,7 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.jetbrains.intellij' version '0.6.1'
|
||||
id 'org.jetbrains.intellij' version '0.6.5'
|
||||
id 'io.gitlab.arturbosch.detekt' version '1.14.1'
|
||||
id "org.jetbrains.changelog" version "0.6.2"
|
||||
}
|
||||
@@ -45,6 +45,8 @@ intellij {
|
||||
intellijRepo = "https://www.jetbrains.com/intellij-repository"
|
||||
plugins = ['java']
|
||||
|
||||
downloadRobotServerPlugin.version = "0.10.0"
|
||||
|
||||
publishPlugin {
|
||||
channels publishChannels.split(',')
|
||||
username publishUsername
|
||||
@@ -52,6 +54,10 @@ intellij {
|
||||
}
|
||||
}
|
||||
|
||||
runIdeForUiTests {
|
||||
systemProperty "robot-server.port", "8082"
|
||||
}
|
||||
|
||||
runPluginVerifier {
|
||||
ideVersions = ["IC-2020.1.4", "IC-2020.2.3"]
|
||||
downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
|
||||
@@ -61,14 +67,18 @@ runPluginVerifier {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven { url = "https://jetbrains.bintray.com/intellij-third-party-dependencies" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||
compileOnly "org.jetbrains:annotations:19.0.0"
|
||||
compileOnly "org.jetbrains:annotations:20.1.0"
|
||||
|
||||
// https://mvnrepository.com/artifact/com.ensarsarajcic.neovim.java/neovim-api
|
||||
compile group: 'com.ensarsarajcic.neovim.java', name: 'neovim-api', version: '0.1.16'
|
||||
testImplementation("com.ensarsarajcic.neovim.java:neovim-api:0.1.16")
|
||||
|
||||
testImplementation("com.intellij.remoterobot:remote-robot:0.10.0")
|
||||
testImplementation("com.intellij.remoterobot:remote-fixtures:1.1.18")
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
@@ -113,6 +123,14 @@ changelog {
|
||||
// version = "0.60"
|
||||
}
|
||||
|
||||
task getUnreleasedChangelog() {
|
||||
group = "changelog"
|
||||
doLast {
|
||||
def log = changelog.getUnreleased().toHTML()
|
||||
println log
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("slackEapNotification") {
|
||||
doLast {
|
||||
if (!slackUrl) return
|
||||
|
@@ -4,7 +4,15 @@ Emulated Vim Plugins
|
||||
IdeaVim extensions emulate plugins of the original Vim. In order to use
|
||||
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
|
||||
|
||||
set <extension-name>
|
||||
```
|
||||
set <extension-name>
|
||||
```
|
||||
|
||||
If you reuse your existing `.vimrc` file using `source ~/.vimrc`, IdeaVim can parse and enable plugins that are defined
|
||||
using [vim-plug](https://github.com/junegunn/vim-plug) or [vundle](https://github.com/VundleVim/Vundle.vim).
|
||||
No additional set commands in `~/.ideavimrc` are required.
|
||||
If you'd like to disable some plugin that's enabled in `.vimrc`, you can use `set no<extension-name>`
|
||||
in `~/.ideavimrc`.
|
||||
|
||||
Available extensions:
|
||||
|
||||
@@ -20,18 +28,52 @@ Available extensions:
|
||||
## surround
|
||||
|
||||
* Setup: `set surround`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/tpope/vim-surround'</code>
|
||||
<br/>
|
||||
<code>Plug 'tpope/vim-surround'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-surround'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1697'</code>
|
||||
</details>
|
||||
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
|
||||
* Commands: `ys`, `cs`, `ds`, `S`
|
||||
|
||||
## multiple-cursors
|
||||
|
||||
* Setup: `set multiple-cursors`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/terryma/vim-multiple-cursors'</code>
|
||||
<br/>
|
||||
<code>Plug 'terryma/vim-multiple-cursors'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-multiple-cursors'</code>
|
||||
</details>
|
||||
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
|
||||
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
|
||||
|
||||
## commentary
|
||||
|
||||
* Setup: `set commentary`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/tpope/vim-commentary'</code>
|
||||
<br/>
|
||||
<code>Plug 'tpope/vim-commentary'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-commentary'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=3695'</code>
|
||||
<br/>
|
||||
<code>Plug 'tomtom/tcomment_vim'</code>
|
||||
<br/>
|
||||
<code>Plug 'tcomment_vim'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1173'</code>
|
||||
</details>
|
||||
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
|
||||
* Commands: `gcc`, `gc + motion`, `v_gc`
|
||||
* By [Daniel Leong](https://github.com/dhleong)
|
||||
@@ -39,6 +81,22 @@ Available extensions:
|
||||
## ReplaceWithRegister
|
||||
|
||||
* Setup: `set ReplaceWithRegister`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/vim-scripts/ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-scripts/ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://github.com/inkarkat/vim-ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'inkarkat/vim-ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-ReplaceWithRegister'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2703'</code>
|
||||
</details>
|
||||
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
|
||||
* Commands: `gr`, `grr`
|
||||
* By [igrekster](https://github.com/igrekster)
|
||||
@@ -47,6 +105,16 @@ Available extensions:
|
||||
|
||||
* Setup:
|
||||
* `set argtextobj`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/vim-scripts/argtextobj.vim'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-scripts/argtextobj.vim'</code>
|
||||
<br/>
|
||||
<code>Plug 'argtextobj.vim'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2699'</code>
|
||||
</details>
|
||||
* By default, only the arguments inside parenthesis are considered. To extend the functionality
|
||||
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
|
||||
list of colon-separated pairs (same as VIM's `matchpairs` option), like
|
||||
@@ -59,6 +127,14 @@ Available extensions:
|
||||
## exchange
|
||||
|
||||
* Setup: `set exchange`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/tommcdo/vim-exchange'</code>
|
||||
<br/>
|
||||
<code>Plug 'tommcdo/vim-exchange'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-exchange'</code>
|
||||
</details>
|
||||
* Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange)
|
||||
* Commands: `cx`, `cxx`, `X`, `cxc`
|
||||
* By [fan-tom](https://github.com/fan-tom)
|
||||
@@ -66,6 +142,16 @@ Available extensions:
|
||||
## textobj-entire
|
||||
|
||||
* Setup: `set textobj-entire`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/kana/vim-textobj-entire'</code>
|
||||
<br/>
|
||||
<code>Plug 'kana/vim-textobj-entire'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-textobj-entire'</code>
|
||||
<br/>
|
||||
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2610'</code>
|
||||
</details>
|
||||
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
|
||||
* Additional text objects: `ae`, `ie`
|
||||
* By [Alexandre Grison](https://github.com/agrison)
|
||||
@@ -74,6 +160,14 @@ Available extensions:
|
||||
|
||||
* Setup:
|
||||
* `set highlightedyank`
|
||||
* <details>
|
||||
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||
<code>Plug 'https://github.com/machakann/vim-highlightedyank'</code>
|
||||
<br/>
|
||||
<code>Plug 'machakann/vim-highlightedyank'</code>
|
||||
<br/>
|
||||
<code>Plug 'vim-highlightedyank'</code>
|
||||
</details>
|
||||
* if you want to optimize highlight duration, assign a time in milliseconds:
|
||||
`let g:highlightedyank_highlight_duration = "1000"`
|
||||
A negative number makes the highlight persistent.
|
||||
|
@@ -125,7 +125,7 @@ The following `:set` commands can appear in `~/.ideavimrc` or be set manually in
|
||||
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
|
||||
"<C-J>", "<C-Q>"
|
||||
|
||||
`ideaenabledbufs` `ideaenabledbufs` List of strings (default "dialog") [To Be Released]
|
||||
`ideavimsupport` `ideavimsupport` List of strings (default "dialog")
|
||||
|
||||
Define the list of additional buffers where IdeaVim is enabled.
|
||||
|
||||
|
@@ -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"/>
|
||||
|
@@ -2,18 +2,70 @@
|
||||
<name>IdeaVim</name>
|
||||
<id>IdeaVIM</id>
|
||||
<change-notes><![CDATA[
|
||||
<ul>
|
||||
<li>Fix ESC in dialogs</li>
|
||||
<li>Add option to disable IdeaVim in dialogs and single line editors</li>
|
||||
<li>Ability to map IDE actions via the <Action> keyword.</li>
|
||||
<li>"IdeaVim: track action Ids" command to find action ids for the :action command.
|
||||
<li>Add new option to register IdeaVim extensions. Please read the changelog for details</li>
|
||||
</ul>
|
||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||
]]></change-notes>
|
||||
<h3>Features:</h3>
|
||||
<ul>
|
||||
<li>Support <code>unmap</code> and <code>mapclear</code> commands
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-1491">VIM-1491</a>
|
||||
</li>
|
||||
<li>Support mappings in ex panel (<code>cmap</code>)
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-1227">VIM-1227</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Fixes:</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-2113">VIM-2113</a>
|
||||
Fix <code>cit</code> for empty tags
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-2114">VIM-2114</a>
|
||||
Unnamed register isn't changed after deleting empty tag
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-1475">VIM-1475</a>
|
||||
Enable block caret to be used in insert mode.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://youtrack.jetbrains.com/issue/VIM-2170">VIM-2170</a>
|
||||
Fix an alternative range format for <code>s</code> command
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Merged PRs:</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/JetBrains/ideavim/pull/249">249</a>
|
||||
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2113 Increase tag range only in visual mode
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/JetBrains/ideavim/pull/250">250</a>
|
||||
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2114 Do not override registers when deleting empty range
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/JetBrains/ideavim/pull/256">256</a>
|
||||
by <a href="https://github.com/brandoncc">Brandon Conway</a>: Fix typo
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/JetBrains/ideavim/pull/254">254</a>
|
||||
by <a href="https://github.com/antekone">Grzegorz Antoniak</a>: VIM-1475: Add an option to use block caret in insert
|
||||
mode
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/JetBrains/ideavim/pull/225">225</a>
|
||||
by <a href="https://github.com/sumoooru2">sumoooru2</a>: Implement cmap
|
||||
</li>
|
||||
</ul>
|
||||
<br/>
|
||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||
]]>
|
||||
</change-notes>
|
||||
<description><![CDATA[
|
||||
<p>Vim emulation plug-in for IDEs based on the IntelliJ platform.</p>
|
||||
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing, marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, window commands, etc.</p>
|
||||
<p>Vim emulation plugin for IntelliJ Platform-based IDEs.</p>
|
||||
<br/>
|
||||
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing,
|
||||
marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, Vim plugins, etc.</p>
|
||||
<br/>
|
||||
<p>See also:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li>
|
||||
@@ -25,11 +77,11 @@
|
||||
|
||||
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
||||
<!-- Check for [Version Update] tag in YouTrack as well -->
|
||||
<idea-version since-build="201.5985.32"/>
|
||||
<idea-version since-build="201.5985.41"/>
|
||||
|
||||
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform -->
|
||||
<depends>com.intellij.modules.lang</depends>
|
||||
<resource-bundle xmlns="">messages</resource-bundle>
|
||||
<resource-bundle>messages.IdeaVimBundle</resource-bundle>
|
||||
|
||||
<application-components>
|
||||
<component>
|
||||
@@ -76,7 +128,7 @@
|
||||
<xi:include href="/META-INF/includes/VimExtensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
<xi:include href="/META-INF/includes/VimListeners.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<actions>
|
||||
<actions resource-bundle="messages.IdeaVimBundle">
|
||||
<action id="VimPluginToggle" class="com.maddyhome.idea.vim.action.VimPluginToggleAction">
|
||||
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
||||
</action>
|
||||
@@ -102,8 +154,6 @@
|
||||
</action>
|
||||
</group>
|
||||
|
||||
<action id="VimFindActionIdAction"
|
||||
class="com.maddyhome.idea.vim.listener.FindActionIdAction" text="IdeaVim: Track Action Ids"
|
||||
description="Starts tracking ids of executed actions"/>
|
||||
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
@@ -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;
|
||||
@@ -325,7 +319,7 @@ public class KeyHandler {
|
||||
}
|
||||
}
|
||||
reset(editor);
|
||||
ChangeGroup.resetCaret(editor, false);
|
||||
ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor());
|
||||
}
|
||||
|
||||
private boolean handleKeyMapping(final @NotNull Editor editor,
|
||||
@@ -599,6 +593,22 @@ public class KeyHandler {
|
||||
}
|
||||
|
||||
DigraphResult res = editorState.processDigraphKey(key, editor);
|
||||
if (ExEntryPanel.getInstance().isActive()) {
|
||||
switch (res.getResult()) {
|
||||
case DigraphResult.RES_HANDLED:
|
||||
setPromptCharacterEx(commandBuilder.isPuttingLiteral() ? '^' : key.getKeyChar());
|
||||
break;
|
||||
case DigraphResult.RES_DONE:
|
||||
case DigraphResult.RES_BAD:
|
||||
if (key.getKeyCode() == KeyEvent.VK_C && (key.getModifiers() & InputEvent.CTRL_DOWN_MASK) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
ExEntryPanel.getInstance().getEntry().clearCurrentAction();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (res.getResult()) {
|
||||
case DigraphResult.RES_HANDLED:
|
||||
editorState.getCommandBuilder().addKey(key);
|
||||
@@ -753,8 +763,10 @@ public class KeyHandler {
|
||||
// the key handler when it's complete.
|
||||
if (action instanceof InsertCompletedDigraphAction) {
|
||||
editorState.startDigraphSequence();
|
||||
setPromptCharacterEx('?');
|
||||
} else if (action instanceof InsertCompletedLiteralAction) {
|
||||
editorState.startLiteralSequence();
|
||||
setPromptCharacterEx('^');
|
||||
}
|
||||
break;
|
||||
case EX_STRING:
|
||||
@@ -777,7 +789,7 @@ public class KeyHandler {
|
||||
* @param name The name of the action to execute
|
||||
* @param context The context to run it in
|
||||
*/
|
||||
public static boolean executeAction(@NotNull String name, @NotNull DataContext context) {
|
||||
public static boolean executeAction(@NotNull @NonNls String name, @NotNull DataContext context) {
|
||||
ActionManager aMgr = ActionManager.getInstance();
|
||||
AnAction action = aMgr.getAction(name);
|
||||
return action != null && executeAction(action, context);
|
||||
@@ -849,6 +861,13 @@ public class KeyHandler {
|
||||
|
||||
}
|
||||
|
||||
private void setPromptCharacterEx(final char promptCharacter) {
|
||||
final ExEntryPanel exEntryPanel = ExEntryPanel.getInstance();
|
||||
if (exEntryPanel.isActive()) {
|
||||
exEntryPanel.getEntry().setCurrentActionPromptCharacter(promptCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
// This class is copied from com.intellij.openapi.editor.actionSystem.DialogAwareDataContext.DialogAwareDataContext
|
||||
private static final class DialogAwareDataContext implements DataContext {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -917,7 +936,9 @@ public class KeyHandler {
|
||||
editorState.popModes();
|
||||
}
|
||||
|
||||
KeyHandler.getInstance().reset(editor);
|
||||
if (editorState.getCommandBuilder().isDone()) {
|
||||
KeyHandler.getInstance().reset(editor);
|
||||
}
|
||||
}
|
||||
|
||||
private final Editor editor;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -20,15 +20,29 @@ package com.maddyhome.idea.vim.action
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.KeyHandler
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.command.Command
|
||||
import com.maddyhome.idea.vim.command.CommandState
|
||||
import com.maddyhome.idea.vim.group.MotionGroup
|
||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||
import com.maddyhome.idea.vim.helper.mode
|
||||
import com.maddyhome.idea.vim.helper.vimForEachCaret
|
||||
|
||||
class ResetModeAction : VimActionHandler.SingleExecution() {
|
||||
override val type: Command.Type = Command.Type.OTHER_WRITABLE
|
||||
|
||||
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||
val modeBeforeReset = editor.mode
|
||||
KeyHandler.getInstance().fullReset(editor.getTopLevelEditor())
|
||||
|
||||
if (modeBeforeReset == CommandState.Mode.INSERT) {
|
||||
editor.vimForEachCaret { caret ->
|
||||
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
|
||||
MotionGroup.moveCaret(editor, caret, position)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
||||
|
@@ -128,7 +128,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
|
||||
private fun isEnabledForEscape(editor: Editor): Boolean {
|
||||
return editor.isPrimaryEditor()
|
||||
|| EditorHelper.isFileEditor(editor) && !editor.inNormalMode
|
||||
|| OptionsManager.ideaenabledbufs.contains("dialog") && !editor.inNormalMode
|
||||
|| OptionsManager.ideavimsupport.contains("dialog") && !editor.inNormalMode
|
||||
}
|
||||
|
||||
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {
|
||||
|
@@ -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
|
||||
|
@@ -19,10 +19,14 @@ package com.maddyhome.idea.vim.action.motion.visual
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.command.Command
|
||||
import com.maddyhome.idea.vim.group.MotionGroup
|
||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||
import com.maddyhome.idea.vim.helper.vimForEachCaret
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
@@ -32,6 +36,16 @@ class VisualExitModeAction : VimActionHandler.SingleExecution() {
|
||||
|
||||
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||
editor.getTopLevelEditor().exitVisualMode()
|
||||
|
||||
// Should it be in [exitVisualMode]?
|
||||
editor.vimForEachCaret { caret ->
|
||||
val lineEnd = EditorHelper.getLineEndForOffset(editor, caret.offset)
|
||||
if (lineEnd == caret.offset) {
|
||||
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
|
||||
MotionGroup.moveCaret(editor, caret, position)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
@@ -178,7 +180,7 @@ class CommandState private constructor() {
|
||||
executingCommand = null
|
||||
resetModes()
|
||||
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
|
||||
startDigraphSequence()
|
||||
digraphSequence.reset()
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
@@ -232,6 +234,7 @@ class CommandState private constructor() {
|
||||
* be added. It's better not to compare the whole string but only
|
||||
* the leading character(s).
|
||||
*/
|
||||
@VimNlsSafe
|
||||
fun toVimNotation(): String {
|
||||
return when (mode) {
|
||||
Mode.COMMAND -> "n"
|
||||
@@ -266,7 +269,7 @@ class CommandState private constructor() {
|
||||
if (msg.isNotEmpty()) {
|
||||
msg.append(" - ")
|
||||
}
|
||||
msg.append("recording")
|
||||
msg.append(MessageHelper.message("show.mode.recording"))
|
||||
}
|
||||
VimPlugin.showMode(msg.toString())
|
||||
}
|
||||
|
@@ -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 argument = cmd.argument
|
||||
val modes = commandInfo.mappingModes
|
||||
if (argument.isEmpty()) {
|
||||
return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
|
||||
} else {
|
||||
val arguments = try {
|
||||
parseCommandArguments(argument)
|
||||
} catch (ignored: IllegalArgumentException) {
|
||||
return false
|
||||
}
|
||||
val commandInfo = COMMAND_INFOS.find { cmd.command.startsWith(it.prefix) } ?: return false
|
||||
val argument = cmd.argument
|
||||
val modes = commandInfo.mappingModes
|
||||
|
||||
if (arguments != null) {
|
||||
for (unsupportedArgument in UNSUPPORTED_SPECIAL_ARGUMENTS) {
|
||||
if (unsupportedArgument in arguments.specialArguments) {
|
||||
throw ExException("Unsupported map argument: $unsupportedArgument")
|
||||
}
|
||||
}
|
||||
VimPlugin.getKey().putKeyMapping(modes, arguments.fromKeys, MappingOwner.IdeaVim, arguments.toKeys, commandInfo.isRecursive)
|
||||
return true
|
||||
}
|
||||
if (argument.isEmpty()) return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor)
|
||||
|
||||
val arguments = try {
|
||||
parseCommandArguments(argument) ?: return false
|
||||
} catch (ignored: IllegalArgumentException) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (unsupportedArgument in UNSUPPORTED_SPECIAL_ARGUMENTS) {
|
||||
if (unsupportedArgument in arguments.specialArguments) {
|
||||
throw ExException("Unsupported map argument: $unsupportedArgument")
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
VimPlugin.getKey()
|
||||
.putKeyMapping(modes, arguments.fromKeys, MappingOwner.IdeaVim, arguments.toKeys, commandInfo.isRecursive)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@NonNls
|
||||
private enum class SpecialArgument(val myName: String) {
|
||||
BUFFER("<buffer>"),
|
||||
NOWAIT("<nowait>"),
|
||||
@@ -113,10 +112,6 @@ class MapHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler, Co
|
||||
private class CommandArguments(val specialArguments: Set<SpecialArgument>, val fromKeys: List<KeyStroke>,
|
||||
val toKeys: List<KeyStroke>)
|
||||
|
||||
private class CommandInfo(val prefix: String, suffix: String, val mappingModes: Set<MappingMode>, val isRecursive: Boolean) {
|
||||
val command = if (suffix.isBlank()) prefix else "$prefix[$suffix]"
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CTRL_V = '\u0016'
|
||||
private val COMMAND_INFOS = arrayOf(
|
@@ -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;
|
||||
@@ -31,10 +32,12 @@ public interface VimExtension {
|
||||
@NotNull ExtensionPointName<ExtensionBeanClass> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension");
|
||||
|
||||
/**
|
||||
* @deprecated Please set extension name in <vimExtension> tag
|
||||
* @deprecated This property is not used anymore, but we'll remove it much later to keep the compatibility of IdeaVim
|
||||
* extensions with previous versions of IdeaVim.
|
||||
*/
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "0.63")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "0.65")
|
||||
@VimNlsSafe
|
||||
@NotNull String getName();
|
||||
|
||||
default MappingOwner getOwner() {
|
||||
|
@@ -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;
|
||||
@@ -203,6 +204,10 @@ public class EditorGroup implements PersistentStateComponent<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBarCursor() {
|
||||
return !isBlockCursor;
|
||||
}
|
||||
|
||||
public void editorCreated(@NotNull Editor editor) {
|
||||
isBlockCursor = editor.getSettings().isBlockCursor();
|
||||
isRefrainFromScrolling = editor.getSettings().isRefrainFromScrolling();
|
||||
@@ -217,7 +222,7 @@ public class EditorGroup implements PersistentStateComponent<Element> {
|
||||
VimPlugin.getChange().insertBeforeCursor(editor, new EditorDataContext(editor, null));
|
||||
KeyHandler.getInstance().reset(editor);
|
||||
}
|
||||
editor.getSettings().setBlockCursor(!CommandStateHelper.inInsertMode(editor));
|
||||
editor.getSettings().setBlockCursor(!CommandStateHelper.inInsertMode(editor) || isBlockCursor);
|
||||
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
|
||||
}
|
||||
|
||||
|
@@ -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 + "'";
|
||||
|
||||
|
@@ -42,10 +42,12 @@ import com.maddyhome.idea.vim.handler.MotionActionHandler;
|
||||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
|
||||
import com.maddyhome.idea.vim.helper.*;
|
||||
import com.maddyhome.idea.vim.option.NumberOption;
|
||||
import com.maddyhome.idea.vim.option.OptionChangeListener;
|
||||
import com.maddyhome.idea.vim.option.OptionsManager;
|
||||
import com.maddyhome.idea.vim.ui.ExEntryPanel;
|
||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
|
||||
import kotlin.Pair;
|
||||
import kotlin.ranges.IntProgression;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -184,7 +186,7 @@ public class MotionGroup {
|
||||
if (caretVisualLine < topVisualLine + scrollOffset) {
|
||||
newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset);
|
||||
}
|
||||
else if (caretVisualLine >= bottomVisualLine - scrollOffset) {
|
||||
else if (caretVisualLine > bottomVisualLine - scrollOffset) {
|
||||
newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
|
||||
}
|
||||
else {
|
||||
@@ -631,10 +633,10 @@ public class MotionGroup {
|
||||
private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) {
|
||||
|
||||
// TODO: Make this work with soft wraps
|
||||
// Vim's algorithm works counts line heights for wrapped lines. We're using visual lines, which handles collapsed
|
||||
// folds, but treats soft wrapped lines as individual lines.
|
||||
// Ironically, after figuring out how Vim's algorithm works (although not *why*), it looks likely to be rewritten as
|
||||
// a dumb line for line reimplementation.
|
||||
// Vim's algorithm works by counting line heights for wrapped lines. We're using visual lines, which handles
|
||||
// collapsed folds, but treats soft wrapped lines as individual lines.
|
||||
// Ironically, after figuring out how Vim's algorithm works (although not *why*) and reimplementing, it looks likely
|
||||
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
||||
|
||||
final int topLine = getVisualLineAtTopOfScreen(editor);
|
||||
final int bottomLine = getVisualLineAtBottomOfScreen(editor);
|
||||
@@ -642,7 +644,7 @@ public class MotionGroup {
|
||||
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
|
||||
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
|
||||
final int topBound = topLine + scrollOffset;
|
||||
final int bottomBound = Math.max(topBound + 1, bottomLine - scrollOffset);
|
||||
final int bottomBound = Math.max(topBound, bottomLine - scrollOffset);
|
||||
|
||||
// If we need to scroll the current line more than half a screen worth of lines then we just centre the new
|
||||
// current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line
|
||||
@@ -650,7 +652,6 @@ public class MotionGroup {
|
||||
// Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if
|
||||
// the number of lines is less. I'm not sure what impact this has.
|
||||
final int height = bottomLine - topLine + 1;
|
||||
final int halfHeight = Math.max(2, (height / 2) - 1);
|
||||
|
||||
// Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean
|
||||
// newLine = caretLine +/- MAX(sj, so)
|
||||
@@ -663,7 +664,7 @@ public class MotionGroup {
|
||||
// (See move.c:scroll_cursor_top)
|
||||
//
|
||||
// When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again
|
||||
// expands lines above and below the new bottom line, but calcualtes things a little differently. The total number
|
||||
// expands lines above and below the new bottom line, but calculates things a little differently. The total number
|
||||
// of lines expanded is at least scrolljump and there must be at least scrolloff lines below.
|
||||
// Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line.
|
||||
// If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra
|
||||
@@ -678,10 +679,26 @@ public class MotionGroup {
|
||||
// out correct scroll locations
|
||||
final int scrollJump = getScrollJump(editor, height);
|
||||
|
||||
if (caretLine < topBound) {
|
||||
// Unavoidable fudge value. Multiline rendered doc comments can mean we have very few actual lines, and scrolling
|
||||
// can get stuck in a loop as we re-centre the cursor instead of actually moving it. But if we ignore all inlays
|
||||
// and use the approximate screen height instead of the actual screen height (in lines), we make incorrect
|
||||
// assumptions about the top/bottom line numbers and can scroll to the wrong location. E.g. if there are enough doc
|
||||
// comments (String.java) it's possible to get 12 lines of actual code on screen. Given scrolloff=5, it's very easy
|
||||
// to hit problems, and have (scrolloffset > height / 2) and scroll to the middle of the screen. We'll use this
|
||||
// fudge value to make sure we're working with sensible values. Note that this problem doesn't affect code without
|
||||
// block inlays as positioning the cursor in the middle of the screen always positions it in a deterministic manner,
|
||||
// relative to other text in the file.
|
||||
final int inlayAwareMinHeightFudge = getApproximateScreenHeight(editor) / 2;
|
||||
|
||||
// Note that while these calculations do the same thing that Vim does, it processes them differently. E.g. it
|
||||
// optionally checks and moves the top line, then optionally checks the bottom line. This gives us the same results
|
||||
// via the tests.
|
||||
if (height > inlayAwareMinHeightFudge && scrollOffset > height / 2) {
|
||||
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||
} else if (caretLine < topBound) {
|
||||
// Scrolling up, put the cursor at the top of the window (minus scrolloff)
|
||||
// Initial approximation in move.c:update_topline
|
||||
if (topLine + scrollOffset - caretLine >= halfHeight) {
|
||||
// Initial approximation in move.c:update_topline (including same calculation for halfHeight)
|
||||
if (topLine + scrollOffset - caretLine >= Math.max(2, (height / 2) - 1)) {
|
||||
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||
}
|
||||
else {
|
||||
@@ -692,9 +709,12 @@ public class MotionGroup {
|
||||
final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset);
|
||||
final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine);
|
||||
|
||||
// Used is set to the line height of caretLine, and then incremented by line height of the lines above and
|
||||
// below caretLine (up to scrolloff or end of file)
|
||||
final int used = 1 + (newTopLine - topLine) + Math.min(scrollOffset, getVisualLineCount(editor) - topLine);
|
||||
// Used is set to the line height of caretLine (1 or how many lines soft wraps take up), and then incremented by
|
||||
// the line heights of the lines above and below caretLine (up to scrolloff or end of file).
|
||||
// Our implementation ignores soft wrap line heights. Folds already have a line height of 1.
|
||||
final int usedAbove = caretLine - newTopLine;
|
||||
final int usedBelow = Math.min(scrollOffset, getVisualLineCount(editor) - caretLine);
|
||||
final int used = 1 + usedAbove + usedBelow;
|
||||
if (used > height) {
|
||||
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||
}
|
||||
@@ -1374,4 +1394,21 @@ public class MotionGroup {
|
||||
return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ScrollOptionsChangeListener implements OptionChangeListener<String> {
|
||||
public static ScrollOptionsChangeListener INSTANCE = new ScrollOptionsChangeListener();
|
||||
|
||||
@Contract(pure = true)
|
||||
private ScrollOptionsChangeListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChange(String oldValue, String newValue) {
|
||||
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||
if (UserDataManager.getVimEditorGroup(editor)) {
|
||||
MotionGroup.scrollCaretIntoView(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -163,7 +163,7 @@ fun updateCaretState(editor: Editor) {
|
||||
|
||||
fun CommandState.Mode.resetShape(editor: Editor) = when (this) {
|
||||
CommandState.Mode.COMMAND, CommandState.Mode.VISUAL, CommandState.Mode.REPLACE -> ChangeGroup.resetCaret(editor, false)
|
||||
CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, true)
|
||||
CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor)
|
||||
CommandState.Mode.CMD_LINE, CommandState.Mode.OP_PENDING -> Unit
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
@@ -43,6 +43,12 @@ import static java.lang.Integer.max;
|
||||
* This is a set of helper methods for working with editors. All line and column values are zero based.
|
||||
*/
|
||||
public class EditorHelper {
|
||||
// Set a max height on block inlays to be made visible at the top/bottom of a line when scrolling up/down. This
|
||||
// mitigates the visible area bouncing around too much and even pushing the cursor line off screen with large
|
||||
// multiline rendered doc comments, while still providing some visibility of the block inlay (e.g. Rider's single line
|
||||
// Code Vision)
|
||||
private static final int BLOCK_INLAY_MAX_LINE_HEIGHT = 3;
|
||||
|
||||
public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) {
|
||||
return editor.getScrollingModel().getVisibleAreaOnScrollingFinished();
|
||||
}
|
||||
@@ -201,7 +207,7 @@ public class EditorHelper {
|
||||
* @param editor The editor
|
||||
* @return The number of screen lines
|
||||
*/
|
||||
private static int getApproximateScreenHeight(final @NotNull Editor editor) {
|
||||
public static int getApproximateScreenHeight(final @NotNull Editor editor) {
|
||||
return getVisibleArea(editor).height / editor.getLineHeight();
|
||||
}
|
||||
|
||||
@@ -641,7 +647,10 @@ public class EditorHelper {
|
||||
* @return Returns true if the window was moved
|
||||
*/
|
||||
public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) {
|
||||
int y = EditorUtil.getVisualLineAreaStartY(editor, normalizeVisualLine(editor, visualLine));
|
||||
|
||||
final int inlayHeight = EditorUtil.getInlaysHeight(editor, visualLine, true);
|
||||
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * editor.getLineHeight();
|
||||
int y = editor.visualLineToY(visualLine) - Math.min(inlayHeight, maxInlayHeight);
|
||||
|
||||
// Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this,
|
||||
// but when we ask for the target location to move the caret to match, we'll get the incorrect value.
|
||||
@@ -653,7 +662,7 @@ public class EditorHelper {
|
||||
// Get the max line number that can sit at the top of the screen
|
||||
final int editorHeight = getVisibleArea(editor).height;
|
||||
final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight();
|
||||
final int yLastLine = editor.visualLineToY(EditorHelper.getLineCount(editor)); // last line + 1
|
||||
final int yLastLine = editor.visualLineToY(getLineCount(editor)); // last line + 1
|
||||
y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight);
|
||||
}
|
||||
return scrollVertically(editor, y);
|
||||
@@ -662,21 +671,25 @@ public class EditorHelper {
|
||||
/**
|
||||
* Scrolls the editor to place the given visual line in the middle of the current window.
|
||||
*
|
||||
* <p>Snaps the line to the nearest standard line height grid, which gives a good position for both an odd and even
|
||||
* number of lines and mimics what Vim does.</p>
|
||||
*
|
||||
* @param editor The editor to scroll
|
||||
* @param visualLine The visual line to place in the middle of the current window
|
||||
*/
|
||||
public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) {
|
||||
int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
|
||||
int lineHeight = editor.getLineHeight();
|
||||
int height = getVisibleArea(editor).height;
|
||||
scrollVertically(editor, y - ((height - lineHeight) / 2));
|
||||
final int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
|
||||
final int screenHeight = getVisibleArea(editor).height;
|
||||
final int lineHeight = editor.getLineHeight();
|
||||
scrollVertically(editor, y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the editor to place the given visual line at the bottom of the screen.
|
||||
*
|
||||
* When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to place a
|
||||
* line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll to.
|
||||
* <p>When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to
|
||||
* place a line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll
|
||||
* to.</p>
|
||||
*
|
||||
* @param editor The editor to scroll
|
||||
* @param visualLine The visual line to place at the bottom of the current window
|
||||
@@ -690,7 +703,12 @@ public class EditorHelper {
|
||||
if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) {
|
||||
exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight();
|
||||
}
|
||||
final int y = EditorUtil.getVisualLineAreaEndY(editor, normalizeVisualLine(editor, visualLine)) + exPanelHeight;
|
||||
|
||||
final int normalizedVisualLine = normalizeVisualLine(editor, visualLine);
|
||||
final int lineHeight = editor.getLineHeight();
|
||||
final int inlayHeight = EditorUtil.getInlaysHeight(editor, normalizedVisualLine, false);
|
||||
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * lineHeight;
|
||||
final int y = editor.visualLineToY(normalizedVisualLine) + lineHeight + Math.min(inlayHeight, maxInlayHeight) + exPanelHeight;
|
||||
final Rectangle visibleArea = getVisibleArea(editor);
|
||||
return scrollVertically(editor, max(0, y - visibleArea.height));
|
||||
}
|
||||
@@ -714,19 +732,19 @@ public class EditorHelper {
|
||||
}
|
||||
|
||||
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
|
||||
EditorHelper.scrollHorizontally(editor, columnLeftX);
|
||||
scrollHorizontally(editor, columnLeftX);
|
||||
}
|
||||
|
||||
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
||||
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
|
||||
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
|
||||
final int screenWidth = getVisibleArea(editor).width;
|
||||
|
||||
// Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number
|
||||
// of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is
|
||||
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
|
||||
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
|
||||
final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth);
|
||||
EditorHelper.scrollHorizontally(editor, x);
|
||||
scrollHorizontally(editor, x);
|
||||
}
|
||||
|
||||
public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
||||
@@ -751,8 +769,8 @@ public class EditorHelper {
|
||||
|
||||
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
|
||||
final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
|
||||
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
|
||||
EditorHelper.scrollHorizontally(editor, targetColumnRightX - screenWidth);
|
||||
final int screenWidth = getVisibleArea(editor).width;
|
||||
scrollHorizontally(editor, targetColumnRightX - screenWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,11 +46,11 @@ val Editor.isIdeaVimDisabledHere: Boolean
|
||||
val timeForCalculation = measureTimeMillis {
|
||||
res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|
||||
|
||||
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|
||||
|| (!OptionsManager.ideavimsupport.contains("singleline")
|
||||
.apply { times += System.currentTimeMillis() to "first single line check" }
|
||||
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|
||||
|
||||
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|
||||
|| (!OptionsManager.ideavimsupport.contains("singleline")
|
||||
.apply { times += System.currentTimeMillis() to "second single line check" }
|
||||
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
|
||||
)
|
||||
@@ -68,7 +68,7 @@ private fun Editor.isDatabaseCell(times: MutableList<Pair<Long, String>>): Boole
|
||||
}
|
||||
|
||||
private val Editor.disabledInDialog: Boolean
|
||||
get() = (!OptionsManager.ideaenabledbufs.contains("dialog") && !OptionsManager.ideaenabledbufs.contains("dialoglegacy"))
|
||||
get() = (!OptionsManager.ideavimsupport.contains("dialog") && !OptionsManager.ideavimsupport.contains("dialoglegacy"))
|
||||
&& (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this))
|
||||
|
||||
/**
|
||||
|
@@ -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,16 +542,19 @@ public class SearchHelper {
|
||||
selectionEndWithoutNewline++;
|
||||
}
|
||||
|
||||
if (closingTagTextRange.getStartOffset() == selectionEndWithoutNewline &&
|
||||
final CommandState.Mode mode = CommandState.getInstance(editor).getMode();
|
||||
if (mode == CommandState.Mode.VISUAL) {
|
||||
if (closingTagTextRange.getStartOffset() == selectionEndWithoutNewline &&
|
||||
openingTag.getEndOffset() == selectionStart) {
|
||||
// Special case: if the inner tag is already selected we should like isOuter is active
|
||||
// Note that we need to ignore newlines, because their selection is lost between multiple "it" invocations
|
||||
isOuter = true;
|
||||
}
|
||||
else if (openingTag.getEndOffset() == closingTagTextRange.getStartOffset() &&
|
||||
selectionStart == openingTag.getEndOffset()) {
|
||||
// Special case: for an empty tag pair (e.g. <a></a>) the whole tag is selected if the caret is in the middle.
|
||||
isOuter = true;
|
||||
// Special case: if the inner tag is already selected we should like isOuter is active
|
||||
// Note that we need to ignore newlines, because their selection is lost between multiple "it" invocations
|
||||
isOuter = true;
|
||||
}
|
||||
else if (openingTag.getEndOffset() == closingTagTextRange.getStartOffset() &&
|
||||
selectionStart == openingTag.getEndOffset()) {
|
||||
// Special case: for an empty tag pair (e.g. <a></a>) the whole tag is selected if the caret is in the middle.
|
||||
isOuter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isOuter) {
|
||||
@@ -786,7 +790,7 @@ public class SearchHelper {
|
||||
if (pos == size - 1 ||
|
||||
!Character.isLetter(chars.charAt(pos + 1)) ||
|
||||
(Character.isUpperCase(chars.charAt(pos + 1)) &&
|
||||
pos <= size - 2 &&
|
||||
pos < size - 2 &&
|
||||
Character.isLowerCase(chars.charAt(pos + 2)))) {
|
||||
res = pos;
|
||||
found++;
|
||||
@@ -1375,7 +1379,7 @@ public class SearchHelper {
|
||||
}
|
||||
|
||||
if (goForward && anyNonWhitespace(editor, end, 1)) {
|
||||
while (end < max &&
|
||||
while (end + 1 < max &&
|
||||
CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) {
|
||||
end++;
|
||||
}
|
||||
|
@@ -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 -> {
|
||||
List<KeyStroke> prefix = new ArrayList<>();
|
||||
final int prefixLength = keys.size() - 1;
|
||||
for (int i = 0; i < prefixLength; i++) {
|
||||
prefix.add(keys.get(i));
|
||||
myPrefixes.remove(prefix);
|
||||
}
|
||||
});
|
||||
toRemove.stream().map(Map.Entry::getKey).forEach(this::removePrefixes);
|
||||
}
|
||||
|
||||
public void delete(@NotNull List<KeyStroke> keys) {
|
||||
MappingInfo removed = myKeys.remove(keys);
|
||||
if (removed == null) return;
|
||||
|
||||
removePrefixes(keys);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
myKeys.clear();
|
||||
myPrefixes.clear();
|
||||
}
|
||||
|
||||
private void removePrefixes(@NotNull List<KeyStroke> keys) {
|
||||
List<KeyStroke> prefix = new ArrayList<>();
|
||||
final int prefixLength = keys.size() - 1;
|
||||
for (int i = 0; i < prefixLength; i++) {
|
||||
prefix.add(keys.get(i));
|
||||
myPrefixes.remove(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Pair<List<KeyStroke>, MappingInfo>> getByOwner(@NotNull MappingOwner owner) {
|
||||
|
@@ -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";
|
||||
}
|
||||
}
|
||||
|
@@ -50,6 +50,7 @@ import com.maddyhome.idea.vim.helper.commandState
|
||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||
import com.maddyhome.idea.vim.helper.inNormalMode
|
||||
import com.maddyhome.idea.vim.option.IdeaRefactorMode
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.beans.PropertyChangeEvent
|
||||
import java.beans.PropertyChangeListener
|
||||
|
||||
@@ -66,6 +67,7 @@ object IdeaSpecifics {
|
||||
}
|
||||
|
||||
class VimActionListener : AnActionListener {
|
||||
@NonNls
|
||||
private val surrounderItems = listOf("if", "if / else", "for")
|
||||
private val surrounderAction = "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
|
||||
private var editor: Editor? = null
|
||||
|
@@ -68,7 +68,7 @@ import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add
|
||||
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.remove
|
||||
import com.maddyhome.idea.vim.option.OptionsManager
|
||||
import com.maddyhome.idea.vim.option.StrictMode
|
||||
import com.maddyhome.idea.vim.ui.ExEntryPanel
|
||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
|
||||
import com.maddyhome.idea.vim.ui.ShowCmdOptionChangeListener
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
@@ -106,6 +106,7 @@ object VimListenerManager {
|
||||
|
||||
OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||
OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||
OptionsManager.scrolloff.addOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
|
||||
OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener)
|
||||
|
||||
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
|
||||
@@ -116,6 +117,7 @@ object VimListenerManager {
|
||||
|
||||
OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||
OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||
OptionsManager.scrolloff.removeOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
|
||||
OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener)
|
||||
|
||||
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
|
||||
@@ -251,11 +253,11 @@ object VimListenerManager {
|
||||
if (onLineEnd(caret)) {
|
||||
// UX protection for case when user performs a small dragging while putting caret on line end
|
||||
caret.removeSelection()
|
||||
ChangeGroup.resetCaret(e.editor, true)
|
||||
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor)
|
||||
}
|
||||
}
|
||||
if (mouseDragging && e.editor.caretModel.primaryCaret.hasSelection()) {
|
||||
ChangeGroup.resetCaret(e.editor, true)
|
||||
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor)
|
||||
|
||||
if (!cutOffFixed && ComponentMouseListener.cutOffEnd) {
|
||||
cutOffFixed = true
|
||||
|
@@ -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;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user