mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-18 10:31:44 +02:00
Compare commits
19 Commits
customized
...
customized
Author | SHA1 | Date | |
---|---|---|---|
c79286b9b0
|
|||
5f59b47b19
|
|||
8d51537f79
|
|||
052de10e3a
|
|||
9ece9a7a04
|
|||
84c868afc3
|
|||
f29ebab390
|
|||
0cb8bba3fd
|
|||
c0ff2b5cd0
|
|||
460234553d
|
|||
cdd5b2abaf
|
|||
9db1732eb3
|
|||
63e292b21f
|
|||
362175431d
|
|||
5e2cab4eda
|
|||
b63792c8f8
|
|||
f543b6a1d1
|
|||
d367b3bc72
|
|||
da2d8d707f
|
2
.github/workflows/integrationsTest.yml
vendored
2
.github/workflows/integrationsTest.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: ./gradlew --no-configuration-cache integrationsTest
|
run: ./gradlew integrationsTest
|
||||||
env:
|
env:
|
||||||
YOUTRACK_TOKEN: ${{ secrets.YOUTRACK_TOKEN }}
|
YOUTRACK_TOKEN: ${{ secrets.YOUTRACK_TOKEN }}
|
||||||
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
12
.github/workflows/runUiOctopusTests.yml
vendored
12
.github/workflows/runUiOctopusTests.yml
vendored
@@ -16,14 +16,14 @@ jobs:
|
|||||||
java-version: 17
|
java-version: 17
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
run: brew install ffmpeg
|
run: brew install ffmpeg
|
||||||
# - name: Setup Gradle
|
- name: Setup Gradle
|
||||||
# uses: gradle/gradle-build-action@v2.4.2
|
uses: gradle/gradle-build-action@v2.4.2
|
||||||
- name: Build Plugin
|
- name: Build Plugin
|
||||||
run: gradle :buildPlugin
|
run: gradle :buildPlugin
|
||||||
- name: Run Idea
|
- name: Run Idea
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/reports
|
mkdir -p build/reports
|
||||||
gradle --no-configuration-cache runIdeForUiTests -Doctopus.handler=false > build/reports/idea.log &
|
gradle runIdeForUiTests -Doctopus.handler=false > build/reports/idea.log &
|
||||||
- name: Wait for Idea started
|
- name: Wait for Idea started
|
||||||
uses: jtalk/url-health-check-action@v3
|
uses: jtalk/url-health-check-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
run: mv tests/ui-ij-tests/video build/reports
|
run: mv tests/ui-ij-tests/video build/reports
|
||||||
- name: Move sandbox logs
|
- name: Move sandbox logs
|
||||||
if: always()
|
if: always()
|
||||||
run: mv build/idea-sandbox/IC-2024.1.2/log_runIdeForUiTests idea-sandbox-log
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
- name: Save report
|
- name: Save report
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
build/reports
|
build/reports
|
||||||
tests/ui-ij-tests/build/reports
|
tests/ui-ij-tests/build/reports
|
||||||
idea-sandbox-log
|
sandbox-idea-log
|
||||||
# build-for-ui-test-linux:
|
# build-for-ui-test-linux:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
# steps:
|
# steps:
|
||||||
@@ -78,4 +78,4 @@ jobs:
|
|||||||
# with:
|
# with:
|
||||||
# name: ui-test-fails-report-linux
|
# name: ui-test-fails-report-linux
|
||||||
# path: |
|
# path: |
|
||||||
# ui-test-example/build/reports
|
# ui-test-example/build/reports
|
10
.github/workflows/runUiPyTests.yml
vendored
10
.github/workflows/runUiPyTests.yml
vendored
@@ -19,14 +19,14 @@ jobs:
|
|||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
run: brew install ffmpeg
|
run: brew install ffmpeg
|
||||||
# - name: Setup Gradle
|
- name: Setup Gradle
|
||||||
# uses: gradle/gradle-build-action@v2.4.2
|
uses: gradle/gradle-build-action@v2.4.2
|
||||||
- name: Build Plugin
|
- name: Build Plugin
|
||||||
run: gradle :buildPlugin
|
run: gradle :buildPlugin
|
||||||
- name: Run Idea
|
- name: Run Idea
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/reports
|
mkdir -p build/reports
|
||||||
gradle --no-configuration-cache :runIdeForUiTests -PideaType=PC > build/reports/idea.log &
|
gradle :runIdeForUiTests -PideaType=PC > build/reports/idea.log &
|
||||||
- name: Wait for Idea started
|
- name: Wait for Idea started
|
||||||
uses: jtalk/url-health-check-action@v3
|
uses: jtalk/url-health-check-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
run: mv tests/ui-py-tests/video build/reports
|
run: mv tests/ui-py-tests/video build/reports
|
||||||
- name: Move sandbox logs
|
- name: Move sandbox logs
|
||||||
if: always()
|
if: always()
|
||||||
run: mv build/idea-sandbox/PC-2024.1.2/log_runIdeForUiTests idea-sandbox-log
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
- name: Save report
|
- name: Save report
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -49,4 +49,4 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
build/reports
|
build/reports
|
||||||
tests/ui-py-tests/build/reports
|
tests/ui-py-tests/build/reports
|
||||||
idea-sandbox-log
|
sandbox-idea-log
|
12
.github/workflows/runUiTests.yml
vendored
12
.github/workflows/runUiTests.yml
vendored
@@ -16,14 +16,14 @@ jobs:
|
|||||||
java-version: 17
|
java-version: 17
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
run: brew install ffmpeg
|
run: brew install ffmpeg
|
||||||
# - name: Setup Gradle
|
- name: Setup Gradle
|
||||||
# uses: gradle/gradle-build-action@v2.4.2
|
uses: gradle/gradle-build-action@v2.4.2
|
||||||
- name: Build Plugin
|
- name: Build Plugin
|
||||||
run: gradle :buildPlugin
|
run: gradle :buildPlugin
|
||||||
- name: Run Idea
|
- name: Run Idea
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/reports
|
mkdir -p build/reports
|
||||||
gradle --no-configuration-cache runIdeForUiTests > build/reports/idea.log &
|
gradle runIdeForUiTests > build/reports/idea.log &
|
||||||
- name: Wait for Idea started
|
- name: Wait for Idea started
|
||||||
uses: jtalk/url-health-check-action@v3
|
uses: jtalk/url-health-check-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
run: mv tests/ui-ij-tests/video build/reports
|
run: mv tests/ui-ij-tests/video build/reports
|
||||||
- name: Move sandbox logs
|
- name: Move sandbox logs
|
||||||
if: always()
|
if: always()
|
||||||
run: mv build/idea-sandbox/IC-2024.1.2/log_runIdeForUiTests idea-sandbox-log
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
- name: Save report
|
- name: Save report
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
build/reports
|
build/reports
|
||||||
tests/ui-ij-tests/build/reports
|
tests/ui-ij-tests/build/reports
|
||||||
idea-sandbox-log
|
sandbox-idea-log
|
||||||
# build-for-ui-test-linux:
|
# build-for-ui-test-linux:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
# steps:
|
# steps:
|
||||||
@@ -78,4 +78,4 @@ jobs:
|
|||||||
# with:
|
# with:
|
||||||
# name: ui-test-fails-report-linux
|
# name: ui-test-fails-report-linux
|
||||||
# path: |
|
# path: |
|
||||||
# ui-test-example/build/reports
|
# ui-test-example/build/reports
|
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
*.swp
|
*.swp
|
||||||
/.gradle/
|
/.gradle/
|
||||||
/.intellijPlatform/
|
|
||||||
|
|
||||||
/.idea/
|
/.idea/
|
||||||
!/.idea/scopes
|
!/.idea/scopes
|
||||||
@@ -27,8 +26,9 @@
|
|||||||
# Generated by gradle task "generateGrammarSource"
|
# Generated by gradle task "generateGrammarSource"
|
||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
|
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
|
||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
||||||
|
# Generated JSONs for lazy classloading
|
||||||
|
/vim-engine/src/main/resources/ksp-generated
|
||||||
|
/src/main/resources/ksp-generated
|
||||||
|
|
||||||
# Created by github automation
|
# Created by github automation
|
||||||
settings.xml
|
settings.xml
|
||||||
|
|
||||||
.kotlin
|
|
@@ -12,7 +12,7 @@
|
|||||||
<option name="taskNames">
|
<option name="taskNames">
|
||||||
<list>
|
<list>
|
||||||
<option value="check" />
|
<option value="check" />
|
||||||
<option value="verifyPlugin" />
|
<option value="runPluginVerifier" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" value="" />
|
<option name="vmOptions" value="" />
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
<DebugAllEnabled>false</DebugAllEnabled>
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
<RunAsTest>false</RunAsTest>
|
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
2
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
2
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
@@ -37,7 +37,7 @@ object Compatibility : IdeaVimBuildType({
|
|||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
|
||||||
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
|
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
|
||||||
# java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
2
.teamcity/_Self/buildTypes/PluginVerifier.kt
vendored
2
.teamcity/_Self/buildTypes/PluginVerifier.kt
vendored
@@ -22,7 +22,7 @@ object PluginVerifier : IdeaVimBuildType({
|
|||||||
|
|
||||||
steps {
|
steps {
|
||||||
gradle {
|
gradle {
|
||||||
tasks = "clean verifyPlugin"
|
tasks = "clean runPluginVerifier"
|
||||||
buildFile = ""
|
buildFile = ""
|
||||||
enableStacktrace = true
|
enableStacktrace = true
|
||||||
}
|
}
|
||||||
|
1
.teamcity/_Self/buildTypes/ReleasePlugin.kt
vendored
1
.teamcity/_Self/buildTypes/ReleasePlugin.kt
vendored
@@ -144,7 +144,6 @@ sealed class ReleasePlugin(private val releaseType: String) : IdeaVimBuildType({
|
|||||||
gradle {
|
gradle {
|
||||||
name = "Run Integrations"
|
name = "Run Integrations"
|
||||||
tasks = "releaseActions"
|
tasks = "releaseActions"
|
||||||
gradleParams = "--no-configuration-cache"
|
|
||||||
}
|
}
|
||||||
// gradle {
|
// gradle {
|
||||||
// name = "Slack Notification"
|
// name = "Slack Notification"
|
||||||
|
12
AUTHORS.md
12
AUTHORS.md
@@ -523,18 +523,6 @@ Contributors:
|
|||||||
[![icon][github]](https://github.com/LazyScaper)
|
[![icon][github]](https://github.com/LazyScaper)
|
||||||
|
|
||||||
Jake
|
Jake
|
||||||
* [![icon][mail]](mailto:the1xdeveloper@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/The1xDeveloper)
|
|
||||||
|
|
||||||
The1xDeveloper
|
|
||||||
* [![icon][mail]](mailto:shaunewilliams@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/shaunlebron)
|
|
||||||
|
|
||||||
shaun
|
|
||||||
* [![icon][mail]](mailto:i.i.babko@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/igorbabko)
|
|
||||||
|
|
||||||
Igor Babko
|
|
||||||
|
|
||||||
Previous contributors:
|
Previous contributors:
|
||||||
|
|
||||||
|
@@ -27,8 +27,8 @@ usual beta standards.
|
|||||||
|
|
||||||
Since version 2.9.0, the changelog can be found on YouTrack
|
Since version 2.9.0, the changelog can be found on YouTrack
|
||||||
|
|
||||||
* [To Be Released](https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20)
|
To Be Released: https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20
|
||||||
* [Version Fixes](https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20%7BFix%20versions%7D%20asc)
|
Latest Fixes: https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20updated%20
|
||||||
|
|
||||||
## 2.9.0, 2024-02-20
|
## 2.9.0, 2024-02-20
|
||||||
|
|
||||||
|
@@ -62,16 +62,12 @@ for a few days or send it to a friend for testing.
|
|||||||
If you are looking for:
|
If you are looking for:
|
||||||
|
|
||||||
- Vim commands (`w`, `<C-O>`, `p`, etc.):
|
- Vim commands (`w`, `<C-O>`, `p`, etc.):
|
||||||
- Any particular command:
|
- Any particular command: `package-info.java`.
|
||||||
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_commands.json)
|
|
||||||
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_commands.json)
|
|
||||||
- How commands are executed in common: `EditorActionHandlerBase`.
|
- How commands are executed in common: `EditorActionHandlerBase`.
|
||||||
- Key mapping: `KeyHandler.handleKey()`.
|
- Key mapping: `KeyHandler.handleKey()`.
|
||||||
|
|
||||||
- Ex commands (`:set`, `:s`, `:nohlsearch`):
|
- Ex commands (`:set`, `:s`, `:nohlsearch`):
|
||||||
- Any particular command:
|
- Any particular ex command: package `com.maddyhome.idea.vim.ex.handler`.
|
||||||
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_ex_commands.json)
|
|
||||||
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_ex_commands.json)
|
|
||||||
- Vim script grammar: `Vimscript.g4`.
|
- Vim script grammar: `Vimscript.g4`.
|
||||||
- Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
|
- Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
|
||||||
- Vim script executor: `Executor`.
|
- Vim script executor: `Executor`.
|
||||||
|
@@ -109,6 +109,7 @@ etc
|
|||||||
|
|
||||||
See also:
|
See also:
|
||||||
|
|
||||||
|
* [The list of all supported commands](src/main/java/com/maddyhome/idea/vim/package-info.java)
|
||||||
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
|
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
|
||||||
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
|
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
|
||||||
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
|
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
|
||||||
@@ -221,13 +222,13 @@ Ex commands or via `:map` command mappings:
|
|||||||
* Execute an action by `{action_id}`. Works from Ex command line.
|
* Execute an action by `{action_id}`. Works from Ex command line.
|
||||||
* Please don't use `:action` in mappings. Use `<Action>` instead.
|
* Please don't use `:action` in mappings. Use `<Action>` instead.
|
||||||
|
|
||||||
### Finding action IDs:
|
### Finding action ids:
|
||||||
|
|
||||||
* IJ provides `IdeaVim: track action IDs` command to show the id of the executed actions.
|
* IJ provides `IdeaVim: track action Ids` command to show the id of the executed actions.
|
||||||
This command can be found in "Search everywhere" (double `shift`).
|
This command can be found in "Search everywhere" (double `shift`).
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>"Track action IDs" Details</strong> (click to see)</summary>
|
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
|
||||||
<picture>
|
<picture>
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="assets/readme/track_action_dark.gif">
|
<source media="(prefers-color-scheme: dark)" srcset="assets/readme/track_action_dark.gif">
|
||||||
<img src="assets/readme/track_action_light.gif" alt="track action ids"/>
|
<img src="assets/readme/track_action_light.gif" alt="track action ids"/>
|
||||||
@@ -368,8 +369,6 @@ is the full list of synonyms.
|
|||||||
- Fancy constants for [undolevels](https://vimhelp.org/options.txt.html#%27undolevels%27):
|
- Fancy constants for [undolevels](https://vimhelp.org/options.txt.html#%27undolevels%27):
|
||||||
> The local value is set to -123456 when the global value is to be used.
|
> The local value is set to -123456 when the global value is to be used.
|
||||||
|
|
||||||
- Vi (not Vim) is a POSIX standard, and [has a spec](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html)! Vim is mostly POSIX compliant when Vi compatibility is selected with the `'compatible'` option, but there are still some differences that can be changed with `'copoptions'`. The spec is interesting because it documents the behaviour of different commands in a stricter style than the user documentation, describing the current line and column after the command, for example. [More details can be found by reading `:help posix`](https://vimhelp.org/vi_diff.txt.html#posix).
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
kotlin("plugin.serialization") version "2.0.0"
|
kotlin("plugin.serialization") version "1.9.22"
|
||||||
}
|
}
|
||||||
|
|
||||||
val kotlinxSerializationVersion: String by project
|
val kotlinxSerializationVersion: String by project
|
||||||
@@ -21,7 +21,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.24")
|
compileOnly("com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.22")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") {
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") {
|
||||||
// kotlin stdlib is provided by IJ, so there is no need to include it into the distribution
|
// kotlin stdlib is provided by IJ, so there is no need to include it into the distribution
|
||||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||||
|
@@ -37,8 +37,7 @@ class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironme
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
|
||||||
val sortedCommands = commands.sortedWith(compareBy({ it.keys }, { it.`class` }))
|
val fileContent = json.encodeToString(commands)
|
||||||
val fileContent = json.encodeToString(sortedCommands)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
@@ -37,8 +37,7 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
|
||||||
val sortedCommandToClass = commandToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
|
val fileContent = json.encodeToString(commandToClass)
|
||||||
val fileContent = json.encodeToString(sortedCommandToClass)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
@@ -37,8 +37,7 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
|
||||||
val sortedNameToClass = nameToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
|
val fileContent = json.encodeToString(nameToClass)
|
||||||
val fileContent = json.encodeToString(sortedNameToClass)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
203
build.gradle.kts
203
build.gradle.kts
@@ -32,8 +32,6 @@ import org.eclipse.jgit.api.Git
|
|||||||
import org.eclipse.jgit.lib.RepositoryBuilder
|
import org.eclipse.jgit.lib.RepositoryBuilder
|
||||||
import org.intellij.markdown.ast.getTextInNode
|
import org.intellij.markdown.ast.getTextInNode
|
||||||
import org.jetbrains.changelog.Changelog
|
import org.jetbrains.changelog.Changelog
|
||||||
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
|
|
||||||
import org.jetbrains.intellij.platform.gradle.tasks.aware.SplitModeAware
|
|
||||||
import org.kohsuke.github.GHUser
|
import org.kohsuke.github.GHUser
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@@ -45,7 +43,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
|
||||||
classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2")
|
classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2")
|
||||||
classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
||||||
|
|
||||||
@@ -66,23 +64,25 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
kotlin("jvm") version "2.0.0"
|
kotlin("jvm") version "1.9.22"
|
||||||
application
|
application
|
||||||
id("java-test-fixtures")
|
id("java-test-fixtures")
|
||||||
id("org.jetbrains.intellij.platform") version "2.0.0-rc2"
|
|
||||||
id("org.jetbrains.changelog") version "2.2.1"
|
id("org.jetbrains.intellij") version "1.17.3"
|
||||||
|
id("org.jetbrains.changelog") version "2.2.0"
|
||||||
|
|
||||||
id("org.jetbrains.kotlinx.kover") version "0.6.1"
|
id("org.jetbrains.kotlinx.kover") version "0.6.1"
|
||||||
id("com.dorongold.task-tree") version "4.0.0"
|
id("com.dorongold.task-tree") version "4.0.0"
|
||||||
id("com.google.devtools.ksp") version "2.0.0-1.0.23"
|
|
||||||
}
|
|
||||||
|
|
||||||
val moduleSources by configurations.registering
|
id("com.google.devtools.ksp") version "1.9.22-1.0.17"
|
||||||
|
}
|
||||||
|
|
||||||
// Import variables from gradle.properties file
|
// Import variables from gradle.properties file
|
||||||
val javaVersion: String by project
|
val javaVersion: String by project
|
||||||
val kotlinVersion: String by project
|
val kotlinVersion: String by project
|
||||||
val ideaVersion: String by project
|
val ideaVersion: String by project
|
||||||
val ideaType: String by project
|
val ideaType: String by project
|
||||||
|
val downloadIdeaSources: String by project
|
||||||
val instrumentPluginCode: String by project
|
val instrumentPluginCode: String by project
|
||||||
val remoteRobotVersion: String by project
|
val remoteRobotVersion: String by project
|
||||||
val splitModeVersion: String by project
|
val splitModeVersion: String by project
|
||||||
@@ -97,9 +97,7 @@ val releaseType: String? by project
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
intellijPlatform {
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
defaultRepositories()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -110,28 +108,10 @@ dependencies {
|
|||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
compileOnly("org.jetbrains:annotations:24.1.0")
|
compileOnly("org.jetbrains:annotations:24.1.0")
|
||||||
|
|
||||||
intellijPlatform {
|
|
||||||
// Note that it is also possible to use local("...") to compile against a locally installed IDE
|
|
||||||
// E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
|
|
||||||
// Or something like: intellijIdeaUltimate(ideaVersion)
|
|
||||||
create(ideaType, ideaVersion)
|
|
||||||
|
|
||||||
pluginVerifier()
|
|
||||||
zipSigner()
|
|
||||||
instrumentationTools()
|
|
||||||
|
|
||||||
testFramework(TestFrameworkType.Platform)
|
|
||||||
testFramework(TestFrameworkType.JUnit5)
|
|
||||||
|
|
||||||
// AceJump is an optional dependency. We use their SessionManager class to check if it's active
|
|
||||||
plugin("AceJump", "3.8.19")
|
|
||||||
plugin("com.intellij.classic.ui", "242.20224.159")
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
|
|
||||||
|
|
||||||
// --------- Test dependencies ----------
|
// --------- Test dependencies ----------
|
||||||
|
|
||||||
|
testImplementation(testFixtures(project(":")))
|
||||||
|
|
||||||
testApi("com.squareup.okhttp3:okhttp:4.12.0")
|
testApi("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/com.ensarsarajcic.neovim.java/neovim-api
|
// https://mvnrepository.com/artifact/com.ensarsarajcic.neovim.java/neovim-api
|
||||||
@@ -145,7 +125,7 @@ dependencies {
|
|||||||
testFixturesImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
testFixturesImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
||||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
|
testImplementation("org.mockito.kotlin:mockito-kotlin:5.3.1")
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
||||||
@@ -153,12 +133,6 @@ dependencies {
|
|||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
|
||||||
|
|
||||||
// Temp workaround suggested in https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4
|
|
||||||
// Can be removed when IJPL-159134 is fixed
|
|
||||||
// testRuntimeOnly("junit:junit:4.13.2")
|
|
||||||
testImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
|
|
||||||
// testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@@ -198,94 +172,60 @@ tasks {
|
|||||||
// See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library
|
// See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library
|
||||||
// For the list of bundled versions
|
// For the list of bundled versions
|
||||||
apiVersion = "1.9"
|
apiVersion = "1.9"
|
||||||
freeCompilerArgs = listOf(
|
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
|
||||||
"-Xjvm-default=all-compatibility",
|
|
||||||
|
|
||||||
// Needed to compile the AceJump which uses kotlin beta
|
|
||||||
// Without these two option compilation fails
|
|
||||||
"-Xskip-prerelease-check",
|
|
||||||
"-Xallow-unstable-dependencies",
|
|
||||||
)
|
|
||||||
// allWarningsAsErrors = true
|
// allWarningsAsErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileTestKotlin {
|
compileTestKotlin {
|
||||||
enabled = false
|
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = javaVersion
|
jvmTarget = javaVersion
|
||||||
apiVersion = "1.9"
|
apiVersion = "1.9"
|
||||||
|
|
||||||
// Needed to compile the AceJump which uses kotlin beta
|
|
||||||
// Without these two option compilation fails
|
|
||||||
freeCompilerArgs += listOf("-Xskip-prerelease-check", "-Xallow-unstable-dependencies")
|
|
||||||
// allWarningsAsErrors = true
|
// allWarningsAsErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that this will run the plugin installed in the IDE specified in dependencies. To run in a different IDE, use
|
|
||||||
// a custom task (see below)
|
|
||||||
runIde {
|
runIde {
|
||||||
systemProperty("octopus.handler", System.getProperty("octopus.handler") ?: true)
|
systemProperty("octopus.handler", System.getProperty("octopus.handler") ?: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
|
downloadRobotServerPlugin {
|
||||||
// Note that the version must be greater than the plugin's target version, for obvious reasons
|
version.set(remoteRobotVersion)
|
||||||
// val runIdeCustom by intellijPlatformTesting.runIde.registering {
|
|
||||||
// type = IntelliJPlatformType.Rider
|
|
||||||
// version = "2024.1.2"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Uncomment to run the plugin in a locally installed IDE
|
|
||||||
// val runIdeLocal by intellijPlatformTesting.runIde.registering {
|
|
||||||
// localPath = file("/Users/{user}/Applications/WebStorm.app")
|
|
||||||
// }
|
|
||||||
|
|
||||||
val runIdeForUiTests by intellijPlatformTesting.runIde.registering {
|
|
||||||
task {
|
|
||||||
jvmArgumentProviders += CommandLineArgumentProvider {
|
|
||||||
listOf(
|
|
||||||
"-Drobot-server.port=8082",
|
|
||||||
"-Dide.mac.message.dialogs.as.sheets=false",
|
|
||||||
"-Djb.privacy.policy.text=<!--999.999-->",
|
|
||||||
"-Djb.consents.confirmation.enabled=false",
|
|
||||||
"-Dide.show.tips.on.startup.default.value=false",
|
|
||||||
"-Doctopus.handler=" + (System.getProperty("octopus.handler") ?: true),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
robotServerPlugin(remoteRobotVersion)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
|
runIdeForUiTests {
|
||||||
splitMode = true
|
systemProperty("robot-server.port", "8082")
|
||||||
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
|
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
|
||||||
|
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
|
||||||
|
systemProperty("jb.consents.confirmation.enabled", "false")
|
||||||
|
systemProperty("ide.show.tips.on.startup.default.value", "false")
|
||||||
|
|
||||||
// Frontend split mode support requires 242+
|
systemProperty("octopus.handler", System.getProperty("octopus.handler") ?: true)
|
||||||
// TODO: Remove this once IdeaVim targets 242, as the task will naturally use the target version to run
|
|
||||||
version.set(splitModeVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add plugin open API sources to the plugin ZIP
|
// Add plugin open API sources to the plugin ZIP
|
||||||
val sourcesJar by registering(Jar::class) {
|
val createOpenApiSourceJar by registering(Jar::class) {
|
||||||
dependsOn(moduleSources)
|
// Java sources
|
||||||
|
from(sourceSets.main.get().java) {
|
||||||
|
include("**/com/maddyhome/idea/vim/**/*.java")
|
||||||
|
}
|
||||||
|
from(project(":vim-engine").sourceSets.main.get().java) {
|
||||||
|
include("**/com/maddyhome/idea/vim/**/*.java")
|
||||||
|
}
|
||||||
|
// Kotlin sources
|
||||||
|
from(kotlin.sourceSets.main.get().kotlin) {
|
||||||
|
include("**/com/maddyhome/idea/vim/**/*.kt")
|
||||||
|
}
|
||||||
|
from(project(":vim-engine").kotlin.sourceSets.main.get().kotlin) {
|
||||||
|
include("**/com/maddyhome/idea/vim/**/*.kt")
|
||||||
|
}
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("libs"))
|
destinationDirectory.set(layout.buildDirectory.dir("libs"))
|
||||||
archiveClassifier.set(DocsType.SOURCES)
|
archiveClassifier.set("src")
|
||||||
from(sourceSets.main.map { it.kotlin })
|
|
||||||
from(provider {
|
|
||||||
moduleSources.map {
|
|
||||||
it.map { jarFile -> zipTree(jarFile) }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPlugin {
|
buildPlugin {
|
||||||
dependsOn(sourcesJar)
|
dependsOn(createOpenApiSourceJar)
|
||||||
from(sourcesJar) { into("lib/src") }
|
from(createOpenApiSourceJar) { into("lib/src") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,51 +250,44 @@ gradle.projectsEvaluated {
|
|||||||
|
|
||||||
// --- Intellij plugin
|
// --- Intellij plugin
|
||||||
|
|
||||||
intellijPlatform {
|
intellij {
|
||||||
pluginConfiguration {
|
version.set(ideaVersion)
|
||||||
name = "IdeaVim"
|
type.set(ideaType)
|
||||||
changeNotes.set(
|
pluginName.set("IdeaVim")
|
||||||
"""
|
|
||||||
Undo in IdeaVim now works like in Vim<br/>
|
|
||||||
Caret movement is no longer a separate undo step, and full insert is undoable in one step.<br/>
|
|
||||||
<a href="https://youtrack.jetbrains.com/issue/VIM-547/Undo-splits-Insert-mode-edits-into-separate-undo-chunks">Share Feedback</a>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<a href="https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20Fix%20versions:%20${version.get()}">Changelog</a>
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
ideaVersion {
|
updateSinceUntilBuild.set(false)
|
||||||
// Let the Gradle plugin set the since-build version. It defaults to the version of the IDE we're building against
|
|
||||||
// specified as two components, `{branch}.{build}` (e.g., "241.15989"). There is no third component specified.
|
|
||||||
// The until-build version defaults to `{branch}.*`, but we want to support _all_ future versions, so we set it
|
|
||||||
// with a null provider (the provider is important).
|
|
||||||
// By letting the Gradle plugin handle this, the Plugin DevKit IntelliJ plugin cannot help us with the "Usage of
|
|
||||||
// IntelliJ API not available in older IDEs" inspection. However, since our since-build is the version we compile
|
|
||||||
// against, we can never get an API that's newer - it would be an unresolved symbol.
|
|
||||||
untilBuild.set(provider { null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
downloadSources.set(downloadIdeaSources.toBoolean())
|
||||||
|
instrumentCode.set(instrumentPluginCode.toBoolean())
|
||||||
|
intellijRepository.set("https://www.jetbrains.com/intellij-repository")
|
||||||
|
plugins.set(listOf("AceJump:3.8.11"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
publishPlugin {
|
||||||
channels.set(publishChannels.split(","))
|
channels.set(publishChannels.split(","))
|
||||||
token.set(publishToken)
|
token.set(publishToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
signing {
|
signPlugin {
|
||||||
certificateChain.set(providers.environmentVariable("CERTIFICATE_CHAIN"))
|
certificateChain.set(providers.environmentVariable("CERTIFICATE_CHAIN"))
|
||||||
privateKey.set(providers.environmentVariable("PRIVATE_KEY"))
|
privateKey.set(providers.environmentVariable("PRIVATE_KEY"))
|
||||||
password.set(providers.environmentVariable("PRIVATE_KEY_PASSWORD"))
|
password.set(providers.environmentVariable("PRIVATE_KEY_PASSWORD"))
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyPlugin {
|
runPluginVerifier {
|
||||||
teamCityOutputFormat = true
|
downloadDir.set("${project.buildDir}/pluginVerifier/ides")
|
||||||
ides {
|
teamCityOutputFormat.set(true)
|
||||||
recommended()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
instrumentCode.set(instrumentPluginCode.toBoolean())
|
patchPluginXml {
|
||||||
|
// Don't forget to update plugin.xml
|
||||||
|
sinceBuild.set("241.15989.150")
|
||||||
|
|
||||||
|
changeNotes.set(
|
||||||
|
"""<a href="https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20Fix%20versions:%20${version.get()}">Changelog</a>"""
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ksp {
|
ksp {
|
||||||
@@ -958,12 +891,12 @@ fun changes(): List<Change> {
|
|||||||
println("Start changes processing")
|
println("Start changes processing")
|
||||||
for (message in messages) {
|
for (message in messages) {
|
||||||
println("Processing '$message'...")
|
println("Processing '$message'...")
|
||||||
val lowercaseMessage = message.lowercase()
|
val lowercaseMessage = message.toLowerCase()
|
||||||
val regex = "^fix\\((vim-\\d+)\\):".toRegex()
|
val regex = "^fix\\((vim-\\d+)\\):".toRegex()
|
||||||
val findResult = regex.find(lowercaseMessage)
|
val findResult = regex.find(lowercaseMessage)
|
||||||
if (findResult != null) {
|
if (findResult != null) {
|
||||||
println("Message matches")
|
println("Message matches")
|
||||||
val value = findResult.groups[1]!!.value.uppercase()
|
val value = findResult.groups[1]!!.value.toUpperCase()
|
||||||
val shortMessage = message.drop(findResult.range.last + 1).trim()
|
val shortMessage = message.drop(findResult.range.last + 1).trim()
|
||||||
newFixes += Change(value, shortMessage)
|
newFixes += Change(value, shortMessage)
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
Welcome to the IdeaVim wiki!
|
Welcome to the IdeaVim wiki!
|
||||||
|
|
||||||
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins)
|
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins.md)
|
||||||
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples)
|
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples.md)
|
||||||
- List of "set" commands: ["set" commands](set-commands)
|
- List of "set" commands: ["set" commands](set-commands.md)
|
||||||
- Docs about "select" mode in vim: [select mode](Select-mode)
|
- Docs about "select" mode in vim: [select mode](Select-mode.md)
|
||||||
|
@@ -82,7 +82,7 @@ Original plugin: [NERDTree](https://github.com/preservim/nerdtree).
|
|||||||
|
|
||||||
### Instructions
|
### Instructions
|
||||||
|
|
||||||
[See here](NERDTree-support).
|
[See here](NERDTree-support.md).
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@@ -5,9 +5,9 @@ Using actions from external plugins is the same, as tracking and reusing any IDE
|
|||||||
1. Install the plugin via Marketplace
|
1. Install the plugin via Marketplace
|
||||||
2. Enable action tracking. You can enable it by one of the following ways:
|
2. Enable action tracking. You can enable it by one of the following ways:
|
||||||
* Execute `:set trackactionids` ex command or just `:set tai`
|
* Execute `:set trackactionids` ex command or just `:set tai`
|
||||||
* Open the "Find actions" window by pressing `Ctrl-Shift-A` and search for "Track Action IDs" to find the toggle that enables and disables action tracking
|
* Open the "Find actions" window by pressing `Ctrl-Shift-A` and search for "Track Action Ids" to find the toggle that enables and disables action tracking
|
||||||
3. Execute the plugin action the way intended by plugin author "See Edit menu or use ⇧ + ⌥ + U / Shift + Alt + U" or just find the `Toggle Camel Case` action in the "Find actions" window (`Ctrl-Shift-A`). If you action tracking is on, you will see this notification in your right bottom corner:
|
3. Execute the plugin action the way intended by plugin author "See Edit menu or use ⇧ + ⌥ + U / Shift + Alt + U" or just find the `Toggle Camel Case` action in the "Find actions" window (`Ctrl-Shift-A`). If you action tracking is on, you will see this notification in your right bottom corner:
|
||||||
|
|
||||||
<img alt="Notification" src="images/action-id-notification.png"/>
|
<img alt="Notification" src="images/action-id-notification.png"/>
|
||||||
4. Copy the action id from the notification to create the following mapping in your .ideavimrc
|
4. Copy the action id from the notification to create the following mapping in your .ideavimrc
|
||||||
```map <leader>t <Action>(de.netnexus.CamelCasePlugin.ToggleCamelCase)```
|
```map <leader>t <Action>(de.netnexus.CamelCasePlugin.ToggleCamelCase)```
|
@@ -1,7 +1,7 @@
|
|||||||
# Support Guide
|
# Support Guide
|
||||||
|
|
||||||
This document is created to help our support team.
|
This document is created to help our support team.
|
||||||
It's not intended to be read by the users as it brings no value to them.
|
It's not intended to be read by the users as it brings to value to them.
|
||||||
|
|
||||||
## Support channels
|
## Support channels
|
||||||
|
|
||||||
@@ -35,4 +35,4 @@ IdeaVim has multiple YouTrack statuses, main are:
|
|||||||
# ~.ideavimrc file
|
# ~.ideavimrc file
|
||||||
|
|
||||||
`~/.ideavimrc` is the file that is used for IdeaVim configuration. It may affect behaviour of the program,
|
`~/.ideavimrc` is the file that is used for IdeaVim configuration. It may affect behaviour of the program,
|
||||||
so it makes sense to additionally request this file in case the issues can't be reproduced.
|
so it makes sense to additionally request this file in case the issues can't be reproduced.
|
@@ -16,13 +16,14 @@
|
|||||||
# https://data.services.jetbrains.com/products?code=IC
|
# https://data.services.jetbrains.com/products?code=IC
|
||||||
# Maven releases are here: https://www.jetbrains.com/intellij-repository/releases
|
# Maven releases are here: https://www.jetbrains.com/intellij-repository/releases
|
||||||
# And snapshots: https://www.jetbrains.com/intellij-repository/snapshots
|
# And snapshots: https://www.jetbrains.com/intellij-repository/snapshots
|
||||||
ideaVersion=2024.2
|
ideaVersion=2024.1.1
|
||||||
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
||||||
ideaType=IC
|
ideaType=IC
|
||||||
|
downloadIdeaSources=true
|
||||||
instrumentPluginCode=true
|
instrumentPluginCode=true
|
||||||
version=chylex-40
|
version=chylex-36
|
||||||
javaVersion=17
|
javaVersion=17
|
||||||
remoteRobotVersion=0.11.23
|
remoteRobotVersion=0.11.22
|
||||||
antlrVersion=4.10.1
|
antlrVersion=4.10.1
|
||||||
|
|
||||||
# [VERSION UPDATE] 2024.2 - remove when IdeaVim targets 2024.2
|
# [VERSION UPDATE] 2024.2 - remove when IdeaVim targets 2024.2
|
||||||
@@ -34,7 +35,7 @@ splitModeVersion=242-EAP-SNAPSHOT
|
|||||||
|
|
||||||
# Please don't forget to update kotlin version in buildscript section
|
# Please don't forget to update kotlin version in buildscript section
|
||||||
# Also update kotlinxSerializationVersion version
|
# Also update kotlinxSerializationVersion version
|
||||||
kotlinVersion=2.0.0
|
kotlinVersion=1.9.22
|
||||||
publishToken=token
|
publishToken=token
|
||||||
publishChannels=eap
|
publishChannels=eap
|
||||||
|
|
||||||
|
@@ -19,8 +19,9 @@ exclude:
|
|||||||
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
|
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
|
||||||
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
|
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
|
||||||
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
|
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
|
||||||
|
- src/main/java/com/maddyhome/idea/vim/vimscript/parser/generated
|
||||||
|
- src/main/java/com/maddyhome/idea/vim/package-info.java
|
||||||
- vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
- vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
||||||
- vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
|
|
||||||
- src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
|
- src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
|
||||||
- tests/ui-fixtures
|
- tests/ui-fixtures
|
||||||
dependencyIgnores:
|
dependencyIgnores:
|
||||||
|
@@ -20,7 +20,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.25")
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.24")
|
||||||
|
|
||||||
implementation("io.ktor:ktor-client-core:2.3.12")
|
implementation("io.ktor:ktor-client-core:2.3.12")
|
||||||
implementation("io.ktor:ktor-client-cio:2.3.10")
|
implementation("io.ktor:ktor-client-cio:2.3.10")
|
||||||
|
@@ -8,19 +8,14 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim
|
package com.maddyhome.idea.vim
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.ProjectManagerListener
|
import com.intellij.openapi.project.ProjectManagerListener
|
||||||
import com.intellij.openapi.startup.ProjectActivity
|
import com.intellij.openapi.startup.ProjectActivity
|
||||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper
|
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.ui.JoinEap
|
|
||||||
import com.maddyhome.idea.vim.ui.JoinEap.EAP_LINK
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Alex Plate
|
* @author Alex Plate
|
||||||
@@ -33,11 +28,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
|
|||||||
if (firstInitializationOccurred) return
|
if (firstInitializationOccurred) return
|
||||||
firstInitializationOccurred = true
|
firstInitializationOccurred = true
|
||||||
|
|
||||||
if (!VimPlugin.getVimState().wasSubscibedToEAPAutomatically && ApplicationManager.getApplication().isEAP && !JoinEap.eapActive()) {
|
|
||||||
VimPlugin.getVimState().wasSubscibedToEAPAutomatically = true
|
|
||||||
UpdateSettings.getInstance().storedPluginHosts += EAP_LINK
|
|
||||||
}
|
|
||||||
|
|
||||||
// This code should be executed once
|
// This code should be executed once
|
||||||
VimPlugin.getInstance().initialize()
|
VimPlugin.getInstance().initialize()
|
||||||
}
|
}
|
||||||
@@ -46,7 +36,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
|
|||||||
// This is a temporal workaround for VIM-2487
|
// This is a temporal workaround for VIM-2487
|
||||||
internal class PyNotebooksCloseWorkaround : ProjectManagerListener {
|
internal class PyNotebooksCloseWorkaround : ProjectManagerListener {
|
||||||
override fun projectClosingBeforeSave(project: Project) {
|
override fun projectClosingBeforeSave(project: Project) {
|
||||||
initInjector()
|
|
||||||
// TODO: Confirm context in CWM scenario
|
// TODO: Confirm context in CWM scenario
|
||||||
if (injector.globalIjOptions().closenotebooks) {
|
if (injector.globalIjOptions().closenotebooks) {
|
||||||
injector.editorGroup.getEditors().forEach { vimEditor ->
|
injector.editorGroup.getEditors().forEach { vimEditor ->
|
||||||
|
@@ -37,7 +37,6 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
|
|||||||
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
|
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
|
||||||
import com.maddyhome.idea.vim.listener.VimListenerManager;
|
import com.maddyhome.idea.vim.listener.VimListenerManager;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimInjector;
|
import com.maddyhome.idea.vim.newapi.IjVimInjector;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup;
|
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup;
|
||||||
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
|
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
|
||||||
import com.maddyhome.idea.vim.vimscript.services.VariableService;
|
import com.maddyhome.idea.vim.vimscript.services.VariableService;
|
||||||
@@ -68,7 +67,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
|
|||||||
private static final Logger LOG = Logger.getInstance(VimPlugin.class);
|
private static final Logger LOG = Logger.getInstance(VimPlugin.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IjVimInjectorKt.initInjector();
|
VimInjectorKt.setInjector(new IjVimInjector());
|
||||||
}
|
}
|
||||||
|
|
||||||
private final @NotNull VimState state = new VimState();
|
private final @NotNull VimState state = new VimState();
|
||||||
|
@@ -18,7 +18,7 @@ import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
|
|||||||
internal class VimProjectService(val project: Project) : Disposable {
|
internal class VimProjectService(val project: Project) : Disposable {
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
// Not sure if this is a best solution
|
// Not sure if this is a best solution
|
||||||
ExEntryPanel.getInstance().setEditor(null)
|
ExEntryPanel.getInstance().editor = null
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
package com.maddyhome.idea.vim.action
|
|
||||||
|
|
||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
|
||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
|
|
||||||
import com.intellij.openapi.command.WriteCommandAction
|
|
||||||
import com.intellij.openapi.fileEditor.TextEditor
|
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
|
||||||
import com.intellij.openapi.project.DumbAwareAction
|
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
|
|
||||||
class VimRunLastMacroInOpenFiles : DumbAwareAction() {
|
|
||||||
override fun update(e: AnActionEvent) {
|
|
||||||
val lastRegister = injector.macro.lastRegister
|
|
||||||
val isEnabled = lastRegister != 0.toChar()
|
|
||||||
|
|
||||||
e.presentation.isEnabled = isEnabled
|
|
||||||
e.presentation.text = if (isEnabled) "Run Macro '${lastRegister}' in Open Files" else "Run Last Macro in Open Files"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
|
||||||
return ActionUpdateThread.EDT
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun actionPerformed(e: AnActionEvent) {
|
|
||||||
val project = e.project ?: return
|
|
||||||
val fileEditorManager = FileEditorManagerEx.getInstanceExIfCreated(project) ?: return
|
|
||||||
val editors = fileEditorManager.allEditors.filterIsInstance<TextEditor>()
|
|
||||||
|
|
||||||
WriteCommandAction.writeCommandAction(project)
|
|
||||||
.withName(e.presentation.text)
|
|
||||||
.withGlobalUndo()
|
|
||||||
.withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION)
|
|
||||||
.run<RuntimeException> {
|
|
||||||
val reg = injector.macro.lastRegister
|
|
||||||
|
|
||||||
for (editor in editors) {
|
|
||||||
fileEditorManager.openFile(editor.file, true)
|
|
||||||
|
|
||||||
val vimEditor = editor.editor.vim
|
|
||||||
vimEditor.mode = Mode.NORMAL()
|
|
||||||
KeyHandler.getInstance().reset(vimEditor)
|
|
||||||
|
|
||||||
injector.macro.playbackRegister(vimEditor, IjEditorExecutionContext(e.dataContext), reg, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -43,7 +43,6 @@ import com.maddyhome.idea.vim.key.ShortcutOwnerInfo
|
|||||||
import com.maddyhome.idea.vim.listener.AceJumpService
|
import com.maddyhome.idea.vim.listener.AceJumpService
|
||||||
import com.maddyhome.idea.vim.listener.AppCodeTemplates.appCodeTemplateCaptured
|
import com.maddyhome.idea.vim.listener.AppCodeTemplates.appCodeTemplateCaptured
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
|
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
|
||||||
import com.maddyhome.idea.vim.ui.ex.ExTextField
|
import com.maddyhome.idea.vim.ui.ex.ExTextField
|
||||||
@@ -62,13 +61,10 @@ import javax.swing.KeyStroke
|
|||||||
* way to get ideavim keys for this plugin. See VIM-3085
|
* way to get ideavim keys for this plugin. See VIM-3085
|
||||||
*/
|
*/
|
||||||
class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
|
class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
|
||||||
|
|
||||||
init {
|
|
||||||
initInjector()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val traceTime: Boolean
|
private val traceTime: Boolean
|
||||||
get() {
|
get() {
|
||||||
|
// Make sure the injector is initialized
|
||||||
|
VimPlugin.getInstance()
|
||||||
return injector.globalOptions().ideatracetime
|
return injector.globalOptions().ideatracetime
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +257,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
|
|||||||
private fun getEditor(e: AnActionEvent): Editor? {
|
private fun getEditor(e: AnActionEvent): Editor? {
|
||||||
return e.getData(PlatformDataKeys.EDITOR)
|
return e.getData(PlatformDataKeys.EDITOR)
|
||||||
?: if (e.getData(PlatformDataKeys.CONTEXT_COMPONENT) is ExTextField) {
|
?: if (e.getData(PlatformDataKeys.CONTEXT_COMPONENT) is ExTextField) {
|
||||||
ExEntryPanel.getInstance().ijEditor
|
ExEntryPanel.getInstance().editor
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
|
|||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
|
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper
|
import com.maddyhome.idea.vim.helper.MessageHelper
|
||||||
import com.maddyhome.idea.vim.helper.inRepeatMode
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
|
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
|
||||||
@@ -102,7 +102,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
|
|||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
val argument = cmd.argument ?: return false
|
val argument = cmd.argument ?: return false
|
||||||
if (!editor.inRepeatMode) {
|
if (!editor.vimStateMachine.isDotRepeatInProgress) {
|
||||||
argumentCaptured = argument
|
argumentCaptured = argument
|
||||||
}
|
}
|
||||||
val range = getMotionRange(editor, context, argument, operatorArguments)
|
val range = getMotionRange(editor, context, argument, operatorArguments)
|
||||||
|
@@ -17,6 +17,7 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.command.Command
|
import com.maddyhome.idea.vim.command.Command
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
|
||||||
@CommandOrMotion(keys = ["."], modes = [Mode.NORMAL])
|
@CommandOrMotion(keys = ["."], modes = [Mode.NORMAL])
|
||||||
@@ -24,7 +25,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
|
|||||||
override val type: Command.Type = Command.Type.OTHER_WRITABLE
|
override val type: Command.Type = Command.Type.OTHER_WRITABLE
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
val state = injector.vimState
|
val state = editor.vimStateMachine
|
||||||
val lastCommand = VimRepeater.lastChangeCommand
|
val lastCommand = VimRepeater.lastChangeCommand
|
||||||
|
|
||||||
if (lastCommand == null && Extension.lastExtensionHandler == null) return false
|
if (lastCommand == null && Extension.lastExtensionHandler == null) return false
|
||||||
|
@@ -79,7 +79,7 @@ internal class VimQuickJavaDoc : VimActionHandler.SingleExecution() {
|
|||||||
override val type: Command.Type = Command.Type.OTHER_READONLY
|
override val type: Command.Type = Command.Type.OTHER_READONLY
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
injector.actionExecutor.executeAction(editor, IdeActions.ACTION_QUICK_JAVADOC, context)
|
injector.actionExecutor.executeAction(IdeActions.ACTION_QUICK_JAVADOC, context)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE.txt file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.maddyhome.idea.vim.command
|
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.state.VimStateMachine
|
|
||||||
|
|
||||||
/**
|
|
||||||
* COMPATIBILITY-LAYER: Additional class
|
|
||||||
* Please see: https://jb.gg/zo8n0r
|
|
||||||
*/
|
|
||||||
@Deprecated("Use `injector.vimState`")
|
|
||||||
class CommandState(private val machine: VimStateMachine) {
|
|
||||||
|
|
||||||
val mode: Mode
|
|
||||||
get() {
|
|
||||||
val myMode = machine.mode
|
|
||||||
return when (myMode) {
|
|
||||||
is com.maddyhome.idea.vim.state.mode.Mode.CMD_LINE -> Mode.CMD_LINE
|
|
||||||
com.maddyhome.idea.vim.state.mode.Mode.INSERT -> Mode.INSERT
|
|
||||||
is com.maddyhome.idea.vim.state.mode.Mode.NORMAL -> Mode.COMMAND
|
|
||||||
is com.maddyhome.idea.vim.state.mode.Mode.OP_PENDING -> Mode.OP_PENDING
|
|
||||||
com.maddyhome.idea.vim.state.mode.Mode.REPLACE -> Mode.REPLACE
|
|
||||||
is com.maddyhome.idea.vim.state.mode.Mode.SELECT -> Mode.SELECT
|
|
||||||
is com.maddyhome.idea.vim.state.mode.Mode.VISUAL -> Mode.VISUAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Use `KeyHandler.keyHandlerState.commandBuilder", ReplaceWith(
|
|
||||||
"KeyHandler.getInstance().keyHandlerState.commandBuilder",
|
|
||||||
"com.maddyhome.idea.vim.KeyHandler"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val commandBuilder: CommandBuilder
|
|
||||||
get() = KeyHandler.getInstance().keyHandlerState.commandBuilder
|
|
||||||
|
|
||||||
@Deprecated("Use `KeyHandler.keyHandlerState.mappingState", ReplaceWith(
|
|
||||||
"KeyHandler.getInstance().keyHandlerState.mappingState",
|
|
||||||
"com.maddyhome.idea.vim.KeyHandler"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val mappingState: MappingState
|
|
||||||
get() = KeyHandler.getInstance().keyHandlerState.mappingState
|
|
||||||
|
|
||||||
enum class Mode {
|
|
||||||
// Basic modes
|
|
||||||
COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/
|
|
||||||
|
|
||||||
// Additional modes
|
|
||||||
OP_PENDING, REPLACE /*, VISUAL_REPLACE*/, INSERT_NORMAL, INSERT_VISUAL, INSERT_SELECT
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class SubMode {
|
|
||||||
NONE, VISUAL_CHARACTER, VISUAL_LINE, VISUAL_BLOCK
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
@Deprecated("Use `injector.vimState`")
|
|
||||||
fun getInstance(editor: Editor): CommandState {
|
|
||||||
return CommandState(injector.vimState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -12,17 +12,17 @@ import com.intellij.application.options.CodeStyle
|
|||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions
|
import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions
|
||||||
import com.maddyhome.idea.vim.api.VimIndentConfig
|
|
||||||
|
|
||||||
internal class IndentConfig private constructor(indentOptions: IndentOptions): VimIndentConfig {
|
internal class IndentConfig private constructor(indentOptions: IndentOptions) {
|
||||||
private val indentSize = indentOptions.INDENT_SIZE
|
private val indentSize = indentOptions.INDENT_SIZE
|
||||||
private val tabSize = indentOptions.TAB_SIZE
|
private val tabSize = indentOptions.TAB_SIZE
|
||||||
private val isUseTabs = indentOptions.USE_TAB_CHARACTER
|
private val isUseTabs = indentOptions.USE_TAB_CHARACTER
|
||||||
|
|
||||||
override fun getIndentSize(depth: Int): Int = indentSize * depth
|
fun getTotalIndent(count: Int): Int = indentSize * count
|
||||||
override fun createIndentByDepth(depth: Int): String = createIndentBySize(getIndentSize(depth))
|
|
||||||
|
|
||||||
override fun createIndentBySize(size: Int): String {
|
fun createIndentByCount(count: Int): String = createIndentBySize(getTotalIndent(count))
|
||||||
|
|
||||||
|
fun createIndentBySize(size: Int): String {
|
||||||
val tabCount: Int
|
val tabCount: Int
|
||||||
val spaceCount: Int
|
val spaceCount: Int
|
||||||
if (isUseTabs) {
|
if (isUseTabs) {
|
||||||
|
@@ -18,8 +18,6 @@ import kotlin.reflect.KProperty
|
|||||||
internal class VimState {
|
internal class VimState {
|
||||||
var isIdeaJoinNotified by StateProperty("idea-join")
|
var isIdeaJoinNotified by StateProperty("idea-join")
|
||||||
var isIdeaPutNotified by StateProperty("idea-put")
|
var isIdeaPutNotified by StateProperty("idea-put")
|
||||||
var isNewUndoNotified by StateProperty("idea-undo")
|
|
||||||
var wasSubscibedToEAPAutomatically by StateProperty("was-automatically-subscribed-to-eap")
|
|
||||||
|
|
||||||
fun readData(element: Element) {
|
fun readData(element: Element) {
|
||||||
val notifications = element.getChild("notifications")
|
val notifications = element.getChild("notifications")
|
||||||
|
@@ -9,124 +9,51 @@ package com.maddyhome.idea.vim.ex
|
|||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanelBase
|
import com.maddyhome.idea.vim.api.VimExOutputPanel
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.helper.vimExOutput
|
import com.maddyhome.idea.vim.helper.vimExOutput
|
||||||
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import javax.swing.KeyStroke
|
|
||||||
|
|
||||||
// TODO: We need a nicer way to handle output, especially wrt testing, appending + clearing
|
// TODO: We need a nicer way to handle output, especially wrt testing, appending + clearing
|
||||||
class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPanelBase() {
|
class ExOutputModel private constructor(private val myEditor: Editor) : VimExOutputPanel {
|
||||||
private var isActiveInTestMode = false
|
private var isActiveInTestMode = false
|
||||||
|
|
||||||
val editor get() = myEditor.get()
|
override val isActive: Boolean
|
||||||
|
|
||||||
val isActive: Boolean
|
|
||||||
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
editor?.let { ExOutputPanel.getNullablePanel(it) }?.myActive ?: false
|
ExOutputPanel.isPanelActive(myEditor)
|
||||||
} else {
|
} else {
|
||||||
isActiveInTestMode
|
isActiveInTestMode
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addText(text: String, isNewLine: Boolean) {
|
override var text: String? = null
|
||||||
if (this.text.isNotEmpty() && isNewLine) this.text += "\n$text" else this.text += text
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun show() {
|
|
||||||
if (editor == null) return
|
|
||||||
val currentPanel = injector.outputPanel.getCurrentOutputPanel()
|
|
||||||
if (currentPanel != null && currentPanel != this) currentPanel.close()
|
|
||||||
|
|
||||||
editor!!.vimExOutput = this
|
|
||||||
val exOutputPanel = ExOutputPanel.getInstance(editor!!)
|
|
||||||
if (!exOutputPanel.myActive) {
|
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
|
||||||
isActiveInTestMode = true
|
|
||||||
} else {
|
|
||||||
exOutputPanel.activate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun scrollPage() {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.scrollPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun scrollHalfPage() {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.scrollHalfPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun scrollLine() {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.scrollLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
override var text: String = ""
|
|
||||||
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
editor?.let { ExOutputPanel.getInstance(it).text } ?: ""
|
ExOutputPanel.getInstance(myEditor).text
|
||||||
} else {
|
} else {
|
||||||
// ExOutputPanel always returns a non-null string
|
// ExOutputPanel always returns a non-null string
|
||||||
field
|
field ?: ""
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
// ExOutputPanel will strip a trailing newline. We'll do it now so that tests have the same behaviour. We also
|
// ExOutputPanel will strip a trailing newline. We'll do it now so that tests have the same behaviour. We also
|
||||||
// never pass null to ExOutputPanel, but we do store it for tests, so we know if we're active or not
|
// never pass null to ExOutputPanel, but we do store it for tests, so we know if we're active or not
|
||||||
val newValue = value.removeSuffix("\n")
|
val newValue = value?.removeSuffix("\n")
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
editor?.let { ExOutputPanel.getInstance(it).setText(newValue) }
|
ExOutputPanel.getInstance(myEditor).setText(newValue ?: "")
|
||||||
} else {
|
} else {
|
||||||
field = newValue
|
field = newValue
|
||||||
isActiveInTestMode = newValue.isNotEmpty()
|
isActiveInTestMode = !newValue.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override var label: String
|
|
||||||
get() {
|
|
||||||
val notNullEditor = editor ?: return ""
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return ""
|
|
||||||
return panel.myLabel.text
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.myLabel.text = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun output(text: String) {
|
override fun output(text: String) {
|
||||||
this.text = text
|
this.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
override fun clear() {
|
||||||
text = ""
|
text = null
|
||||||
}
|
|
||||||
|
|
||||||
override val atEnd: Boolean
|
|
||||||
get() {
|
|
||||||
val notNullEditor = editor ?: return false
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return false
|
|
||||||
return panel.isAtEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBadKey() {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.onBadKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close(key: KeyStroke?) {
|
|
||||||
val notNullEditor = editor ?: return
|
|
||||||
val panel = ExOutputPanel.getNullablePanel(notNullEditor) ?: return
|
|
||||||
panel.close(key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
editor?.let { ExOutputPanel.getInstance(it).close() }
|
ExOutputPanel.getInstance(myEditor).close()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
isActiveInTestMode = false
|
isActiveInTestMode = false
|
||||||
@@ -138,7 +65,7 @@ class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPane
|
|||||||
fun getInstance(editor: Editor): ExOutputModel {
|
fun getInstance(editor: Editor): ExOutputModel {
|
||||||
var model = editor.vimExOutput
|
var model = editor.vimExOutput
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
model = ExOutputModel(WeakReference(editor))
|
model = ExOutputModel(editor)
|
||||||
editor.vimExOutput = model
|
editor.vimExOutput = model
|
||||||
}
|
}
|
||||||
return model
|
return model
|
||||||
|
@@ -24,14 +24,13 @@ import com.maddyhome.idea.vim.common.CommandAlias
|
|||||||
import com.maddyhome.idea.vim.common.CommandAliasHandler
|
import com.maddyhome.idea.vim.common.CommandAliasHandler
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.helper.TestInputModel
|
import com.maddyhome.idea.vim.helper.TestInputModel
|
||||||
import com.maddyhome.idea.vim.helper.inRepeatMode
|
|
||||||
import com.maddyhome.idea.vim.helper.noneOfEnum
|
import com.maddyhome.idea.vim.helper.noneOfEnum
|
||||||
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.key.MappingOwner
|
import com.maddyhome.idea.vim.key.MappingOwner
|
||||||
import com.maddyhome.idea.vim.key.OperatorFunction
|
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.ui.ModalEntry
|
import com.maddyhome.idea.vim.ui.ModalEntry
|
||||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanelService
|
|
||||||
import com.maddyhome.idea.vim.vimscript.model.Executable
|
import com.maddyhome.idea.vim.vimscript.model.Executable
|
||||||
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
|
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
|
||||||
import com.maddyhome.idea.vim.vimscript.model.VimLContext
|
import com.maddyhome.idea.vim.vimscript.model.VimLContext
|
||||||
@@ -152,7 +151,7 @@ object VimExtensionFacade {
|
|||||||
/** Returns a single key stroke from the user input similar to 'getchar()'. */
|
/** Returns a single key stroke from the user input similar to 'getchar()'. */
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun inputKeyStroke(editor: Editor): KeyStroke {
|
fun inputKeyStroke(editor: Editor): KeyStroke {
|
||||||
if (editor.vim.inRepeatMode) {
|
if (editor.vim.vimStateMachine.isDotRepeatInProgress) {
|
||||||
val input = Extension.consumeKeystroke()
|
val input = Extension.consumeKeystroke()
|
||||||
LOG.trace("inputKeyStroke: dot repeat in progress. Input: $input")
|
LOG.trace("inputKeyStroke: dot repeat in progress. Input: $input")
|
||||||
return input ?: error("Not enough keystrokes saved: ${Extension.lastExtensionHandler}")
|
return input ?: error("Not enough keystrokes saved: ${Extension.lastExtensionHandler}")
|
||||||
@@ -184,7 +183,7 @@ object VimExtensionFacade {
|
|||||||
/** Returns a string typed in the input box similar to 'input()'. */
|
/** Returns a string typed in the input box similar to 'input()'. */
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun inputString(editor: Editor, context: DataContext, prompt: String, finishOn: Char?): String {
|
fun inputString(editor: Editor, context: DataContext, prompt: String, finishOn: Char?): String {
|
||||||
return (injector.commandLine as ExEntryPanelService).inputString(editor.vim, context.vim, prompt, finishOn) ?: ""
|
return injector.commandLine.inputString(editor.vim, context.vim, prompt, finishOn) ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the current contents of the given register similar to 'getreg()'. */
|
/** Get the current contents of the given register similar to 'getreg()'. */
|
||||||
|
@@ -46,6 +46,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissin
|
|||||||
import com.maddyhome.idea.vim.extension.exportOperatorFunction
|
import com.maddyhome.idea.vim.extension.exportOperatorFunction
|
||||||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
|
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
|
||||||
import com.maddyhome.idea.vim.helper.PsiHelper
|
import com.maddyhome.idea.vim.helper.PsiHelper
|
||||||
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.key.OperatorFunction
|
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
@@ -64,7 +65,7 @@ internal class CommentaryExtension : VimExtension {
|
|||||||
selectionType: SelectionType,
|
selectionType: SelectionType,
|
||||||
resetCaret: Boolean = true,
|
resetCaret: Boolean = true,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val mode = editor.mode
|
val mode = editor.vimStateMachine.mode
|
||||||
if (mode !is Mode.VISUAL) {
|
if (mode !is Mode.VISUAL) {
|
||||||
editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset)
|
editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset)
|
||||||
}
|
}
|
||||||
@@ -79,12 +80,11 @@ internal class CommentaryExtension : VimExtension {
|
|||||||
|
|
||||||
val project = editor.ij.project!!
|
val project = editor.ij.project!!
|
||||||
val callback = { afterCommenting(mode, editor, resetCaret, range) }
|
val callback = { afterCommenting(mode, editor, resetCaret, range) }
|
||||||
actions.any { executeActionWithCallbackOnSuccess(editor, it, project, context, callback) }
|
actions.any { executeActionWithCallbackOnSuccess(it, project, context, callback) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeActionWithCallbackOnSuccess(
|
private fun executeActionWithCallbackOnSuccess(
|
||||||
editor: VimEditor,
|
|
||||||
action: String,
|
action: String,
|
||||||
project: Project,
|
project: Project,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
@@ -93,7 +93,7 @@ internal class CommentaryExtension : VimExtension {
|
|||||||
val res = Ref.create<Boolean>(false)
|
val res = Ref.create<Boolean>(false)
|
||||||
AsyncActionExecutionService.getInstance(project).withExecutionAfterAction(
|
AsyncActionExecutionService.getInstance(project).withExecutionAfterAction(
|
||||||
action,
|
action,
|
||||||
{ res.set(injector.actionExecutor.executeAction(editor, name = action, context = context)) },
|
{ res.set(injector.actionExecutor.executeAction(action, context)) },
|
||||||
{ if (res.get()) callback() })
|
{ if (res.get()) callback() })
|
||||||
return res.get()
|
return res.get()
|
||||||
}
|
}
|
||||||
|
@@ -23,15 +23,13 @@ import com.intellij.util.Alarm
|
|||||||
import com.intellij.util.Alarm.ThreadToUse
|
import com.intellij.util.Alarm.ThreadToUse
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.common.ModeChangeListener
|
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.common.VimYankListener
|
|
||||||
import com.maddyhome.idea.vim.extension.VimExtension
|
import com.maddyhome.idea.vim.extension.VimExtension
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper
|
import com.maddyhome.idea.vim.helper.MessageHelper
|
||||||
import com.maddyhome.idea.vim.helper.VimNlsSafe
|
import com.maddyhome.idea.vim.helper.VimNlsSafe
|
||||||
|
import com.maddyhome.idea.vim.listener.VimInsertListener
|
||||||
|
import com.maddyhome.idea.vim.listener.VimYankListener
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
@@ -77,7 +75,7 @@ internal class HighlightColorResetter : LafManagerListener {
|
|||||||
*
|
*
|
||||||
* When a new text is yanked or user starts editing, the old highlighting would be deleted.
|
* When a new text is yanked or user starts editing, the old highlighting would be deleted.
|
||||||
*/
|
*/
|
||||||
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
|
internal class VimHighlightedYank : VimExtension, VimYankListener, VimInsertListener {
|
||||||
private val highlightHandler = HighlightHandler()
|
private val highlightHandler = HighlightHandler()
|
||||||
private var initialised = false
|
private var initialised = false
|
||||||
|
|
||||||
@@ -85,8 +83,8 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
|||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
// Note that these listeners will still be registered when IdeaVim is disabled. However, they'll never get called
|
// Note that these listeners will still be registered when IdeaVim is disabled. However, they'll never get called
|
||||||
injector.listenersNotifier.modeChangeListeners.add(this)
|
VimPlugin.getYank().addListener(this)
|
||||||
injector.listenersNotifier.yankListeners.add(this)
|
VimPlugin.getChange().addInsertListener(this)
|
||||||
|
|
||||||
// Register our own disposable to remove highlights when IdeaVim is disabled. Somehow, we need to re-register when
|
// Register our own disposable to remove highlights when IdeaVim is disabled. Somehow, we need to re-register when
|
||||||
// IdeaVim is re-enabled. We don't get a call back for that, but because the listeners are active until the
|
// IdeaVim is re-enabled. We don't get a call back for that, but because the listeners are active until the
|
||||||
@@ -107,8 +105,8 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
// Called when the extension is disabled with `:set no{extension}` or if the plugin owning the extension unloads
|
// Called when the extension is disabled with `:set no{extension}` or if the plugin owning the extension unloads
|
||||||
injector.listenersNotifier.modeChangeListeners.remove(this)
|
VimPlugin.getYank().removeListener(this)
|
||||||
injector.listenersNotifier.yankListeners.remove(this)
|
VimPlugin.getChange().removeInsertListener(this)
|
||||||
|
|
||||||
highlightHandler.clearYankHighlighters()
|
highlightHandler.clearYankHighlighters()
|
||||||
initialised = false
|
initialised = false
|
||||||
@@ -119,8 +117,7 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
|||||||
highlightHandler.highlightYankRange(editor.ij, range)
|
highlightHandler.highlightYankRange(editor.ij, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
override fun insertModeStarted(editor: Editor) {
|
||||||
if (editor.mode !is Mode.INSERT) return
|
|
||||||
ensureInitialised()
|
ensureInitialised()
|
||||||
highlightHandler.clearYankHighlighters()
|
highlightHandler.clearYankHighlighters()
|
||||||
}
|
}
|
||||||
|
@@ -481,9 +481,6 @@ internal class NerdTree : VimExtension {
|
|||||||
registerCommand("NERDTreeMapNewFile", "n", NerdAction.ToIj("NewFile"))
|
registerCommand("NERDTreeMapNewFile", "n", NerdAction.ToIj("NewFile"))
|
||||||
registerCommand("NERDTreeMapNewDir", "N", NerdAction.ToIj("NewDir"))
|
registerCommand("NERDTreeMapNewDir", "N", NerdAction.ToIj("NewDir"))
|
||||||
registerCommand("NERDTreeMapDelete", "d", NerdAction.ToIj("\$Delete"))
|
registerCommand("NERDTreeMapDelete", "d", NerdAction.ToIj("\$Delete"))
|
||||||
registerCommand("NERDTreeMapCopy", "y", NerdAction.ToIj("\$Copy"))
|
|
||||||
registerCommand("NERDTreeMapPaste", "v", NerdAction.ToIj("\$Paste"))
|
|
||||||
registerCommand("NERDTreeMapRename", "<C-r>", NerdAction.ToIj("RenameElement"))
|
|
||||||
registerCommand("NERDTreeMapRefreshRoot", "R", NerdAction.ToIj("Synchronize"))
|
registerCommand("NERDTreeMapRefreshRoot", "R", NerdAction.ToIj("Synchronize"))
|
||||||
registerCommand("NERDTreeMapMenu", "m", NerdAction.ToIj("ShowPopupMenu"))
|
registerCommand("NERDTreeMapMenu", "m", NerdAction.ToIj("ShowPopupMenu"))
|
||||||
registerCommand("NERDTreeMapQuit", "q", NerdAction.ToIj("HideActiveWindow"))
|
registerCommand("NERDTreeMapQuit", "q", NerdAction.ToIj("HideActiveWindow"))
|
||||||
|
@@ -36,7 +36,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissin
|
|||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
|
||||||
import com.maddyhome.idea.vim.extension.exportOperatorFunction
|
import com.maddyhome.idea.vim.extension.exportOperatorFunction
|
||||||
import com.maddyhome.idea.vim.group.findBlockRange
|
import com.maddyhome.idea.vim.group.findBlockRange
|
||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
|
||||||
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
|
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
|
||||||
import com.maddyhome.idea.vim.key.OperatorFunction
|
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
@@ -51,7 +50,6 @@ import com.maddyhome.idea.vim.state.mode.selectionType
|
|||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
import com.maddyhome.idea.vim.state.mode.returnTo
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Port of vim-surround.
|
* Port of vim-surround.
|
||||||
@@ -117,9 +115,6 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
// it.moveToOffset(lineStartOffset)
|
// it.moveToOffset(lineStartOffset)
|
||||||
}
|
}
|
||||||
// Jump back to start
|
// Jump back to start
|
||||||
if (editor.mode !is Mode.NORMAL) {
|
|
||||||
editor.mode = Mode.NORMAL()
|
|
||||||
}
|
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
|
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +136,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
// Leave visual mode
|
// Leave visual mode
|
||||||
editor.exitVisualMode()
|
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,10 +306,8 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
|
|
||||||
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
||||||
val editor = caret.editor
|
val editor = caret.editor
|
||||||
if (editor.mode is Mode.CMD_LINE) {
|
val ijEditor = editor.ij
|
||||||
editor.mode = (editor.mode as Mode.CMD_LINE).returnTo()
|
return when (ijEditor.vim.mode) {
|
||||||
}
|
|
||||||
return when (editor.mode) {
|
|
||||||
is Mode.NORMAL -> injector.markService.getChangeMarks(caret)
|
is Mode.NORMAL -> injector.markService.getChangeMarks(caret)
|
||||||
is Mode.VISUAL -> caret.run { TextRange(selectionStart, selectionEnd) }
|
is Mode.VISUAL -> caret.run { TextRange(selectionStart, selectionEnd) }
|
||||||
else -> null
|
else -> null
|
||||||
@@ -357,9 +350,6 @@ private fun getSurroundPair(c: Char): Pair<String, String>? = if (c in SURROUND_
|
|||||||
|
|
||||||
private fun inputTagPair(editor: Editor, context: DataContext): Pair<String, String>? {
|
private fun inputTagPair(editor: Editor, context: DataContext): Pair<String, String>? {
|
||||||
val tagInput = inputString(editor, context, "<", '>')
|
val tagInput = inputString(editor, context, "<", '>')
|
||||||
if (editor.vim.mode is Mode.CMD_LINE) {
|
|
||||||
editor.vim.mode = editor.vim.mode.returnTo()
|
|
||||||
}
|
|
||||||
val matcher = tagNameAndAttributesCapturePattern.matcher(tagInput)
|
val matcher = tagNameAndAttributesCapturePattern.matcher(tagInput)
|
||||||
return if (matcher.find()) {
|
return if (matcher.find()) {
|
||||||
val tagName = matcher.group(1)
|
val tagName = matcher.group(1)
|
||||||
@@ -376,9 +366,6 @@ private fun inputFunctionName(
|
|||||||
withInternalSpaces: Boolean,
|
withInternalSpaces: Boolean,
|
||||||
): Pair<String, String>? {
|
): Pair<String, String>? {
|
||||||
val functionNameInput = inputString(editor, context, "function: ", null)
|
val functionNameInput = inputString(editor, context, "function: ", null)
|
||||||
if (editor.vim.mode is Mode.CMD_LINE) {
|
|
||||||
editor.vim.mode = editor.vim.mode.returnTo()
|
|
||||||
}
|
|
||||||
if (functionNameInput.isEmpty()) return null
|
if (functionNameInput.isEmpty()) return null
|
||||||
return if (withInternalSpaces) "$functionNameInput( " to " )" else "$functionNameInput(" to ")"
|
return if (withInternalSpaces) "$functionNameInput( " to " )" else "$functionNameInput(" to ")"
|
||||||
}
|
}
|
||||||
|
@@ -15,35 +15,77 @@ import com.intellij.openapi.command.CommandProcessor
|
|||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
|
import com.intellij.openapi.command.UndoConfirmationPolicy
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.LogicalPosition
|
||||||
import com.intellij.openapi.editor.actions.EnterAction
|
import com.intellij.openapi.editor.actions.EnterAction
|
||||||
import com.intellij.openapi.editor.event.EditorMouseEvent
|
import com.intellij.openapi.editor.event.EditorMouseEvent
|
||||||
import com.intellij.openapi.editor.event.EditorMouseListener
|
import com.intellij.openapi.editor.event.EditorMouseListener
|
||||||
|
import com.intellij.openapi.editor.impl.TextRangeInterval
|
||||||
import com.intellij.openapi.util.UserDataHolder
|
import com.intellij.openapi.util.UserDataHolder
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import com.intellij.psi.util.PsiUtilBase
|
import com.intellij.psi.util.PsiUtilBase
|
||||||
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import com.maddyhome.idea.vim.EventFacade
|
import com.maddyhome.idea.vim.EventFacade
|
||||||
|
import com.maddyhome.idea.vim.api.BufferPosition
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimCaret
|
import com.maddyhome.idea.vim.api.VimCaret
|
||||||
import com.maddyhome.idea.vim.api.VimChangeGroupBase
|
import com.maddyhome.idea.vim.api.VimChangeGroupBase
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
|
import com.maddyhome.idea.vim.api.VimMotionGroupBase
|
||||||
|
import com.maddyhome.idea.vim.api.anyNonWhitespace
|
||||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
||||||
|
import com.maddyhome.idea.vim.api.getLineEndOffset
|
||||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
||||||
|
import com.maddyhome.idea.vim.api.getText
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.api.lineLength
|
||||||
|
import com.maddyhome.idea.vim.api.normalizeOffset
|
||||||
|
import com.maddyhome.idea.vim.api.options
|
||||||
|
import com.maddyhome.idea.vim.command.Argument
|
||||||
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
|
import com.maddyhome.idea.vim.common.IndentConfig.Companion.create
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
|
import com.maddyhome.idea.vim.ex.ranges.LineRange
|
||||||
|
import com.maddyhome.idea.vim.group.MotionGroup.Companion.getMotionRange2
|
||||||
|
import com.maddyhome.idea.vim.group.visual.VimSelection
|
||||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
|
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
|
||||||
|
import com.maddyhome.idea.vim.handler.Motion
|
||||||
|
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
|
||||||
import com.maddyhome.idea.vim.handler.commandContinuation
|
import com.maddyhome.idea.vim.handler.commandContinuation
|
||||||
|
import com.maddyhome.idea.vim.helper.CharacterHelper
|
||||||
|
import com.maddyhome.idea.vim.helper.CharacterHelper.changeCase
|
||||||
|
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
||||||
|
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||||
|
import com.maddyhome.idea.vim.helper.NumberType
|
||||||
|
import com.maddyhome.idea.vim.helper.endOffsetInclusive
|
||||||
|
import com.maddyhome.idea.vim.helper.findNumberUnderCursor
|
||||||
|
import com.maddyhome.idea.vim.helper.findNumbersInRange
|
||||||
import com.maddyhome.idea.vim.helper.inInsertMode
|
import com.maddyhome.idea.vim.helper.inInsertMode
|
||||||
|
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition
|
||||||
|
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
|
||||||
import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance
|
import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance
|
||||||
import com.maddyhome.idea.vim.listener.VimInsertListener
|
import com.maddyhome.idea.vim.listener.VimInsertListener
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
import com.maddyhome.idea.vim.regexp.VimRegex
|
||||||
|
import com.maddyhome.idea.vim.regexp.match.VimMatchResult
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
|
||||||
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.commands.SortOption
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides all the insert/replace related functionality
|
* Provides all the insert/replace related functionality
|
||||||
*/
|
*/
|
||||||
class ChangeGroup : VimChangeGroupBase() {
|
class ChangeGroup : VimChangeGroupBase() {
|
||||||
|
private val insertListeners = ContainerUtil.createLockFreeCopyOnWriteList<VimInsertListener>()
|
||||||
private val listener: EditorMouseListener = object : EditorMouseListener {
|
private val listener: EditorMouseListener = object : EditorMouseListener {
|
||||||
override fun mouseClicked(event: EditorMouseEvent) {
|
override fun mouseClicked(event: EditorMouseEvent) {
|
||||||
val editor = event.editor
|
val editor = event.editor
|
||||||
@@ -103,6 +145,163 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDeleteRangeAndType2(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument,
|
||||||
|
isChange: Boolean,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Pair<TextRange, SelectionType>? {
|
||||||
|
val range = getMotionRange2(
|
||||||
|
(editor as IjVimEditor).editor,
|
||||||
|
(caret as IjVimCaret).caret,
|
||||||
|
(context as IjEditorExecutionContext).context,
|
||||||
|
argument,
|
||||||
|
operatorArguments
|
||||||
|
)
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
// Delete motion commands that are not linewise become linewise if all the following are true:
|
||||||
|
// 1) The range is across multiple lines
|
||||||
|
// 2) There is only whitespace before the start of the range
|
||||||
|
// 3) There is only whitespace after the end of the range
|
||||||
|
var type: SelectionType
|
||||||
|
type = if (argument.motion.isLinewiseMotion()) {
|
||||||
|
SelectionType.LINE_WISE
|
||||||
|
} else {
|
||||||
|
SelectionType.CHARACTER_WISE
|
||||||
|
}
|
||||||
|
val motion = argument.motion
|
||||||
|
if (!isChange && !motion.isLinewiseMotion()) {
|
||||||
|
val start = editor.offsetToBufferPosition(range.startOffset)
|
||||||
|
val end = editor.offsetToBufferPosition(range.endOffset)
|
||||||
|
if (start.line != end.line) {
|
||||||
|
val offset1 = range.startOffset
|
||||||
|
if (!editor.anyNonWhitespace(offset1, -1)) {
|
||||||
|
val offset = range.endOffset
|
||||||
|
if (!editor.anyNonWhitespace(offset, 1)) {
|
||||||
|
type = SelectionType.LINE_WISE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pair(range, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the case of count characters
|
||||||
|
*
|
||||||
|
* @param editor The editor to change
|
||||||
|
* @param caret The caret on which the operation is performed
|
||||||
|
* @param count The number of characters to change
|
||||||
|
* @return true if able to change count characters
|
||||||
|
*/
|
||||||
|
override fun changeCaseToggleCharacter(editor: VimEditor, caret: VimCaret, count: Int): Boolean {
|
||||||
|
val allowWrap = injector.options(editor).whichwrap.contains("~")
|
||||||
|
var motion = injector.motion.getHorizontalMotion(editor, caret, count, true, allowWrap)
|
||||||
|
if (motion is Motion.Error) return false
|
||||||
|
changeCase(editor, caret, caret.offset, (motion as AbsoluteOffset).offset, CharacterHelper.CASE_TOGGLE)
|
||||||
|
motion = injector.motion.getHorizontalMotion(
|
||||||
|
editor,
|
||||||
|
caret,
|
||||||
|
count,
|
||||||
|
false,
|
||||||
|
allowWrap
|
||||||
|
) // same but without allow end because we can change till end, but can't move caret there
|
||||||
|
if (motion is AbsoluteOffset) {
|
||||||
|
caret.moveToOffset(editor.normalizeOffset(motion.offset, false))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun blockInsert(
|
||||||
|
editor: VimEditor,
|
||||||
|
context: ExecutionContext,
|
||||||
|
range: TextRange,
|
||||||
|
append: Boolean,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Boolean {
|
||||||
|
val lines = getLinesCountInVisualBlock(editor, range)
|
||||||
|
val startPosition = editor.offsetToBufferPosition(range.startOffset)
|
||||||
|
val mode = operatorArguments.mode
|
||||||
|
val visualBlockMode = mode is VISUAL && mode.selectionType === SelectionType.BLOCK_WISE
|
||||||
|
for (caret in editor.carets()) {
|
||||||
|
val line = startPosition.line
|
||||||
|
var column = startPosition.column
|
||||||
|
if (!visualBlockMode) {
|
||||||
|
column = 0
|
||||||
|
} else if (append) {
|
||||||
|
column += range.maxLength
|
||||||
|
if (caret.vimLastColumn == VimMotionGroupBase.LAST_COLUMN) {
|
||||||
|
column = VimMotionGroupBase.LAST_COLUMN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val lineLength = editor.lineLength(line)
|
||||||
|
if (column < VimMotionGroupBase.LAST_COLUMN && lineLength < column) {
|
||||||
|
val pad = EditorHelper.pad((editor as IjVimEditor).editor, line, column)
|
||||||
|
val offset = editor.getLineEndOffset(line)
|
||||||
|
insertText(editor, caret, offset, pad)
|
||||||
|
}
|
||||||
|
if (visualBlockMode || !append) {
|
||||||
|
(caret as IjVimCaret).caret.moveToInlayAwareLogicalPosition(LogicalPosition(line, column))
|
||||||
|
}
|
||||||
|
if (visualBlockMode) {
|
||||||
|
setInsertRepeat(lines, column, append)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (visualBlockMode || !append) {
|
||||||
|
insertBeforeCursor(editor, context)
|
||||||
|
} else {
|
||||||
|
insertAfterCursor(editor, context)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the case of all the characters in the range
|
||||||
|
*
|
||||||
|
* @param editor The editor to change
|
||||||
|
* @param caret The caret to be moved
|
||||||
|
* @param range The range to change
|
||||||
|
* @param type The case change type (TOGGLE, UPPER, LOWER)
|
||||||
|
* @return true if able to delete the text, false if not
|
||||||
|
*/
|
||||||
|
override fun changeCaseRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: Char): Boolean {
|
||||||
|
val starts = range.startOffsets
|
||||||
|
val ends = range.endOffsets
|
||||||
|
for (i in ends.indices.reversed()) {
|
||||||
|
changeCase(editor, caret, starts[i], ends[i], type)
|
||||||
|
}
|
||||||
|
caret.moveToOffset(range.startOffset)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This performs the actual case change.
|
||||||
|
*
|
||||||
|
* @param editor The editor to change
|
||||||
|
* @param start The start offset to change
|
||||||
|
* @param end The end offset to change
|
||||||
|
* @param type The type of change (TOGGLE, UPPER, LOWER)
|
||||||
|
*/
|
||||||
|
private fun changeCase(editor: VimEditor, caret: VimCaret, start: Int, end: Int, type: Char) {
|
||||||
|
var start = start
|
||||||
|
var end = end
|
||||||
|
if (start > end) {
|
||||||
|
val t = end
|
||||||
|
end = start
|
||||||
|
start = t
|
||||||
|
}
|
||||||
|
end = editor.normalizeOffset(end, true)
|
||||||
|
val chars = editor.text()
|
||||||
|
val sb = StringBuilder()
|
||||||
|
for (i in start until end) {
|
||||||
|
sb.append(changeCase(chars[i], type))
|
||||||
|
}
|
||||||
|
replaceText(editor, caret, start, end, sb.toString())
|
||||||
|
}
|
||||||
|
|
||||||
private fun restoreCursor(editor: VimEditor, caret: VimCaret, startLine: Int) {
|
private fun restoreCursor(editor: VimEditor, caret: VimCaret, startLine: Int) {
|
||||||
if (caret != editor.primaryCaret()) {
|
if (caret != editor.primaryCaret()) {
|
||||||
(editor as IjVimEditor).editor.caretModel.addCaret(
|
(editor as IjVimEditor).editor.caretModel.addCaret(
|
||||||
@@ -111,13 +310,88 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reformatCode(editor: VimEditor, start: Int, end: Int) {
|
/**
|
||||||
|
* Changes the case of all the character moved over by the motion argument.
|
||||||
|
*
|
||||||
|
* @param editor The editor to change
|
||||||
|
* @param caret The caret on which motion pretends to be performed
|
||||||
|
* @param context The data context
|
||||||
|
* @param type The case change type (TOGGLE, UPPER, LOWER)
|
||||||
|
* @param argument The motion command
|
||||||
|
* @return true if able to delete the text, false if not
|
||||||
|
*/
|
||||||
|
override fun changeCaseMotion(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext?,
|
||||||
|
type: Char,
|
||||||
|
argument: Argument,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Boolean {
|
||||||
|
val range = injector.motion.getMotionRange(
|
||||||
|
editor, caret, context!!, argument,
|
||||||
|
operatorArguments
|
||||||
|
)
|
||||||
|
return range != null && changeCaseRange(editor, caret, range, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reformatCodeMotion(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Boolean {
|
||||||
|
val range = injector.motion.getMotionRange(
|
||||||
|
editor, caret, context, argument,
|
||||||
|
operatorArguments
|
||||||
|
)
|
||||||
|
return range != null && reformatCodeRange(editor, caret, range)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reformatCodeSelection(editor: VimEditor, caret: VimCaret, range: VimSelection) {
|
||||||
|
val textRange = range.toVimTextRange(true)
|
||||||
|
reformatCodeRange(editor, caret, textRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reformatCodeRange(editor: VimEditor, caret: VimCaret, range: TextRange): Boolean {
|
||||||
|
val starts = range.startOffsets
|
||||||
|
val ends = range.endOffsets
|
||||||
|
val firstLine = editor.offsetToBufferPosition(range.startOffset).line
|
||||||
|
for (i in ends.indices.reversed()) {
|
||||||
|
val startOffset = editor.getLineStartForOffset(starts[i])
|
||||||
|
val offset = ends[i] - if (startOffset == ends[i]) 0 else 1
|
||||||
|
val endOffset = editor.getLineEndForOffset(offset)
|
||||||
|
reformatCode(editor, startOffset, endOffset)
|
||||||
|
}
|
||||||
|
val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
|
||||||
|
caret.moveToOffset(newOffset)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reformatCode(editor: VimEditor, start: Int, end: Int) {
|
||||||
val project = (editor as IjVimEditor).editor.project ?: return
|
val project = (editor as IjVimEditor).editor.project ?: return
|
||||||
val file = PsiUtilBase.getPsiFileInEditor(editor.editor, project) ?: return
|
val file = PsiUtilBase.getPsiFileInEditor(editor.editor, project) ?: return
|
||||||
val textRange = com.intellij.openapi.util.TextRange.create(start, end)
|
val textRange = com.intellij.openapi.util.TextRange.create(start, end)
|
||||||
CodeStyleManager.getInstance(project).reformatText(file, listOf(textRange))
|
CodeStyleManager.getInstance(project).reformatText(file, listOf(textRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun autoIndentMotion(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
) {
|
||||||
|
val range = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments)
|
||||||
|
if (range != null) {
|
||||||
|
autoIndentRange(
|
||||||
|
editor, caret, context,
|
||||||
|
TextRange(range.startOffset, range.endOffsetInclusive)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun autoIndentRange(
|
override fun autoIndentRange(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
caret: VimCaret,
|
caret: VimCaret,
|
||||||
@@ -172,14 +446,361 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(message = "Please use listenersNotifier", replaceWith = ReplaceWith("injector.listenersNotifier.modeChangeListeners.add", imports = ["import com.maddyhome.idea.vim.api.injector"]))
|
override fun indentLines(
|
||||||
fun addInsertListener(listener: VimInsertListener) {
|
editor: VimEditor,
|
||||||
injector.listenersNotifier.modeChangeListeners.add(listener)
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
lines: Int,
|
||||||
|
dir: Int,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
) {
|
||||||
|
val start = caret.offset
|
||||||
|
val end = injector.motion.moveCaretToRelativeLineEnd(editor, caret, lines - 1, true)
|
||||||
|
indentRange(editor, caret, context, TextRange(start, end), 1, dir, operatorArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun indentMotion(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument,
|
||||||
|
dir: Int,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
) {
|
||||||
|
val range = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments)
|
||||||
|
if (range != null) {
|
||||||
|
indentRange(editor, caret, context, range, 1, dir, operatorArguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun indentRange(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
range: TextRange,
|
||||||
|
count: Int,
|
||||||
|
dir: Int,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
) {
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
logger.debug("count=$count")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the current caret column
|
||||||
|
val intendedColumn = caret.vimLastColumn
|
||||||
|
val indentConfig = create((editor as IjVimEditor).editor)
|
||||||
|
val sline = editor.offsetToBufferPosition(range.startOffset).line
|
||||||
|
val endLogicalPosition = editor.offsetToBufferPosition(range.endOffset)
|
||||||
|
val eline = if (endLogicalPosition.column == 0) max((endLogicalPosition.line - 1).toDouble(), 0.0)
|
||||||
|
.toInt() else endLogicalPosition.line
|
||||||
|
if (range.isMultiple) {
|
||||||
|
val from = editor.offsetToBufferPosition(range.startOffset).column
|
||||||
|
if (dir == 1) {
|
||||||
|
// Right shift blockwise selection
|
||||||
|
val indent = indentConfig.createIndentByCount(count)
|
||||||
|
for (l in sline..eline) {
|
||||||
|
val len = editor.lineLength(l)
|
||||||
|
if (len > from) {
|
||||||
|
val spos = BufferPosition(l, from, false)
|
||||||
|
insertText(editor, caret, spos, indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Left shift blockwise selection
|
||||||
|
val chars = editor.text()
|
||||||
|
for (l in sline..eline) {
|
||||||
|
val len = editor.lineLength(l)
|
||||||
|
if (len > from) {
|
||||||
|
val spos = BufferPosition(l, from, false)
|
||||||
|
val epos = BufferPosition(l, from + indentConfig.getTotalIndent(count) - 1, false)
|
||||||
|
val wsoff = editor.bufferPositionToOffset(spos)
|
||||||
|
val weoff = editor.bufferPositionToOffset(epos)
|
||||||
|
var pos: Int
|
||||||
|
pos = wsoff
|
||||||
|
while (pos <= weoff) {
|
||||||
|
if (charType(editor, chars[pos], false) !== CharacterHelper.CharacterType.WHITESPACE) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if (pos > wsoff) {
|
||||||
|
deleteText(editor, TextRange(wsoff, pos), null, caret, operatorArguments, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Shift non-blockwise selection
|
||||||
|
for (l in sline..eline) {
|
||||||
|
val soff = editor.getLineStartOffset(l)
|
||||||
|
val eoff = editor.getLineEndOffset(l, true)
|
||||||
|
val woff = injector.motion.moveCaretToLineStartSkipLeading(editor, l)
|
||||||
|
val col = editor.offsetToBufferPosition(woff).column
|
||||||
|
val limit = max(0.0, (col + dir * indentConfig.getTotalIndent(count)).toDouble())
|
||||||
|
.toInt()
|
||||||
|
if (col > 0 || soff != eoff) {
|
||||||
|
val indent = indentConfig.createIndentBySize(limit)
|
||||||
|
replaceText(editor, caret, soff, woff, indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!editor.editor.inInsertMode) {
|
||||||
|
if (!range.isMultiple) {
|
||||||
|
// The caret has moved, so reset the intended column before trying to get the expected offset
|
||||||
|
val newCaret = caret.setVimLastColumnAndGetCaret(intendedColumn)
|
||||||
|
val offset = injector.motion.moveCaretToLineWithStartOfLineOption(editor, sline, caret)
|
||||||
|
newCaret.moveToOffset(offset)
|
||||||
|
} else {
|
||||||
|
caret.moveToOffset(range.startOffset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort range of text with a given comparator
|
||||||
|
*
|
||||||
|
* @param editor The editor to replace text in
|
||||||
|
* @param range The range to sort
|
||||||
|
* @param lineComparator The comparator to use to sort
|
||||||
|
* @param sortOptions The option to sort the range
|
||||||
|
* @return true if able to sort the text, false if not
|
||||||
|
*/
|
||||||
|
override fun sortRange(
|
||||||
|
editor: VimEditor, caret: VimCaret, range: LineRange, lineComparator: Comparator<String>,
|
||||||
|
sortOptions: SortOption,
|
||||||
|
): Boolean {
|
||||||
|
val startLine = range.startLine
|
||||||
|
val endLine = range.endLine
|
||||||
|
val count = range.size
|
||||||
|
if (count < 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val startOffset = editor.getLineStartOffset(startLine)
|
||||||
|
val endOffset = editor.getLineEndOffset(endLine)
|
||||||
|
|
||||||
|
val selectedText = (editor as IjVimEditor).editor.document.getText(TextRangeInterval(startOffset, endOffset))
|
||||||
|
val lines = selectedText.split("\n")
|
||||||
|
val modifiedLines = sortOptions.pattern?.let {
|
||||||
|
if (sortOptions.sortOnPattern) {
|
||||||
|
extractPatternFromLines(editor, lines, startLine, it)
|
||||||
|
} else {
|
||||||
|
deletePatternFromLines(editor, lines, startLine, it)
|
||||||
|
}
|
||||||
|
} ?: lines
|
||||||
|
val sortedLines = lines.zip(modifiedLines)
|
||||||
|
.sortedWith { l1, l2 -> lineComparator.compare(l1.second, l2.second) }
|
||||||
|
.map {it.first}
|
||||||
|
.toMutableList()
|
||||||
|
|
||||||
|
if (sortOptions.unique) {
|
||||||
|
val iterator = sortedLines.iterator()
|
||||||
|
var previous: String? = null
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val current = iterator.next()
|
||||||
|
if (current == previous || sortOptions.ignoreCase && current.equals(previous, ignoreCase = true)) {
|
||||||
|
iterator.remove()
|
||||||
|
} else {
|
||||||
|
previous = current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortedLines.isEmpty()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
replaceText(editor, caret, startOffset, endOffset, StringUtil.join(sortedLines, "\n"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractPatternFromLines(editor: VimEditor, lines: List<String>, startLine: Int, pattern: String): List<String> {
|
||||||
|
val regex = VimRegex(pattern)
|
||||||
|
return lines.mapIndexed { i: Int, line: String ->
|
||||||
|
val result = regex.findInLine(editor, startLine + i, 0)
|
||||||
|
when (result) {
|
||||||
|
is VimMatchResult.Success -> result.value
|
||||||
|
is VimMatchResult.Failure -> line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deletePatternFromLines(editor: VimEditor, lines: List<String>, startLine: Int, pattern: String): List<String> {
|
||||||
|
val regex = VimRegex(pattern)
|
||||||
|
return lines.mapIndexed { i: Int, line: String ->
|
||||||
|
val result = regex.findInLine(editor, startLine + i, 0)
|
||||||
|
when (result) {
|
||||||
|
is VimMatchResult.Success -> line.substring(result.value.length, line.length)
|
||||||
|
is VimMatchResult.Failure -> line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform increment and decrement for numbers in visual mode
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Flag [avalanche] marks if increment (or decrement) should be performed in avalanche mode
|
||||||
|
* (for v_g_Ctrl-A and v_g_Ctrl-X commands)
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
override fun changeNumberVisualMode(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: VimCaret,
|
||||||
|
selectedRange: TextRange,
|
||||||
|
count: Int,
|
||||||
|
avalanche: Boolean,
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
val nf: List<String> = injector.options(editor).nrformats
|
||||||
|
val alpha = nf.contains("alpha")
|
||||||
|
val hex = nf.contains("hex")
|
||||||
|
val octal = nf.contains("octal")
|
||||||
|
val numberRanges = findNumbersInRange((editor as IjVimEditor).editor, selectedRange, alpha, hex, octal)
|
||||||
|
val newNumbers: MutableList<String?> = ArrayList()
|
||||||
|
for (i in numberRanges.indices) {
|
||||||
|
val numberRange = numberRanges[i]
|
||||||
|
val iCount = if (avalanche) (i + 1) * count else count
|
||||||
|
val newNumber = changeNumberInRange(editor, numberRange, iCount, alpha, hex, octal)
|
||||||
|
newNumbers.add(newNumber)
|
||||||
|
}
|
||||||
|
for (i in newNumbers.indices.reversed()) {
|
||||||
|
// Replace text bottom up. In other direction ranges will be desynchronized after inc numbers like 99
|
||||||
|
val (first) = numberRanges[i]
|
||||||
|
val newNumber = newNumbers[i]
|
||||||
|
replaceText(editor, caret, first.startOffset, first.endOffset, newNumber!!)
|
||||||
|
}
|
||||||
|
(caret as IjVimCaret).caret.moveToInlayAwareOffset(selectedRange.startOffset)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun changeNumber(editor: VimEditor, caret: VimCaret, count: Int): Boolean {
|
||||||
|
val nf: List<String> = injector.options(editor).nrformats
|
||||||
|
val alpha = nf.contains("alpha")
|
||||||
|
val hex = nf.contains("hex")
|
||||||
|
val octal = nf.contains("octal")
|
||||||
|
val range = findNumberUnderCursor((editor as IjVimEditor).editor, (caret as IjVimCaret).caret, alpha, hex, octal)
|
||||||
|
if (range == null) {
|
||||||
|
logger.debug("no number on line")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val newNumber = changeNumberInRange(editor, range, count, alpha, hex, octal)
|
||||||
|
return if (newNumber == null) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
replaceText(editor, caret, range.first.startOffset, range.first.endOffset, newNumber)
|
||||||
|
caret.caret.moveToInlayAwareOffset(range.first.startOffset + newNumber.length - 1)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
strokes.clear()
|
||||||
|
repeatCharsCount = 0
|
||||||
|
if (lastStrokes != null) {
|
||||||
|
lastStrokes!!.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveStrokes(newStrokes: String?) {
|
||||||
|
val chars = newStrokes!!.toCharArray()
|
||||||
|
strokes.add(chars)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeNumberInRange(
|
||||||
|
editor: VimEditor,
|
||||||
|
range: Pair<TextRange, NumberType>,
|
||||||
|
count: Int,
|
||||||
|
alpha: Boolean,
|
||||||
|
hex: Boolean,
|
||||||
|
octal: Boolean,
|
||||||
|
): String? {
|
||||||
|
val text = editor.getText(range.first)
|
||||||
|
val numberType = range.second
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
logger.debug("found range $range")
|
||||||
|
logger.debug("text=$text")
|
||||||
|
}
|
||||||
|
var number = text
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
var ch = text[0]
|
||||||
|
if (hex && NumberType.HEX == numberType) {
|
||||||
|
if (!text.lowercase(Locale.getDefault()).startsWith(HEX_START)) {
|
||||||
|
throw RuntimeException("Hex number should start with 0x: $text")
|
||||||
|
}
|
||||||
|
for (i in text.length - 1 downTo 2) {
|
||||||
|
val index = "abcdefABCDEF".indexOf(text[i])
|
||||||
|
if (index >= 0) {
|
||||||
|
lastLower = index < 6
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var num = BigInteger(text.substring(2), 16)
|
||||||
|
num = num.add(BigInteger.valueOf(count.toLong()))
|
||||||
|
if (num.compareTo(BigInteger.ZERO) < 0) {
|
||||||
|
num = BigInteger(MAX_HEX_INTEGER, 16).add(BigInteger.ONE).add(num)
|
||||||
|
}
|
||||||
|
number = num.toString(16)
|
||||||
|
number = number.padStart(text.length - 2, '0')
|
||||||
|
if (!lastLower) {
|
||||||
|
number = number.uppercase(Locale.getDefault())
|
||||||
|
}
|
||||||
|
number = text.substring(0, 2) + number
|
||||||
|
} else if (octal && NumberType.OCT == numberType && text.length > 1) {
|
||||||
|
if (!text.startsWith("0")) throw RuntimeException("Oct number should start with 0: $text")
|
||||||
|
var num = BigInteger(text, 8).add(BigInteger.valueOf(count.toLong()))
|
||||||
|
if (num.compareTo(BigInteger.ZERO) < 0) {
|
||||||
|
num = BigInteger("1777777777777777777777", 8).add(BigInteger.ONE).add(num)
|
||||||
|
}
|
||||||
|
number = num.toString(8)
|
||||||
|
number = "0" + number.padStart(text.length - 1, '0')
|
||||||
|
} else if (alpha && NumberType.ALPHA == numberType) {
|
||||||
|
if (!Character.isLetter(ch)) throw RuntimeException("Not alpha number : $text")
|
||||||
|
ch += count.toChar().code
|
||||||
|
if (Character.isLetter(ch)) {
|
||||||
|
number = ch.toString()
|
||||||
|
}
|
||||||
|
} else if (NumberType.DEC == numberType) {
|
||||||
|
if (ch != '-' && !Character.isDigit(ch)) throw RuntimeException("Not dec number : $text")
|
||||||
|
var pad = ch == '0'
|
||||||
|
var len = text.length
|
||||||
|
if (ch == '-' && text[1] == '0') {
|
||||||
|
pad = true
|
||||||
|
len--
|
||||||
|
}
|
||||||
|
var num = BigInteger(text)
|
||||||
|
num = num.add(BigInteger.valueOf(count.toLong()))
|
||||||
|
number = num.toString()
|
||||||
|
if (!octal && pad) {
|
||||||
|
var neg = false
|
||||||
|
if (number[0] == '-') {
|
||||||
|
neg = true
|
||||||
|
number = number.substring(1)
|
||||||
|
}
|
||||||
|
number = number.padStart(len, '0')
|
||||||
|
if (neg) {
|
||||||
|
number = "-$number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return number
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addInsertListener(listener: VimInsertListener) {
|
||||||
|
insertListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(message = "Please use listenersNotifier", replaceWith = ReplaceWith("injector.listenersNotifier.modeChangeListeners.remove", imports = ["import com.maddyhome.idea.vim.api.injector"]))
|
|
||||||
fun removeInsertListener(listener: VimInsertListener) {
|
fun removeInsertListener(listener: VimInsertListener) {
|
||||||
injector.listenersNotifier.modeChangeListeners.remove(listener)
|
insertListeners.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun notifyListeners(editor: VimEditor) {
|
||||||
|
insertListeners.forEach(Consumer { listener: VimInsertListener -> listener.insertModeStarted((editor as IjVimEditor).editor) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
|
override fun resetRepeat() {
|
||||||
|
setInsertRepeat(0, 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@@ -11,14 +11,11 @@ package com.maddyhome.idea.vim.group;
|
|||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
|
import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
|
||||||
import com.maddyhome.idea.vim.api.VimEditor;
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanel;
|
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper;
|
import com.maddyhome.idea.vim.helper.EditorHelper;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
|
|
||||||
|
|
||||||
public class DigraphGroup extends VimDigraphGroupBase {
|
public class DigraphGroup extends VimDigraphGroupBase {
|
||||||
|
|
||||||
public void showDigraphs(@NotNull VimEditor editor) {
|
public void showDigraphs(@NotNull VimEditor editor) {
|
||||||
@@ -74,9 +71,7 @@ public class DigraphGroup extends VimDigraphGroupBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VimOutputPanel output = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
|
ExOutputModel.getInstance(((IjVimEditor) editor).getEditor()).output(res.toString());
|
||||||
output.addText(res.toString(), true );
|
|
||||||
output.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
|
private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
|
||||||
|
@@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.group;
|
package com.maddyhome.idea.vim.group;
|
||||||
|
|
||||||
|
import com.intellij.execution.impl.ConsoleViewImpl;
|
||||||
import com.intellij.find.EditorSearchSession;
|
import com.intellij.find.EditorSearchSession;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.client.ClientAppSession;
|
import com.intellij.openapi.client.ClientAppSession;
|
||||||
import com.intellij.openapi.client.ClientKind;
|
import com.intellij.openapi.client.ClientKind;
|
||||||
import com.intellij.openapi.client.ClientSessionsManager;
|
import com.intellij.openapi.client.ClientSessionsManager;
|
||||||
@@ -21,10 +23,12 @@ import com.intellij.openapi.editor.event.CaretListener;
|
|||||||
import com.intellij.openapi.editor.ex.EditorEx;
|
import com.intellij.openapi.editor.ex.EditorEx;
|
||||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.api.*;
|
import com.maddyhome.idea.vim.api.*;
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
import com.maddyhome.idea.vim.helper.CaretVisualAttributesHelperKt;
|
import com.maddyhome.idea.vim.helper.CaretVisualAttributesHelperKt;
|
||||||
|
import com.maddyhome.idea.vim.helper.CommandStateHelper;
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper;
|
import com.maddyhome.idea.vim.helper.EditorHelper;
|
||||||
import com.maddyhome.idea.vim.helper.UserDataManager;
|
import com.maddyhome.idea.vim.helper.UserDataManager;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimDocument;
|
import com.maddyhome.idea.vim.newapi.IjVimDocument;
|
||||||
@@ -214,9 +218,46 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
editorEx.addPropertyChangeListener(FontSizeChangeListener.INSTANCE);
|
editorEx.addPropertyChangeListener(FontSizeChangeListener.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (injector.getApplication().isUnitTest()) {
|
// We add Vim bindings to all opened editors, including editors used as UI controls rather than just project file
|
||||||
updateCaretsVisualAttributes(new IjVimEditor(editor));
|
// editors. This includes editors used as part of the UI, such as the VCS commit message, or used as read-only
|
||||||
|
// viewers for text output, such as log files in run configurations or the Git Console tab. And editors are used for
|
||||||
|
// interactive stdin/stdout for console-based run configurations.
|
||||||
|
// We want to provide an intuitive experience for working with these additional editors, so we automatically switch
|
||||||
|
// to INSERT mode if they are interactive editors. Recognising these can be a bit tricky.
|
||||||
|
// These additional interactive editors are not file-based, but must have a writable document. However, log output
|
||||||
|
// documents are also writable (the IDE is writing new content as it becomes available) just not user-editable. So
|
||||||
|
// we must also check that the editor is not in read-only "viewer" mode (this includes "rendered" mode, which is
|
||||||
|
// read-only and also hides the caret).
|
||||||
|
// Furthermore, interactive stdin/stdout console output in run configurations is hosted in a read-only editor, but
|
||||||
|
// it can still be edited. The `ConsoleViewImpl` class installs a typing handler that ignores the editor's
|
||||||
|
// `isViewer` property and allows typing if the associated process (if any) is still running. We can get the
|
||||||
|
// editor's console view and check this ourselves, but we have to wait until the editor has finished initialising
|
||||||
|
// before it's available in user data.
|
||||||
|
// Finally, we have a special check for diff windows. If we compare against clipboard, we get a diff editor that is
|
||||||
|
// not file based, is writable, and not a viewer, but we don't want to treat this as an interactive editor.
|
||||||
|
// Note that we need a similar check in `VimEditor.isWritable` to allow Escape to work to exit insert mode. We need
|
||||||
|
// to know that a read-only editor that is hosting a console view with a running process can be treated as writable.
|
||||||
|
Runnable switchToInsertMode = () -> {
|
||||||
|
ExecutionContext context = injector.getExecutionContextManager().getEditorExecutionContext(new IjVimEditor(editor));
|
||||||
|
VimPlugin.getChange().insertBeforeCursor(new IjVimEditor(editor), context);
|
||||||
|
KeyHandler.getInstance().reset(new IjVimEditor(editor));
|
||||||
|
};
|
||||||
|
if (!editor.isViewer() &&
|
||||||
|
!EditorHelper.isFileEditor(editor) &&
|
||||||
|
editor.getDocument().isWritable() &&
|
||||||
|
!CommandStateHelper.inInsertMode(editor) &&
|
||||||
|
editor.getEditorKind() != EditorKind.DIFF) {
|
||||||
|
switchToInsertMode.run();
|
||||||
}
|
}
|
||||||
|
ApplicationManager.getApplication().invokeLater(
|
||||||
|
() -> {
|
||||||
|
if (editor.isDisposed()) return;
|
||||||
|
ConsoleViewImpl consoleView = editor.getUserData(ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW);
|
||||||
|
if (consoleView != null && consoleView.isRunning() && !CommandStateHelper.inInsertMode(editor)) {
|
||||||
|
switchToInsertMode.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateCaretsVisualAttributes(new IjVimEditor(editor));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editorDeinit(@NotNull Editor editor) {
|
public void editorDeinit(@NotNull Editor editor) {
|
||||||
@@ -238,8 +279,9 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
VimPlugin.getNotifications(project).notifyAboutIdeaJoin(editor);
|
VimPlugin.getNotifications(project).notifyAboutIdeaJoin(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Element getState() {
|
public Element getState() {
|
||||||
Element element = new Element("editor");
|
Element element = new Element("editor");
|
||||||
saveData(element);
|
saveData(element);
|
||||||
return element;
|
return element;
|
||||||
@@ -315,16 +357,18 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Collection<VimEditor> getEditors() {
|
public Collection<VimEditor> getEditors() {
|
||||||
return getLocalEditors()
|
return getLocalEditors()
|
||||||
.filter(UserDataManager::getVimInitialised)
|
.filter(UserDataManager::getVimInitialised)
|
||||||
.map(IjVimEditor::new)
|
.map(IjVimEditor::new)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Collection<VimEditor> getEditors(@NotNull VimDocument buffer) {
|
public Collection<VimEditor> getEditors(@NotNull VimDocument buffer) {
|
||||||
final Document document = ((IjVimDocument)buffer).getDocument();
|
final Document document = ((IjVimDocument)buffer).getDocument();
|
||||||
return getLocalEditors()
|
return getLocalEditors()
|
||||||
.filter(editor -> UserDataManager.getVimInitialised(editor) && editor.getDocument().equals(document))
|
.filter(editor -> UserDataManager.getVimInitialised(editor) && editor.getDocument().equals(document))
|
||||||
@@ -344,7 +388,7 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
// events such as document change (to update search highlights), and these can come from CWM guests, and we'd get
|
// events such as document change (to update search highlights), and these can come from CWM guests, and we'd get
|
||||||
// the remote editors.
|
// the remote editors.
|
||||||
// This invocation will always get local editors, regardless of the current context.
|
// This invocation will always get local editors, regardless of the current context.
|
||||||
List<ClientAppSession> appSessions = ClientSessionsManager.getAppSessions(ClientKind.LOCAL);
|
List<ClientAppSession> appSessions = ClientSessionsManager.getAppSessions(ClientKind.ALL);
|
||||||
if (!appSessions.isEmpty()) {
|
if (!appSessions.isEmpty()) {
|
||||||
ClientAppSession localSession = appSessions.get(0);
|
ClientAppSession localSession = appSessions.get(0);
|
||||||
return localSession.getService(ClientEditorManager.class).editors();
|
return localSession.getService(ClientEditorManager.class).editors();
|
||||||
@@ -372,15 +416,11 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
// Note that IDE scale is handled by LafManager.lookAndFeelChanged
|
// Note that IDE scale is handled by LafManager.lookAndFeelChanged
|
||||||
VimCommandLine activeCommandLine = injector.getCommandLine().getActiveCommandLine();
|
VimCommandLine activeCommandLine = injector.getCommandLine().getActiveCommandLine();
|
||||||
if (activeCommandLine != null) {
|
if (activeCommandLine != null) {
|
||||||
activeCommandLine.close(true, false);
|
injector.getProcessGroup().cancelExEntry(new IjVimEditor(editor), false);
|
||||||
}
|
}
|
||||||
VimOutputPanel outputPanel = injector.getOutputPanel().getCurrentOutputPanel();
|
ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
|
||||||
if (outputPanel != null) {
|
if (exOutputModel != null) {
|
||||||
outputPanel.close();
|
exOutputModel.close();
|
||||||
}
|
|
||||||
VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
|
|
||||||
if (modalInput != null) {
|
|
||||||
modalInput.deactivate(true, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -173,20 +173,20 @@ class FileGroup : VimFileBase() {
|
|||||||
/**
|
/**
|
||||||
* Saves specific file in the project.
|
* Saves specific file in the project.
|
||||||
*/
|
*/
|
||||||
override fun saveFile(editor: VimEditor, context: ExecutionContext) {
|
override fun saveFile(context: ExecutionContext) {
|
||||||
val action = if (injector.globalIjOptions().ideawrite.contains(IjOptionConstants.ideawrite_all)) {
|
val action = if (injector.globalIjOptions().ideawrite.contains(IjOptionConstants.ideawrite_all)) {
|
||||||
injector.nativeActionManager.saveAll
|
injector.nativeActionManager.saveAll
|
||||||
} else {
|
} else {
|
||||||
injector.nativeActionManager.saveCurrent
|
injector.nativeActionManager.saveCurrent
|
||||||
}
|
}
|
||||||
action.execute(editor, context)
|
action.execute(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves all files in the project.
|
* Saves all files in the project.
|
||||||
*/
|
*/
|
||||||
override fun saveFiles(editor: VimEditor, context: ExecutionContext) {
|
override fun saveFiles(context: ExecutionContext) {
|
||||||
injector.nativeActionManager.saveAll.execute(editor, context)
|
injector.nativeActionManager.saveAll.execute(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -271,7 +271,7 @@ class FileGroup : VimFileBase() {
|
|||||||
val msg = StringBuilder()
|
val msg = StringBuilder()
|
||||||
val doc = editor.document
|
val doc = editor.document
|
||||||
|
|
||||||
if (injector.vimState.mode !is VISUAL) {
|
if (getInstance(IjVimEditor(editor)).mode !is VISUAL) {
|
||||||
val lp = editor.caretModel.logicalPosition
|
val lp = editor.caretModel.logicalPosition
|
||||||
val col = editor.caretModel.offset - doc.getLineStartOffset(lp.line)
|
val col = editor.caretModel.offset - doc.getLineStartOffset(lp.line)
|
||||||
var endoff = doc.getLineEndOffset(lp.line)
|
var endoff = doc.getLineEndOffset(lp.line)
|
||||||
|
@@ -14,7 +14,9 @@ import com.intellij.openapi.components.State;
|
|||||||
import com.intellij.openapi.components.Storage;
|
import com.intellij.openapi.components.Storage;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.history.*;
|
import com.maddyhome.idea.vim.history.HistoryBlock;
|
||||||
|
import com.maddyhome.idea.vim.history.HistoryEntry;
|
||||||
|
import com.maddyhome.idea.vim.history.VimHistoryBase;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -33,20 +35,21 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
logger.debug("saveData");
|
logger.debug("saveData");
|
||||||
Element hist = new Element("history");
|
Element hist = new Element("history");
|
||||||
|
|
||||||
for (Type type : getHistories().keySet()) {
|
saveData(hist, SEARCH);
|
||||||
saveData(hist, type);
|
saveData(hist, COMMAND);
|
||||||
}
|
saveData(hist, EXPRESSION);
|
||||||
|
saveData(hist, INPUT);
|
||||||
|
|
||||||
element.addContent(hist);
|
element.addContent(hist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveData(@NotNull Element element, VimHistory.Type type) {
|
private void saveData(@NotNull Element element, String key) {
|
||||||
final HistoryBlock block = getHistories().get(type);
|
final HistoryBlock block = getHistories().get(key);
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Element root = new Element("history-" + typeToKey(type));
|
final Element root = new Element("history-" + key);
|
||||||
|
|
||||||
for (HistoryEntry entry : block.getEntries()) {
|
for (HistoryEntry entry : block.getEntries()) {
|
||||||
final Element entryElement = new Element("entry");
|
final Element entryElement = new Element("entry");
|
||||||
@@ -64,10 +67,10 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Element child : hist.getChildren()) {
|
readData(hist, SEARCH);
|
||||||
String key = child.getName().replace("history-", "");
|
readData(hist, COMMAND);
|
||||||
readData(hist, key);
|
readData(hist, EXPRESSION);
|
||||||
}
|
readData(hist, INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readData(@NotNull Element element, String key) {
|
private void readData(@NotNull Element element, String key) {
|
||||||
@@ -77,7 +80,7 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
}
|
}
|
||||||
|
|
||||||
block = new HistoryBlock();
|
block = new HistoryBlock();
|
||||||
getHistories().put(getTypeForString(key), block);
|
getHistories().put(key, block);
|
||||||
|
|
||||||
final Element root = element.getChild("history-" + key);
|
final Element root = element.getChild("history-" + key);
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
@@ -91,25 +94,6 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String typeToKey(VimHistory.Type type) {
|
|
||||||
if (type instanceof VimHistory.Type.Search) {
|
|
||||||
return SEARCH;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Command) {
|
|
||||||
return COMMAND;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Expression) {
|
|
||||||
return EXPRESSION;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Input) {
|
|
||||||
return INPUT;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Custom) {
|
|
||||||
return ((Type.Custom) type).getId();
|
|
||||||
}
|
|
||||||
return "unreachable";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Element getState() {
|
public Element getState() {
|
||||||
|
@@ -26,7 +26,7 @@ class IjVimPsiService: VimPsiService {
|
|||||||
val psiFile = PsiHelper.getFile(editor.ij) ?: return null
|
val psiFile = PsiHelper.getFile(editor.ij) ?: return null
|
||||||
val psiElement = psiFile.findElementAt(pos) ?: return null
|
val psiElement = psiFile.findElementAt(pos) ?: return null
|
||||||
val language = psiElement.language
|
val language = psiElement.language
|
||||||
val commenter = LanguageCommenters.INSTANCE.forLanguage(language) ?: return null
|
val commenter = LanguageCommenters.INSTANCE.forLanguage(language)
|
||||||
val psiComment = PsiTreeUtil.getParentOfType(psiElement, PsiComment::class.java, false) ?: return null
|
val psiComment = PsiTreeUtil.getParentOfType(psiElement, PsiComment::class.java, false) ?: return null
|
||||||
val commentText = psiComment.text
|
val commentText = psiComment.text
|
||||||
|
|
||||||
|
@@ -26,7 +26,10 @@ import com.maddyhome.idea.vim.EventFacade;
|
|||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
||||||
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
|
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
|
||||||
import com.maddyhome.idea.vim.api.*;
|
import com.maddyhome.idea.vim.api.NativeAction;
|
||||||
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
|
import com.maddyhome.idea.vim.api.VimInjectorKt;
|
||||||
|
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
|
||||||
import com.maddyhome.idea.vim.command.MappingMode;
|
import com.maddyhome.idea.vim.command.MappingMode;
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
import com.maddyhome.idea.vim.key.*;
|
import com.maddyhome.idea.vim.key.*;
|
||||||
@@ -77,6 +80,25 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
((IjVimEditor)editor).getEditor().getComponent());
|
((IjVimEditor)editor).getEditor().getComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull Editor editor) {
|
||||||
|
List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
|
||||||
|
MappingInfo mappingInfo = row.getSecond();
|
||||||
|
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(mappingInfo.isRecursive() ? " " : "*");
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(mappingInfo.getPresentableString());
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
ExOutputModel.getInstance(editor).output(builder.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateShortcutKeysRegistration() {
|
public void updateShortcutKeysRegistration() {
|
||||||
for (VimEditor editor : injector.getEditorGroup().getEditors()) {
|
for (VimEditor editor : injector.getEditorGroup().getEditors()) {
|
||||||
@@ -336,22 +358,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
|
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
|
||||||
List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
|
return showKeyMappings(modes, ((IjVimEditor) editor).getEditor());
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
|
|
||||||
MappingInfo mappingInfo = row.getSecond();
|
|
||||||
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
|
|
||||||
builder.append(" ");
|
|
||||||
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
|
|
||||||
builder.append(" ");
|
|
||||||
builder.append(mappingInfo.isRecursive() ? " " : "*");
|
|
||||||
builder.append(" ");
|
|
||||||
builder.append(mappingInfo.getPresentableString());
|
|
||||||
builder.append("\n");
|
|
||||||
}
|
|
||||||
VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
|
|
||||||
outputPanel.addText(builder.toString(), true);
|
|
||||||
outputPanel.show();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,14 +47,12 @@ import com.maddyhome.idea.vim.helper.getNormalizedScrollOffset
|
|||||||
import com.maddyhome.idea.vim.helper.getNormalizedSideScrollOffset
|
import com.maddyhome.idea.vim.helper.getNormalizedSideScrollOffset
|
||||||
import com.maddyhome.idea.vim.helper.isEndAllowed
|
import com.maddyhome.idea.vim.helper.isEndAllowed
|
||||||
import com.maddyhome.idea.vim.helper.vimLastColumn
|
import com.maddyhome.idea.vim.helper.vimLastColumn
|
||||||
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.listener.AppCodeTemplates
|
import com.maddyhome.idea.vim.listener.AppCodeTemplates
|
||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.ReturnTo
|
|
||||||
import com.maddyhome.idea.vim.state.mode.returnTo
|
|
||||||
import org.jetbrains.annotations.Range
|
import org.jetbrains.annotations.Range
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -309,32 +307,19 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
val editor = fileEditor.editor
|
val editor = fileEditor.editor
|
||||||
if (!editor.isDisposed) {
|
if (!editor.isDisposed) {
|
||||||
editor.vim.let { vimEditor ->
|
editor.vim.let { vimEditor ->
|
||||||
when (vimEditor.mode) {
|
when (vimEditor.vimStateMachine.mode) {
|
||||||
is Mode.VISUAL -> {
|
is Mode.VISUAL -> {
|
||||||
vimEditor.exitVisualMode()
|
vimEditor.exitVisualMode()
|
||||||
KeyHandler.getInstance().reset(vimEditor)
|
KeyHandler.getInstance().reset(vimEditor)
|
||||||
}
|
}
|
||||||
is Mode.CMD_LINE -> {
|
is Mode.CMD_LINE -> {
|
||||||
val commandLine = injector.commandLine.getActiveCommandLine() ?: return
|
injector.processGroup.cancelExEntry(vimEditor, false)
|
||||||
commandLine.close(refocusOwningEditor = false, resetCaret = false)
|
ExOutputModel.tryGetInstance(editor)?.close()
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val state = injector.vimState as VimStateMachineImpl
|
|
||||||
if (state.mode is Mode.VISUAL) {
|
|
||||||
val returnTo = state.mode.returnTo
|
|
||||||
when (returnTo) {
|
|
||||||
ReturnTo.INSERT -> state.mode = Mode.INSERT
|
|
||||||
ReturnTo.REPLACE -> state.mode = Mode.REPLACE
|
|
||||||
null -> state.mode = Mode.NORMAL()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val keyHandler = KeyHandler.getInstance()
|
|
||||||
KeyHandler.getInstance().reset(keyHandler.keyHandlerState, state.mode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,25 +62,6 @@ internal class NotificationService(private val project: Project?) {
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
constructor() : this(null)
|
constructor() : this(null)
|
||||||
|
|
||||||
fun notifyAboutNewUndo() {
|
|
||||||
val notification = Notification(
|
|
||||||
IDEAVIM_NOTIFICATION_ID,
|
|
||||||
"Undo in IdeaVim now works like in Vim",
|
|
||||||
"""
|
|
||||||
Caret movement is no longer a separate undo step, and full insert is undoable in one step.
|
|
||||||
""".trimIndent(),
|
|
||||||
NotificationType.INFORMATION,
|
|
||||||
)
|
|
||||||
|
|
||||||
notification.addAction(object : DumbAwareAction("Share Feedback") {
|
|
||||||
override fun actionPerformed(p0: AnActionEvent) {
|
|
||||||
BrowserUtil.browse("https://youtrack.jetbrains.com/issue/VIM-547/Undo-splits-Insert-mode-edits-into-separate-undo-chunks")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
notification.notify(project)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun notifyAboutIdeaPut() {
|
fun notifyAboutIdeaPut() {
|
||||||
val notification = Notification(
|
val notification = Notification(
|
||||||
IDEAVIM_NOTIFICATION_ID,
|
IDEAVIM_NOTIFICATION_ID,
|
||||||
@@ -201,8 +182,8 @@ internal class NotificationService(private val project: Project?) {
|
|||||||
).notify(project)
|
).notify(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyActionId(id: String?, candidates: List<String>? = null) {
|
fun notifyActionId(id: String?) {
|
||||||
ActionIdNotifier.notifyActionId(id, project, candidates)
|
ActionIdNotifier.notifyActionId(id, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyKeymapIssues(issues: ArrayList<KeyMapIssue>) {
|
fun notifyKeymapIssues(issues: ArrayList<KeyMapIssue>) {
|
||||||
@@ -278,31 +259,20 @@ internal class NotificationService(private val project: Project?) {
|
|||||||
|
|
||||||
object ActionIdNotifier {
|
object ActionIdNotifier {
|
||||||
private var notification: Notification? = null
|
private var notification: Notification? = null
|
||||||
|
private const val NO_ID = "<i>Cannot detect action id</i>"
|
||||||
|
|
||||||
fun notifyActionId(id: String?, project: Project?, candidates: List<String>? = null) {
|
fun notifyActionId(id: String?, project: Project?) {
|
||||||
notification?.expire()
|
notification?.expire()
|
||||||
|
|
||||||
val possibleIDs = candidates?.distinct()?.sorted()
|
val content = if (id != null) "Action id: $id" else NO_ID
|
||||||
val content = when {
|
Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let {
|
||||||
id != null -> "Action ID: <code>$id</code><br><br>"
|
notification = it
|
||||||
possibleIDs.isNullOrEmpty() -> "<i>Cannot detect action ID</i><br><br>"
|
|
||||||
possibleIDs.size == 1 -> "Possible action ID: <code>${possibleIDs[0]}</code><br><br>"
|
|
||||||
else -> {
|
|
||||||
buildString {
|
|
||||||
append("<p>Multiple possible action IDs. Candidates include:<ul>")
|
|
||||||
possibleIDs.forEach { append("<li><code>$it</code></li>") }
|
|
||||||
append("</ul></p>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} + "<small>See the ${ActionCenter.getToolwindowName()} tool window for previous IDs</small>"
|
|
||||||
|
|
||||||
notification = Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).also {
|
|
||||||
it.whenExpired { notification = null }
|
it.whenExpired { notification = null }
|
||||||
|
it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>")
|
||||||
|
|
||||||
it.addAction(StopTracking())
|
it.addAction(StopTracking())
|
||||||
|
|
||||||
if (id != null || possibleIDs?.size == 1) {
|
if (id != null) it.addAction(CopyActionId(id, project))
|
||||||
it.addAction(CopyActionId(id ?: possibleIDs?.get(0), project))
|
|
||||||
}
|
|
||||||
|
|
||||||
it.notify(project)
|
it.notify(project)
|
||||||
}
|
}
|
||||||
|
@@ -95,6 +95,8 @@ class ProcessGroup : VimProcessGroupBase() {
|
|||||||
val progressIndicator = ProgressIndicatorProvider.getInstance().progressIndicator
|
val progressIndicator = ProgressIndicatorProvider.getInstance().progressIndicator
|
||||||
val output = handler.runProcessWithProgressIndicator(progressIndicator)
|
val output = handler.runProcessWithProgressIndicator(progressIndicator)
|
||||||
|
|
||||||
|
lastCommand = command
|
||||||
|
|
||||||
if (output.isCancelled) {
|
if (output.isCancelled) {
|
||||||
// TODO: Vim will use whatever text has already been written to stdout
|
// TODO: Vim will use whatever text has already been written to stdout
|
||||||
// For whatever reason, we're not getting any here, so just throw an exception
|
// For whatever reason, we're not getting any here, so just throw an exception
|
||||||
|
@@ -14,8 +14,6 @@ import com.intellij.openapi.components.State;
|
|||||||
import com.intellij.openapi.components.Storage;
|
import com.intellij.openapi.components.Storage;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.api.VimInjectorKt;
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
|
|
||||||
import com.maddyhome.idea.vim.register.Register;
|
import com.maddyhome.idea.vim.register.Register;
|
||||||
import com.maddyhome.idea.vim.register.VimRegisterGroupBase;
|
import com.maddyhome.idea.vim.register.VimRegisterGroupBase;
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType;
|
import com.maddyhome.idea.vim.state.mode.SelectionType;
|
||||||
@@ -37,10 +35,6 @@ import java.util.List;
|
|||||||
})
|
})
|
||||||
public class RegisterGroup extends VimRegisterGroupBase implements PersistentStateComponent<Element> {
|
public class RegisterGroup extends VimRegisterGroupBase implements PersistentStateComponent<Element> {
|
||||||
|
|
||||||
static {
|
|
||||||
IjVimInjectorKt.initInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getInstance(RegisterGroup.class);
|
private static final Logger logger = Logger.getInstance(RegisterGroup.class);
|
||||||
|
|
||||||
public RegisterGroup() {
|
public RegisterGroup() {
|
||||||
|
@@ -25,7 +25,6 @@ import com.maddyhome.idea.vim.mark.Jump
|
|||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import org.jdom.Element
|
import org.jdom.Element
|
||||||
|
|
||||||
@State(name = "VimJumpsSettings", storages = [Storage(value = "\$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)])
|
@State(name = "VimJumpsSettings", storages = [Storage(value = "\$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)])
|
||||||
@@ -66,7 +65,6 @@ internal class VimJumpServiceImpl : VimJumpServiceBase(), PersistentStateCompone
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun loadState(state: Element) {
|
override fun loadState(state: Element) {
|
||||||
initInjector()
|
|
||||||
val projectElements = state.getChildren("project")
|
val projectElements = state.getChildren("project")
|
||||||
for (projectElement in projectElements) {
|
for (projectElement in projectElements) {
|
||||||
val jumps = mutableListOf<Jump>()
|
val jumps = mutableListOf<Jump>()
|
||||||
@@ -91,7 +89,6 @@ internal class VimJumpServiceImpl : VimJumpServiceBase(), PersistentStateCompone
|
|||||||
|
|
||||||
internal class JumpsListener(val project: Project) : RecentPlacesListener {
|
internal class JumpsListener(val project: Project) : RecentPlacesListener {
|
||||||
override fun recentPlaceAdded(changePlace: PlaceInfo, isChanged: Boolean) {
|
override fun recentPlaceAdded(changePlace: PlaceInfo, isChanged: Boolean) {
|
||||||
initInjector()
|
|
||||||
if (!injector.globalIjOptions().unifyjumps) return
|
if (!injector.globalIjOptions().unifyjumps) return
|
||||||
|
|
||||||
val jumpService = injector.jumpService
|
val jumpService = injector.jumpService
|
||||||
|
@@ -46,7 +46,6 @@ import com.maddyhome.idea.vim.put.PutData
|
|||||||
import com.maddyhome.idea.vim.put.VimPasteProvider
|
import com.maddyhome.idea.vim.put.VimPasteProvider
|
||||||
import com.maddyhome.idea.vim.put.VimPutBase
|
import com.maddyhome.idea.vim.put.VimPutBase
|
||||||
import com.maddyhome.idea.vim.register.RegisterConstants
|
import com.maddyhome.idea.vim.register.RegisterConstants
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.state.mode.isBlock
|
import com.maddyhome.idea.vim.state.mode.isBlock
|
||||||
import com.maddyhome.idea.vim.state.mode.isChar
|
import com.maddyhome.idea.vim.state.mode.isChar
|
||||||
@@ -84,7 +83,7 @@ internal class PutGroup : VimPutBase() {
|
|||||||
val editor = (vimEditor as IjVimEditor).editor
|
val editor = (vimEditor as IjVimEditor).editor
|
||||||
val context = vimContext.context as DataContext
|
val context = vimContext.context as DataContext
|
||||||
val carets: MutableMap<Caret, RangeMarker> = mutableMapOf()
|
val carets: MutableMap<Caret, RangeMarker> = mutableMapOf()
|
||||||
if (injector.vimState.mode is Mode.INSERT) {
|
if (editor.isInsertMode) {
|
||||||
val undo = injector.undo
|
val undo = injector.undo
|
||||||
val nanoTime = System.nanoTime()
|
val nanoTime = System.nanoTime()
|
||||||
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
||||||
|
@@ -16,7 +16,6 @@ import com.intellij.openapi.keymap.ex.KeymapManagerEx
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.startup.ProjectActivity
|
import com.intellij.openapi.startup.ProjectActivity
|
||||||
import com.maddyhome.idea.vim.api.key
|
import com.maddyhome.idea.vim.api.key
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs the chain of handlers for esc and enter
|
* Logs the chain of handlers for esc and enter
|
||||||
@@ -35,8 +34,6 @@ internal class EditorHandlersChainLogger : ProjectActivity {
|
|||||||
private val editorHandlers = ExtensionPointName<EditorActionHandlerBean>("com.intellij.editorActionHandler")
|
private val editorHandlers = ExtensionPointName<EditorActionHandlerBean>("com.intellij.editorActionHandler")
|
||||||
|
|
||||||
override suspend fun execute(project: Project) {
|
override suspend fun execute(project: Project) {
|
||||||
initInjector()
|
|
||||||
|
|
||||||
if (!enableOctopus) return
|
if (!enableOctopus) return
|
||||||
|
|
||||||
val escHandlers = editorHandlers.extensionList
|
val escHandlers = editorHandlers.extensionList
|
||||||
|
@@ -19,7 +19,7 @@ import com.maddyhome.idea.vim.command.OperatorArguments
|
|||||||
*/
|
*/
|
||||||
internal abstract class IdeActionHandler(private val actionName: String) : VimActionHandler.SingleExecution() {
|
internal abstract class IdeActionHandler(private val actionName: String) : VimActionHandler.SingleExecution() {
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
injector.actionExecutor.executeAction(editor, name = actionName, context = context)
|
injector.actionExecutor.executeAction(actionName, context)
|
||||||
injector.scroll.scrollCaretIntoView(editor)
|
injector.scroll.scrollCaretIntoView(editor)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@@ -218,17 +218,13 @@ internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandle
|
|||||||
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
|
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
|
||||||
override val key: String = "<Esc>"
|
override val key: String = "<Esc>"
|
||||||
|
|
||||||
private val ideaVimSupportDialog
|
|
||||||
get() = injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
|
|
||||||
|
|
||||||
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
|
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
|
||||||
|
val ideaVimSupportDialog =
|
||||||
|
injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
|
||||||
|
|
||||||
return editor.isPrimaryEditor() ||
|
return editor.isPrimaryEditor() ||
|
||||||
EditorHelper.isFileEditor(editor) && vimStateNeedsToHandleEscape(editor) ||
|
EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode ||
|
||||||
ideaVimSupportDialog && vimStateNeedsToHandleEscape(editor)
|
ideaVimSupportDialog && !editor.vim.mode.inNormalMode
|
||||||
}
|
|
||||||
|
|
||||||
private fun vimStateNeedsToHandleEscape(editor: Editor): Boolean {
|
|
||||||
return !editor.vim.mode.inNormalMode || KeyHandler.getInstance().keyHandlerState.mappingState.hasKeys
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ import com.maddyhome.idea.vim.VimPlugin
|
|||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.common.EditorListener
|
|
||||||
import com.maddyhome.idea.vim.common.IsReplaceCharListener
|
import com.maddyhome.idea.vim.common.IsReplaceCharListener
|
||||||
import com.maddyhome.idea.vim.common.ModeChangeListener
|
import com.maddyhome.idea.vim.common.ModeChangeListener
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
@@ -74,7 +73,7 @@ internal object GuicursorChangeListener : EffectiveOptionValueChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Editor.guicursorMode(): GuiCursorMode {
|
private fun Editor.guicursorMode(): GuiCursorMode {
|
||||||
return GuiCursorMode.fromMode(vim.mode, injector.vimState.isReplaceCharacter)
|
return GuiCursorMode.fromMode(vim.mode, vim.vimStateMachine.isReplaceCharacter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,7 +86,6 @@ private fun isBlockCursorOverride() = EditorSettingsExternalizable.getInstance()
|
|||||||
|
|
||||||
private fun Editor.updatePrimaryCaretVisualAttributes() {
|
private fun Editor.updatePrimaryCaretVisualAttributes() {
|
||||||
if (VimPlugin.isNotEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
|
if (VimPlugin.isNotEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
|
||||||
if (isIdeaVimDisabledHere) return
|
|
||||||
caretModel.primaryCaret.visualAttributes = AttributesCache.getCaretVisualAttributes(this)
|
caretModel.primaryCaret.visualAttributes = AttributesCache.getCaretVisualAttributes(this)
|
||||||
|
|
||||||
// Make sure the caret is visible as soon as it's set. It might be invisible while blinking
|
// Make sure the caret is visible as soon as it's set. It might be invisible while blinking
|
||||||
@@ -101,7 +99,6 @@ private fun Editor.updatePrimaryCaretVisualAttributes() {
|
|||||||
|
|
||||||
private fun Editor.updateSecondaryCaretsVisualAttributes() {
|
private fun Editor.updateSecondaryCaretsVisualAttributes() {
|
||||||
if (VimPlugin.isNotEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
|
if (VimPlugin.isNotEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
|
||||||
if (isIdeaVimDisabledHere) return
|
|
||||||
// IntelliJ simulates visual block with multiple carets with selections. Do our best to hide them
|
// IntelliJ simulates visual block with multiple carets with selections. Do our best to hide them
|
||||||
val attributes = if (this.vim.inBlockSelection) HIDDEN else AttributesCache.getCaretVisualAttributes(this)
|
val attributes = if (this.vim.inBlockSelection) HIDDEN else AttributesCache.getCaretVisualAttributes(this)
|
||||||
this.caretModel.allCarets.forEach {
|
this.caretModel.allCarets.forEach {
|
||||||
@@ -147,7 +144,7 @@ private object AttributesCache {
|
|||||||
@TestOnly
|
@TestOnly
|
||||||
internal fun getGuiCursorMode(editor: Editor) = editor.guicursorMode()
|
internal fun getGuiCursorMode(editor: Editor) = editor.guicursorMode()
|
||||||
|
|
||||||
class CaretVisualAttributesListener : IsReplaceCharListener, ModeChangeListener, EditorListener {
|
class CaretVisualAttributesListener : IsReplaceCharListener, ModeChangeListener {
|
||||||
override fun isReplaceCharChanged(editor: VimEditor) {
|
override fun isReplaceCharChanged(editor: VimEditor) {
|
||||||
updateCaretsVisual(editor)
|
updateCaretsVisual(editor)
|
||||||
}
|
}
|
||||||
@@ -156,19 +153,21 @@ class CaretVisualAttributesListener : IsReplaceCharListener, ModeChangeListener,
|
|||||||
updateCaretsVisual(editor)
|
updateCaretsVisual(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun focusGained(editor: VimEditor) {
|
|
||||||
updateCaretsVisual(editor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateCaretsVisual(editor: VimEditor) {
|
private fun updateCaretsVisual(editor: VimEditor) {
|
||||||
val ijEditor = (editor as IjVimEditor).editor
|
if (injector.globalOptions().ideaglobalmode) {
|
||||||
ijEditor.updateCaretsVisualAttributes()
|
updateAllEditorsCaretsVisual()
|
||||||
ijEditor.updateCaretsVisualPosition()
|
} else {
|
||||||
|
val ijEditor = (editor as IjVimEditor).editor
|
||||||
|
ijEditor.updateCaretsVisualAttributes()
|
||||||
|
ijEditor.updateCaretsVisualPosition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateAllEditorsCaretsVisual() {
|
fun updateAllEditorsCaretsVisual() {
|
||||||
injector.editorGroup.getEditors().forEach { editor ->
|
injector.editorGroup.getEditors().forEach { editor ->
|
||||||
updateCaretsVisual(editor)
|
val ijEditor = (editor as IjVimEditor).editor
|
||||||
|
ijEditor.updateCaretsVisualAttributes()
|
||||||
|
ijEditor.updateCaretsVisualPosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -34,4 +34,4 @@ val Editor.inVisualMode: Boolean
|
|||||||
|
|
||||||
@get:JvmName("inExMode")
|
@get:JvmName("inExMode")
|
||||||
internal val Editor.inExMode
|
internal val Editor.inExMode
|
||||||
get() = this.vim.mode is Mode.CMD_LINE
|
get() = this.vim.vimStateMachine.mode is Mode.CMD_LINE
|
||||||
|
@@ -13,23 +13,23 @@ import com.intellij.openapi.actionSystem.ActionManager
|
|||||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||||
import com.intellij.openapi.actionSystem.AnAction
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionResult
|
||||||
import com.intellij.openapi.actionSystem.DataContextWrapper
|
import com.intellij.openapi.actionSystem.DataContextWrapper
|
||||||
import com.intellij.openapi.actionSystem.EmptyAction
|
import com.intellij.openapi.actionSystem.EmptyAction
|
||||||
import com.intellij.openapi.actionSystem.IdeActions
|
import com.intellij.openapi.actionSystem.IdeActions
|
||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||||
|
import com.intellij.openapi.actionSystem.ex.ActionManagerEx
|
||||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||||
import com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks
|
|
||||||
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
||||||
import com.intellij.openapi.actionSystem.impl.Utils
|
import com.intellij.openapi.actionSystem.impl.Utils
|
||||||
import com.intellij.openapi.application.ex.ApplicationManagerEx
|
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
|
import com.intellij.openapi.command.UndoConfirmationPolicy
|
||||||
import com.intellij.openapi.components.Service
|
import com.intellij.openapi.components.Service
|
||||||
import com.intellij.openapi.diagnostic.thisLogger
|
|
||||||
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
|
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
|
||||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
|
import com.intellij.openapi.project.IndexNotReadyException
|
||||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||||
import com.intellij.openapi.util.NlsContexts
|
import com.intellij.openapi.util.NlsContexts
|
||||||
|
import com.intellij.util.SlowOperations
|
||||||
import com.maddyhome.idea.vim.RegisterActions
|
import com.maddyhome.idea.vim.RegisterActions
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.NativeAction
|
import com.maddyhome.idea.vim.api.NativeAction
|
||||||
@@ -61,8 +61,6 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
get() = IdeActions.ACTION_EXPAND_REGION
|
get() = IdeActions.ACTION_EXPAND_REGION
|
||||||
override val ACTION_EXPAND_REGION_RECURSIVELY: String
|
override val ACTION_EXPAND_REGION_RECURSIVELY: String
|
||||||
get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
|
get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
|
||||||
override val ACTION_EXPAND_COLLAPSE_TOGGLE: String
|
|
||||||
get() = "ExpandCollapseToggleAction"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute an action
|
* Execute an action
|
||||||
@@ -71,12 +69,6 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
* @param context The context to run it in
|
* @param context The context to run it in
|
||||||
*/
|
*/
|
||||||
override fun executeAction(editor: VimEditor?, action: NativeAction, context: ExecutionContext): Boolean {
|
override fun executeAction(editor: VimEditor?, action: NativeAction, context: ExecutionContext): Boolean {
|
||||||
val applicationEx = ApplicationManagerEx.getApplicationEx()
|
|
||||||
if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
|
|
||||||
// This is needed for VIM-3376 and it should turn into error at soeme moment
|
|
||||||
thisLogger().warn(RuntimeException("Actions cannot be updated when write-action is running or pending", ))
|
|
||||||
}
|
|
||||||
|
|
||||||
val ijAction = (action as IjNativeAction).action
|
val ijAction = (action as IjNativeAction).action
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,15 +121,51 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is taken directly from ActionUtil.performActionDumbAwareWithCallbacks
|
||||||
|
// But with one check removed. With this check some actions (like `:w` doesn't work)
|
||||||
|
// https://youtrack.jetbrains.com/issue/VIM-2691/File-is-not-saved-on-w
|
||||||
|
private fun performDumbAwareWithCallbacks(
|
||||||
|
action: AnAction,
|
||||||
|
event: AnActionEvent,
|
||||||
|
performRunnable: Runnable,
|
||||||
|
) {
|
||||||
|
val project = event.project
|
||||||
|
var indexError: IndexNotReadyException? = null
|
||||||
|
val manager = ActionManagerEx.getInstanceEx()
|
||||||
|
manager.fireBeforeActionPerformed(action, event)
|
||||||
|
var result: AnActionResult? = null
|
||||||
|
try {
|
||||||
|
SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use {
|
||||||
|
performRunnable.run()
|
||||||
|
result = AnActionResult.PERFORMED
|
||||||
|
}
|
||||||
|
} catch (ex: IndexNotReadyException) {
|
||||||
|
indexError = ex
|
||||||
|
result = AnActionResult.failed(ex)
|
||||||
|
} catch (ex: RuntimeException) {
|
||||||
|
result = AnActionResult.failed(ex)
|
||||||
|
throw ex
|
||||||
|
} catch (ex: Error) {
|
||||||
|
result = AnActionResult.failed(ex)
|
||||||
|
throw ex
|
||||||
|
} finally {
|
||||||
|
if (result == null) result = AnActionResult.failed(Throwable())
|
||||||
|
manager.fireAfterActionPerformed(action, event, result!!)
|
||||||
|
}
|
||||||
|
if (indexError != null) {
|
||||||
|
ActionUtil.showDumbModeWarning(project, action, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute an action by name
|
* Execute an action by name
|
||||||
*
|
*
|
||||||
* @param name The name of the action to execute
|
* @param name The name of the action to execute
|
||||||
* @param context The context to run it in
|
* @param context The context to run it in
|
||||||
*/
|
*/
|
||||||
override fun executeAction(editor: VimEditor, name: @NonNls String, context: ExecutionContext): Boolean {
|
override fun executeAction(name: @NonNls String, context: ExecutionContext): Boolean {
|
||||||
val action = getAction(name, context)
|
val action = getAction(name, context)
|
||||||
return action != null && executeAction(editor, IjNativeAction(action), context)
|
return action != null && executeAction(null, IjNativeAction(action), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAction(name: String, context: ExecutionContext): AnAction? {
|
private fun getAction(name: String, context: ExecutionContext): AnAction? {
|
||||||
@@ -183,8 +211,8 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
CommandProcessor.getInstance().executeCommand(editor?.ij?.project, runnable, name, groupId)
|
CommandProcessor.getInstance().executeCommand(editor?.ij?.project, runnable, name, groupId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeEsc(editor: VimEditor, context: ExecutionContext): Boolean {
|
override fun executeEsc(context: ExecutionContext): Boolean {
|
||||||
return executeAction(editor, IdeActions.ACTION_EDITOR_ESCAPE, context)
|
return executeAction(IdeActions.ACTION_EDITOR_ESCAPE, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeVimAction(
|
override fun executeVimAction(
|
||||||
|
@@ -14,7 +14,6 @@ import com.intellij.openapi.editor.VisualPosition
|
|||||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager
|
import com.intellij.openapi.editor.actionSystem.EditorActionManager
|
||||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||||
import com.maddyhome.idea.vim.api.EngineEditorHelper
|
import com.maddyhome.idea.vim.api.EngineEditorHelper
|
||||||
import com.maddyhome.idea.vim.api.EngineEditorHelperBase
|
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.VimRangeMarker
|
import com.maddyhome.idea.vim.api.VimRangeMarker
|
||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||||
@@ -23,7 +22,7 @@ import com.maddyhome.idea.vim.newapi.ij
|
|||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
internal class IjEditorHelper : EngineEditorHelperBase() {
|
internal class IjEditorHelper : EngineEditorHelper {
|
||||||
override fun amountOfInlaysBeforeVisualPosition(editor: VimEditor, pos: VimVisualPosition): Int {
|
override fun amountOfInlaysBeforeVisualPosition(editor: VimEditor, pos: VimVisualPosition): Int {
|
||||||
return (editor as IjVimEditor).editor.amountOfInlaysBeforeVisualPosition(
|
return (editor as IjVimEditor).editor.amountOfInlaysBeforeVisualPosition(
|
||||||
VisualPosition(
|
VisualPosition(
|
||||||
@@ -52,6 +51,10 @@ internal class IjEditorHelper : EngineEditorHelperBase() {
|
|||||||
return EditorHelper.getVisualLineAtBottomOfScreen(editor.ij)
|
return EditorHelper.getVisualLineAtBottomOfScreen(editor.ij)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pad(editor: VimEditor, line: Int, to: Int): String {
|
||||||
|
return EditorHelper.pad(editor.ij, line, to)
|
||||||
|
}
|
||||||
|
|
||||||
override fun inlayAwareOffsetToVisualPosition(editor: VimEditor, offset: Int): VimVisualPosition {
|
override fun inlayAwareOffsetToVisualPosition(editor: VimEditor, offset: Int): VimVisualPosition {
|
||||||
return EditorUtil.inlayAwareOffsetToVisualPosition(editor.ij, offset).vim
|
return EditorUtil.inlayAwareOffsetToVisualPosition(editor.ij, offset).vim
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ import com.maddyhome.idea.vim.state.mode.returnTo
|
|||||||
internal fun Editor.exitSelectMode(adjustCaretPosition: Boolean) {
|
internal fun Editor.exitSelectMode(adjustCaretPosition: Boolean) {
|
||||||
if (!this.vim.inSelectMode) return
|
if (!this.vim.inSelectMode) return
|
||||||
|
|
||||||
val returnTo = this.vim.mode.returnTo
|
val returnTo = this.vim.vimStateMachine.mode.returnTo
|
||||||
when (returnTo) {
|
when (returnTo) {
|
||||||
ReturnTo.INSERT -> {
|
ReturnTo.INSERT -> {
|
||||||
this.vim.mode = Mode.INSERT
|
this.vim.mode = Mode.INSERT
|
||||||
@@ -64,7 +64,7 @@ internal fun Editor.exitSelectMode(adjustCaretPosition: Boolean) {
|
|||||||
internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
|
internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
|
||||||
if (!this.inSelectMode) return
|
if (!this.inSelectMode) return
|
||||||
|
|
||||||
val returnTo = this.mode.returnTo
|
val returnTo = this.vimStateMachine.mode.returnTo
|
||||||
when (returnTo) {
|
when (returnTo) {
|
||||||
ReturnTo.INSERT -> {
|
ReturnTo.INSERT -> {
|
||||||
this.mode = Mode.INSERT
|
this.mode = Mode.INSERT
|
||||||
|
@@ -180,7 +180,7 @@ internal object ScrollViewHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getScrollJump(editor: VimEditor, height: Int): Int {
|
private fun getScrollJump(editor: VimEditor, height: Int): Int {
|
||||||
val flags = injector.vimState.executingCommandFlags
|
val flags = VimStateMachine.getInstance(editor).executingCommandFlags
|
||||||
val scrollJump = !flags.contains(CommandFlags.FLAG_IGNORE_SCROLL_JUMP)
|
val scrollJump = !flags.contains(CommandFlags.FLAG_IGNORE_SCROLL_JUMP)
|
||||||
|
|
||||||
// Default value is 1. Zero is a valid value, but we normalise to 1 - we always want to scroll at least one line
|
// Default value is 1. Zero is a valid value, but we normalise to 1 - we always want to scroll at least one line
|
||||||
@@ -203,7 +203,7 @@ internal object ScrollViewHelper {
|
|||||||
val caretColumn = position.column
|
val caretColumn = position.column
|
||||||
val halfWidth = getApproximateScreenWidth(editor) / 2
|
val halfWidth = getApproximateScreenWidth(editor) / 2
|
||||||
val scrollOffset = getNormalizedSideScrollOffset(editor)
|
val scrollOffset = getNormalizedSideScrollOffset(editor)
|
||||||
val flags = injector.vimState.executingCommandFlags
|
val flags = VimStateMachine.getInstance(vimEditor).executingCommandFlags
|
||||||
val allowSidescroll = !flags.contains(CommandFlags.FLAG_IGNORE_SIDE_SCROLL_JUMP)
|
val allowSidescroll = !flags.contains(CommandFlags.FLAG_IGNORE_SIDE_SCROLL_JUMP)
|
||||||
val sidescroll = injector.options(vimEditor).sidescroll
|
val sidescroll = injector.options(vimEditor).sidescroll
|
||||||
val offsetLeft = caretColumn - (currentVisualLeftColumn + scrollOffset)
|
val offsetLeft = caretColumn - (currentVisualLeftColumn + scrollOffset)
|
||||||
|
@@ -16,15 +16,18 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.spellchecker.SpellCheckerSeveritiesProvider
|
import com.intellij.spellchecker.SpellCheckerSeveritiesProvider
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.getLineEndOffset
|
import com.maddyhome.idea.vim.api.getLineEndOffset
|
||||||
|
import com.maddyhome.idea.vim.api.getText
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import it.unimi.dsi.fastutil.ints.IntComparator
|
import it.unimi.dsi.fastutil.ints.IntComparator
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterator
|
import it.unimi.dsi.fastutil.ints.IntIterator
|
||||||
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntSortedSet
|
import it.unimi.dsi.fastutil.ints.IntSortedSet
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check ignorecase and smartcase options to see if a case insensitive search should be performed with the given pattern.
|
* Check ignorecase and smartcase options to see if a case insensitive search should be performed with the given pattern.
|
||||||
@@ -94,6 +97,210 @@ fun countWords(
|
|||||||
return CountPosition(count, position)
|
return CountPosition(count, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun findNumbersInRange(
|
||||||
|
editor: Editor,
|
||||||
|
textRange: TextRange,
|
||||||
|
alpha: Boolean,
|
||||||
|
hex: Boolean,
|
||||||
|
octal: Boolean,
|
||||||
|
): List<Pair<TextRange, NumberType>> {
|
||||||
|
val result: MutableList<Pair<TextRange, NumberType>> = ArrayList()
|
||||||
|
|
||||||
|
|
||||||
|
for (i in 0 until textRange.size()) {
|
||||||
|
val startOffset = textRange.startOffsets[i]
|
||||||
|
val end = textRange.endOffsets[i]
|
||||||
|
val text: String = editor.vim.getText(startOffset, end)
|
||||||
|
val textChunks = text.split("\\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
var chunkStart = 0
|
||||||
|
for (chunk in textChunks) {
|
||||||
|
val number = findNumberInText(chunk, 0, alpha, hex, octal)
|
||||||
|
|
||||||
|
if (number != null) {
|
||||||
|
result.add(
|
||||||
|
Pair(
|
||||||
|
TextRange(
|
||||||
|
number.first.startOffset + startOffset + chunkStart,
|
||||||
|
number.first.endOffset + startOffset + chunkStart
|
||||||
|
),
|
||||||
|
number.second
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
chunkStart += 1 + chunk.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findNumberUnderCursor(
|
||||||
|
editor: Editor,
|
||||||
|
caret: Caret,
|
||||||
|
alpha: Boolean,
|
||||||
|
hex: Boolean,
|
||||||
|
octal: Boolean,
|
||||||
|
): Pair<TextRange, NumberType>? {
|
||||||
|
val lline = caret.logicalPosition.line
|
||||||
|
val text = IjVimEditor(editor).getLineText(lline).lowercase(Locale.getDefault())
|
||||||
|
val startLineOffset = IjVimEditor(editor).getLineStartOffset(lline)
|
||||||
|
val posOnLine = caret.offset - startLineOffset
|
||||||
|
|
||||||
|
val numberTextRange = findNumberInText(text, posOnLine, alpha, hex, octal) ?: return null
|
||||||
|
|
||||||
|
return Pair(
|
||||||
|
TextRange(
|
||||||
|
numberTextRange.first.startOffset + startLineOffset,
|
||||||
|
numberTextRange.first.endOffset + startLineOffset
|
||||||
|
),
|
||||||
|
numberTextRange.second
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for number in given text from start position
|
||||||
|
*
|
||||||
|
* @param textInRange - text to search in
|
||||||
|
* @param startPosOnLine - start offset to search
|
||||||
|
* @return - text range with number
|
||||||
|
*/
|
||||||
|
fun findNumberInText(
|
||||||
|
textInRange: String,
|
||||||
|
startPosOnLine: Int,
|
||||||
|
alpha: Boolean,
|
||||||
|
hex: Boolean,
|
||||||
|
octal: Boolean,
|
||||||
|
): Pair<TextRange, NumberType>? {
|
||||||
|
if (logger.isDebugEnabled) {
|
||||||
|
logger.debug("text=$textInRange")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = startPosOnLine
|
||||||
|
val lineEndOffset = textInRange.length
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Skip over current whitespace if any
|
||||||
|
while (pos < lineEndOffset && !isNumberChar(textInRange[pos], alpha, hex, octal, true)) {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled) logger.debug("pos=$pos")
|
||||||
|
if (pos >= lineEndOffset) {
|
||||||
|
logger.debug("no number char on line")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val isHexChar = "abcdefABCDEF".indexOf(textInRange[pos]) >= 0
|
||||||
|
|
||||||
|
if (hex) {
|
||||||
|
// Ox and OX handling
|
||||||
|
if (textInRange[pos] == '0' && pos < lineEndOffset - 1 && "xX".indexOf(textInRange[pos + 1]) >= 0) {
|
||||||
|
pos += 2
|
||||||
|
} else if ("xX".indexOf(textInRange[pos]) >= 0 && pos > 0 && textInRange[pos - 1] == '0') {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("checking hex")
|
||||||
|
val range = findRange(textInRange, pos, false, true, false, false)
|
||||||
|
val start = range.first
|
||||||
|
val end = range.second
|
||||||
|
|
||||||
|
// Ox and OX
|
||||||
|
if (start >= 2 && textInRange.substring(start - 2, start).equals("0x", ignoreCase = true)) {
|
||||||
|
logger.debug("found hex")
|
||||||
|
return Pair(TextRange(start - 2, end), NumberType.HEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHexChar || alpha) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (octal) {
|
||||||
|
logger.debug("checking octal")
|
||||||
|
val range = findRange(textInRange, pos, false, false, true, false)
|
||||||
|
val start = range.first
|
||||||
|
val end = range.second
|
||||||
|
|
||||||
|
if (end - start == 1 && textInRange[start] == '0') {
|
||||||
|
return Pair(TextRange(start, end), NumberType.DEC)
|
||||||
|
}
|
||||||
|
if (textInRange[start] == '0' && end > start &&
|
||||||
|
!(start > 0 && isNumberChar(textInRange[start - 1], false, false, false, true))
|
||||||
|
) {
|
||||||
|
logger.debug("found octal")
|
||||||
|
return Pair(TextRange(start, end), NumberType.OCT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alpha) {
|
||||||
|
if (logger.isDebugEnabled) logger.debug("checking alpha for " + textInRange[pos])
|
||||||
|
if (isNumberChar(textInRange[pos], true, false, false, false)) {
|
||||||
|
if (logger.isDebugEnabled) logger.debug("found alpha at $pos")
|
||||||
|
return Pair(TextRange(pos, pos + 1), NumberType.ALPHA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val range = findRange(textInRange, pos, false, false, false, true)
|
||||||
|
var start = range.first
|
||||||
|
val end = range.second
|
||||||
|
if (start > 0 && textInRange[start - 1] == '-') {
|
||||||
|
start--
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair(TextRange(start, end), NumberType.DEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for digits block that matches parameters
|
||||||
|
*/
|
||||||
|
private fun findRange(
|
||||||
|
text: String,
|
||||||
|
pos: Int,
|
||||||
|
alpha: Boolean,
|
||||||
|
hex: Boolean,
|
||||||
|
octal: Boolean,
|
||||||
|
decimal: Boolean,
|
||||||
|
): Pair<Int, Int> {
|
||||||
|
var end = pos
|
||||||
|
while (end < text.length && isNumberChar(text[end], alpha, hex, octal, decimal || octal)) {
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
var start = pos
|
||||||
|
while (start >= 0 && isNumberChar(text[start], alpha, hex, octal, decimal || octal)) {
|
||||||
|
start--
|
||||||
|
}
|
||||||
|
if (start < end &&
|
||||||
|
(start == -1 ||
|
||||||
|
0 <= start && start < text.length &&
|
||||||
|
!isNumberChar(text[start], alpha, hex, octal, decimal || octal))
|
||||||
|
) {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
if (octal) {
|
||||||
|
for (i in start until end) {
|
||||||
|
if (!isNumberChar(text[i], false, false, true, false)) return Pair(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pair(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isNumberChar(ch: Char, alpha: Boolean, hex: Boolean, octal: Boolean, decimal: Boolean): Boolean {
|
||||||
|
return if (alpha && ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) {
|
||||||
|
true
|
||||||
|
} else if (octal && (ch >= '0' && ch <= '7')) {
|
||||||
|
true
|
||||||
|
} else if (hex && ((ch >= '0' && ch <= '9') || "abcdefABCDEF".indexOf(ch) >= 0)) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
decimal && (ch >= '0' && ch <= '9')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the word under the cursor or the next word to the right of the cursor on the current line.
|
* Find the word under the cursor or the next word to the right of the cursor on the current line.
|
||||||
*
|
*
|
||||||
|
@@ -16,7 +16,6 @@ import com.intellij.openapi.components.Service
|
|||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.fileEditor.TextEditor
|
import com.intellij.openapi.fileEditor.TextEditor
|
||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.registry.Registry
|
import com.intellij.openapi.util.registry.Registry
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
@@ -24,8 +23,8 @@ import com.maddyhome.idea.vim.api.VimCaret
|
|||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.common.ChangesListener
|
import com.maddyhome.idea.vim.common.ChangesListener
|
||||||
import com.maddyhome.idea.vim.common.InsertSequence
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
|
import com.maddyhome.idea.vim.common.InsertSequence
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
@@ -71,7 +70,6 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
restoreVisualMode(editor)
|
restoreVisualMode(editor)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notifyAboutNewUndo(editor.ij.project)
|
|
||||||
runWithBooleanRegistryOption("ide.undo.transparent.caret.movement", true) {
|
runWithBooleanRegistryOption("ide.undo.transparent.caret.movement", true) {
|
||||||
var nextUndoNanoTime = undoManager.getNextUndoNanoTime(fileEditor)
|
var nextUndoNanoTime = undoManager.getNextUndoNanoTime(fileEditor)
|
||||||
val insertInfo = (editor.primaryCaret() as IjVimCaret).getInsertSequenceForTime(nextUndoNanoTime)
|
val insertInfo = (editor.primaryCaret() as IjVimCaret).getInsertSequenceForTime(nextUndoNanoTime)
|
||||||
@@ -92,13 +90,6 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyAboutNewUndo(project: Project?) {
|
|
||||||
if (VimPlugin.getVimState().isNewUndoNotified) return
|
|
||||||
VimPlugin.getVimState().isNewUndoNotified = true
|
|
||||||
|
|
||||||
VimPlugin.getNotifications(project).notifyAboutNewUndo()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasSelection(editor: VimEditor): Boolean {
|
private fun hasSelection(editor: VimEditor): Boolean {
|
||||||
return editor.primaryCaret().ij.hasSelection()
|
return editor.primaryCaret().ij.hasSelection()
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.ex.ExOutputModel
|
|||||||
import com.maddyhome.idea.vim.group.visual.VisualChange
|
import com.maddyhome.idea.vim.group.visual.VisualChange
|
||||||
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
|
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
||||||
@@ -102,6 +103,7 @@ internal var Editor.vimInitialised: Boolean by userDataOr { false }
|
|||||||
// ------------------ Editor
|
// ------------------ Editor
|
||||||
internal fun unInitializeEditor(editor: Editor) {
|
internal fun unInitializeEditor(editor: Editor) {
|
||||||
editor.vimLastSelectionType = null
|
editor.vimLastSelectionType = null
|
||||||
|
editor.vimStateMachine = null
|
||||||
editor.vimMorePanel = null
|
editor.vimMorePanel = null
|
||||||
editor.vimExOutput = null
|
editor.vimExOutput = null
|
||||||
editor.vimLastHighlighters = null
|
editor.vimLastHighlighters = null
|
||||||
@@ -116,6 +118,7 @@ internal var Editor.vimIncsearchCurrentMatchOffset: Int? by userData()
|
|||||||
* @see :help visualmode()
|
* @see :help visualmode()
|
||||||
*/
|
*/
|
||||||
internal var Editor.vimLastSelectionType: SelectionType? by userData()
|
internal var Editor.vimLastSelectionType: SelectionType? by userData()
|
||||||
|
internal var Editor.vimStateMachine: VimStateMachine? by userData()
|
||||||
internal var Editor.vimEditorGroup: Boolean by userDataOr { false }
|
internal var Editor.vimEditorGroup: Boolean by userDataOr { false }
|
||||||
internal var Editor.vimHasRelativeLineNumbersInstalled: Boolean by userDataOr { false }
|
internal var Editor.vimHasRelativeLineNumbersInstalled: Boolean by userDataOr { false }
|
||||||
internal var Editor.vimMorePanel: ExOutputPanel? by userData()
|
internal var Editor.vimMorePanel: ExOutputPanel? by userData()
|
||||||
|
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2024 The IdeaVim authors
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE.txt file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.maddyhome.idea.vim.listener
|
|
||||||
|
|
||||||
import com.intellij.execution.impl.ConsoleViewImpl
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
|
||||||
import com.maddyhome.idea.vim.common.EditorListener
|
|
||||||
import com.maddyhome.idea.vim.helper.inInsertMode
|
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This listener is similar to the one we introduce in vim-engine to handle focus change,
|
|
||||||
* However, in IJ we would like to start editing in some editors in INSERT mode (e.g., consoles)
|
|
||||||
* It is different to we had previously. Now we go to INSERT mode not only when we focus on the console the first time, but every time.
|
|
||||||
* Going to INSERT on every focus is easier to implement and more consistent (behavior is always the same, you don't have to remember if you are focusing a console the first time or not)
|
|
||||||
*/
|
|
||||||
class IJEditorFocusListener : EditorListener {
|
|
||||||
override fun focusGained(editor: VimEditor) {
|
|
||||||
val editorInFocus = KeyHandler.getInstance().editorInFocus
|
|
||||||
if (editorInFocus != null && editorInFocus.ij == editor.ij) return
|
|
||||||
|
|
||||||
KeyHandler.getInstance().editorInFocus = editor
|
|
||||||
|
|
||||||
// We add Vim bindings to all opened editors, including editors used as UI controls rather than just project file
|
|
||||||
// editors. This includes editors used as part of the UI, such as the VCS commit message, or used as read-only
|
|
||||||
// viewers for text output, such as log files in run configurations or the Git Console tab. And editors are used for
|
|
||||||
// interactive stdin/stdout for console-based run configurations.
|
|
||||||
// We want to provide an intuitive experience for working with these additional editors, so we automatically switch
|
|
||||||
// to INSERT mode if they are interactive editors. Recognising these can be a bit tricky.
|
|
||||||
// These additional interactive editors are not file-based, but must have a writable document. However, log output
|
|
||||||
// documents are also writable (the IDE is writing new content as it becomes available) just not user-editable. So
|
|
||||||
// we must also check that the editor is not in read-only "viewer" mode (this includes "rendered" mode, which is
|
|
||||||
// read-only and also hides the caret).
|
|
||||||
// Furthermore, interactive stdin/stdout console output in run configurations is hosted in a read-only editor, but
|
|
||||||
// it can still be edited. The `ConsoleViewImpl` class installs a typing handler that ignores the editor's
|
|
||||||
// `isViewer` property and allows typing if the associated process (if any) is still running. We can get the
|
|
||||||
// editor's console view and check this ourselves, but we have to wait until the editor has finished initialising
|
|
||||||
// before it's available in user data.
|
|
||||||
// Finally, we have a special check for diff windows. If we compare against clipboard, we get a diff editor that is
|
|
||||||
// not file based, is writable, and not a viewer, but we don't want to treat this as an interactive editor.
|
|
||||||
// Note that we need a similar check in `VimEditor.isWritable` to allow Escape to work to exit insert mode. We need
|
|
||||||
// to know that a read-only editor that is hosting a console view with a running process can be treated as writable.
|
|
||||||
|
|
||||||
val ijEditor = editor.ij
|
|
||||||
|
|
||||||
|
|
||||||
val switchToInsertMode = Runnable {
|
|
||||||
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
|
||||||
VimPlugin.getChange().insertBeforeCursor(editor, context)
|
|
||||||
}
|
|
||||||
if (!ijEditor.document.isWritable) {
|
|
||||||
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
|
||||||
val mode = injector.vimState.mode
|
|
||||||
when (mode) {
|
|
||||||
is Mode.INSERT -> editor.exitInsertMode(context, OperatorArguments(false, 0, mode))
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationManager.getApplication().invokeLater {
|
|
||||||
if (ijEditor.isDisposed) return@invokeLater
|
|
||||||
val consoleView: ConsoleViewImpl? = ijEditor.getUserData(ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW)
|
|
||||||
if (consoleView != null && consoleView.isRunning && !ijEditor.inInsertMode) {
|
|
||||||
switchToInsertMode.run()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyHandler.getInstance().reset(editor)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -29,7 +29,6 @@ import com.intellij.openapi.actionSystem.ex.AnActionListener
|
|||||||
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.impl.ScrollingModelImpl
|
import com.intellij.openapi.editor.impl.ScrollingModelImpl
|
||||||
import com.intellij.openapi.keymap.KeymapManager
|
|
||||||
import com.intellij.openapi.project.DumbAwareToggleAction
|
import com.intellij.openapi.project.DumbAwareToggleAction
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
@@ -38,8 +37,8 @@ import com.maddyhome.idea.vim.action.VimShortcutKeyAction
|
|||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.group.NotificationService
|
import com.maddyhome.idea.vim.group.NotificationService
|
||||||
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
|
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
|
||||||
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.inNormalMode
|
import com.maddyhome.idea.vim.state.mode.inNormalMode
|
||||||
@@ -62,7 +61,6 @@ internal object IdeaSpecifics {
|
|||||||
private var caretOffset = -1
|
private var caretOffset = -1
|
||||||
private var completionPrevDocumentLength: Int? = null
|
private var completionPrevDocumentLength: Int? = null
|
||||||
private var completionPrevDocumentOffset: Int? = null
|
private var completionPrevDocumentOffset: Int? = null
|
||||||
|
|
||||||
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
|
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
|
||||||
if (VimPlugin.isNotEnabled()) return
|
if (VimPlugin.isNotEnabled()) return
|
||||||
|
|
||||||
@@ -76,24 +74,7 @@ internal object IdeaSpecifics {
|
|||||||
if (!isVimAction && injector.globalIjOptions().trackactionids) {
|
if (!isVimAction && injector.globalIjOptions().trackactionids) {
|
||||||
if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) {
|
if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) {
|
||||||
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
|
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
|
||||||
val candidates = if (id == null) {
|
VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
|
||||||
// Some actions are specific to the component they're registered for, and are copies of a global action,
|
|
||||||
// reusing the action ID and shortcuts (e.g. `NextTab` is different for editor tabs and tool window tabs).
|
|
||||||
// Unfortunately, ActionManager doesn't know about these "local" actions, so can't return the action ID.
|
|
||||||
// However, the new "local" action does copy the shortcuts of the global template action, so we can look up
|
|
||||||
// all actions with matching shortcuts. We might return more action IDs than expected, so this is a list of
|
|
||||||
// candidates, not a definite match of the action being executed, but the list should include our target
|
|
||||||
// action. Note that we might return duplicate IDs because the keymap might have multiple shortcuts mapped
|
|
||||||
// to the same action. The notifier will handle de-duplication and sorting as a presentation detail.
|
|
||||||
action.shortcutSet.shortcuts.flatMap { KeymapManager.getInstance().activeKeymap.getActionIdList(it) }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can still get empty ID and empty candidates. Notably, for the tool window toggle buttons on the new UI.
|
|
||||||
// We could filter out action events with `place == ActionPlaces.TOOLWINDOW_TOOLBAR_BAR`
|
|
||||||
VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id, candidates)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +128,7 @@ internal object IdeaSpecifics {
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
editor?.let {
|
editor?.let {
|
||||||
|
val commandState = it.vim.vimStateMachine
|
||||||
it.vim.mode = Mode.NORMAL()
|
it.vim.mode = Mode.NORMAL()
|
||||||
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
|
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
|
||||||
KeyHandler.getInstance().reset(it.vim)
|
KeyHandler.getInstance().reset(it.vim)
|
||||||
@@ -245,13 +227,9 @@ internal object IdeaSpecifics {
|
|||||||
|
|
||||||
//region Find action ID
|
//region Find action ID
|
||||||
internal class FindActionIdAction : DumbAwareToggleAction() {
|
internal class FindActionIdAction : DumbAwareToggleAction() {
|
||||||
override fun isSelected(e: AnActionEvent): Boolean {
|
override fun isSelected(e: AnActionEvent): Boolean = injector.globalIjOptions().trackactionids
|
||||||
initInjector()
|
|
||||||
return injector.globalIjOptions().trackactionids
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
||||||
initInjector()
|
|
||||||
injector.globalIjOptions().trackactionids = !injector.globalIjOptions().trackactionids
|
injector.globalIjOptions().trackactionids = !injector.globalIjOptions().trackactionids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2024 The IdeaVim authors
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
||||||
@@ -9,18 +9,7 @@
|
|||||||
package com.maddyhome.idea.vim.listener
|
package com.maddyhome.idea.vim.listener
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
|
||||||
import com.maddyhome.idea.vim.common.ModeChangeListener
|
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
|
|
||||||
@Deprecated(message = "Please use ModeChangeListener", replaceWith = ReplaceWith("ModeChangeListener", imports = ["import com.maddyhome.idea.vim.common.ModeChangeListener"]))
|
|
||||||
interface VimInsertListener : ModeChangeListener {
|
|
||||||
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
|
||||||
if (editor.mode == Mode.INSERT) {
|
|
||||||
insertModeStarted(editor.ij)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
interface VimInsertListener {
|
||||||
fun insertModeStarted(editor: Editor)
|
fun insertModeStarted(editor: Editor)
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,7 @@ import com.intellij.util.ExceptionUtil
|
|||||||
import com.jetbrains.rd.util.lifetime.Lifetime
|
import com.jetbrains.rd.util.lifetime.Lifetime
|
||||||
import com.maddyhome.idea.vim.EventFacade
|
import com.maddyhome.idea.vim.EventFacade
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
|
import com.maddyhome.idea.vim.KeyHandlerStateResetter
|
||||||
import com.maddyhome.idea.vim.VimKeyListener
|
import com.maddyhome.idea.vim.VimKeyListener
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.VimTypedActionHandler
|
import com.maddyhome.idea.vim.VimTypedActionHandler
|
||||||
@@ -94,8 +95,8 @@ import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
|
|||||||
import com.maddyhome.idea.vim.helper.vimDisabled
|
import com.maddyhome.idea.vim.helper.vimDisabled
|
||||||
import com.maddyhome.idea.vim.helper.vimInitialised
|
import com.maddyhome.idea.vim.helper.vimInitialised
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
|
|
||||||
import com.maddyhome.idea.vim.newapi.InsertTimeRecorder
|
import com.maddyhome.idea.vim.newapi.InsertTimeRecorder
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
@@ -161,7 +162,6 @@ internal object VimListenerManager {
|
|||||||
check(keyCheckRequests.tryEmit(Unit))
|
check(keyCheckRequests.tryEmit(Unit))
|
||||||
|
|
||||||
val caretVisualAttributesListener = CaretVisualAttributesListener()
|
val caretVisualAttributesListener = CaretVisualAttributesListener()
|
||||||
injector.listenersNotifier.myEditorListeners.add(caretVisualAttributesListener)
|
|
||||||
injector.listenersNotifier.modeChangeListeners.add(caretVisualAttributesListener)
|
injector.listenersNotifier.modeChangeListeners.add(caretVisualAttributesListener)
|
||||||
injector.listenersNotifier.isReplaceCharListeners.add(caretVisualAttributesListener)
|
injector.listenersNotifier.isReplaceCharListeners.add(caretVisualAttributesListener)
|
||||||
caretVisualAttributesListener.updateAllEditorsCaretsVisual()
|
caretVisualAttributesListener.updateAllEditorsCaretsVisual()
|
||||||
@@ -178,7 +178,7 @@ internal object VimListenerManager {
|
|||||||
injector.listenersNotifier.macroRecordingListeners.add(macroWidgetListener)
|
injector.listenersNotifier.macroRecordingListeners.add(macroWidgetListener)
|
||||||
injector.listenersNotifier.vimPluginListeners.add(macroWidgetListener)
|
injector.listenersNotifier.vimPluginListeners.add(macroWidgetListener)
|
||||||
|
|
||||||
injector.listenersNotifier.myEditorListeners.add(IJEditorFocusListener())
|
injector.listenersNotifier.myEditorListeners.add(KeyHandlerStateResetter())
|
||||||
injector.listenersNotifier.myEditorListeners.add(ShowCmdWidgetUpdater())
|
injector.listenersNotifier.myEditorListeners.add(ShowCmdWidgetUpdater())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +395,6 @@ internal object VimListenerManager {
|
|||||||
editor.vim.mode = Mode.NORMAL()
|
editor.vim.mode = Mode.NORMAL()
|
||||||
KeyHandler.getInstance().reset(editor.vim)
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
}
|
}
|
||||||
injector.scroll.scrollCaretIntoView(editor.vim)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
@@ -745,10 +744,12 @@ internal object VimListenerManager {
|
|||||||
|
|
||||||
if (event.area == EditorMouseEventArea.EDITING_AREA) {
|
if (event.area == EditorMouseEventArea.EDITING_AREA) {
|
||||||
val editor = event.editor
|
val editor = event.editor
|
||||||
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
val commandLine = injector.commandLine.getActiveCommandLine()
|
||||||
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
if (commandLine != null) {
|
||||||
|
injector.processGroup.cancelExEntry(editor.vim, false)
|
||||||
|
}
|
||||||
|
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
ExOutputModel.tryGetInstance(editor)?.close()
|
||||||
|
|
||||||
val caretModel = editor.caretModel
|
val caretModel = editor.caretModel
|
||||||
if (editor.vim.mode.selectionType != null) {
|
if (editor.vim.mode.selectionType != null) {
|
||||||
@@ -774,10 +775,12 @@ internal object VimListenerManager {
|
|||||||
event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA &&
|
event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA &&
|
||||||
event.mouseEvent.button != MouseEvent.BUTTON3
|
event.mouseEvent.button != MouseEvent.BUTTON3
|
||||||
) {
|
) {
|
||||||
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
val commandLine = injector.commandLine.getActiveCommandLine()
|
||||||
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
if (commandLine != null) {
|
||||||
|
injector.processGroup.cancelExEntry(event.editor.vim, false)
|
||||||
|
}
|
||||||
|
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
ExOutputModel.getInstance(event.editor).close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,13 +11,12 @@ package com.maddyhome.idea.vim.newapi
|
|||||||
import com.intellij.openapi.editor.VisualPosition
|
import com.intellij.openapi.editor.VisualPosition
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.NativeAction
|
import com.maddyhome.idea.vim.api.NativeAction
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
|
||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
|
||||||
internal fun NativeAction?.execute(editor: VimEditor, context: ExecutionContext) {
|
internal fun NativeAction?.execute(context: ExecutionContext) {
|
||||||
if (this == null) return
|
if (this == null) return
|
||||||
injector.actionExecutor.executeAction(editor, this, context)
|
injector.actionExecutor.executeAction(null, this, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val VisualPosition.vim: VimVisualPosition
|
internal val VisualPosition.vim: VimVisualPosition
|
||||||
|
@@ -14,9 +14,6 @@ import com.maddyhome.idea.vim.common.LiveRange
|
|||||||
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
|
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
|
||||||
override val startOffset: Int
|
override val startOffset: Int
|
||||||
get() = marker.startOffset
|
get() = marker.startOffset
|
||||||
|
|
||||||
override val endOffset: Int
|
|
||||||
get() = marker.endOffset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val RangeMarker.vim: LiveRange
|
val RangeMarker.vim: LiveRange
|
||||||
|
@@ -30,9 +30,7 @@ import com.maddyhome.idea.vim.api.VimCaret
|
|||||||
import com.maddyhome.idea.vim.api.VimCaretListener
|
import com.maddyhome.idea.vim.api.VimCaretListener
|
||||||
import com.maddyhome.idea.vim.api.VimDocument
|
import com.maddyhome.idea.vim.api.VimDocument
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.VimEditorBase
|
|
||||||
import com.maddyhome.idea.vim.api.VimFoldRegion
|
import com.maddyhome.idea.vim.api.VimFoldRegion
|
||||||
import com.maddyhome.idea.vim.api.VimIndentConfig
|
|
||||||
import com.maddyhome.idea.vim.api.VimScrollingModel
|
import com.maddyhome.idea.vim.api.VimScrollingModel
|
||||||
import com.maddyhome.idea.vim.api.VimSelectionModel
|
import com.maddyhome.idea.vim.api.VimSelectionModel
|
||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||||
@@ -40,7 +38,6 @@ import com.maddyhome.idea.vim.api.VirtualFile
|
|||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.common.IndentConfig
|
import com.maddyhome.idea.vim.common.IndentConfig
|
||||||
import com.maddyhome.idea.vim.common.IndentConfig.Companion.create
|
|
||||||
import com.maddyhome.idea.vim.common.LiveRange
|
import com.maddyhome.idea.vim.common.LiveRange
|
||||||
import com.maddyhome.idea.vim.common.ModeChangeListener
|
import com.maddyhome.idea.vim.common.ModeChangeListener
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
@@ -55,7 +52,6 @@ import com.maddyhome.idea.vim.helper.inExMode
|
|||||||
import com.maddyhome.idea.vim.helper.isTemplateActive
|
import com.maddyhome.idea.vim.helper.isTemplateActive
|
||||||
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
|
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
|
||||||
import com.maddyhome.idea.vim.helper.vimLastSelectionType
|
import com.maddyhome.idea.vim.helper.vimLastSelectionType
|
||||||
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
|
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
||||||
@@ -63,7 +59,7 @@ import org.jetbrains.annotations.ApiStatus
|
|||||||
import java.lang.System.identityHashCode
|
import java.lang.System.identityHashCode
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase() {
|
internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
|
||||||
companion object {
|
companion object {
|
||||||
// For cases where Editor does not have a project (for some reason)
|
// For cases where Editor does not have a project (for some reason)
|
||||||
// It's something IJ Platform related and stored here because of this reason
|
// It's something IJ Platform related and stored here because of this reason
|
||||||
@@ -76,22 +72,12 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
val editor = editor.getTopLevelEditor()
|
val editor = editor.getTopLevelEditor()
|
||||||
val originalEditor = editor
|
val originalEditor = editor
|
||||||
|
|
||||||
override fun updateMode(mode: Mode) {
|
|
||||||
(injector.vimState as VimStateMachineImpl).mode = mode
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateIsReplaceCharacter(isReplaceCharacter: Boolean) {
|
|
||||||
(injector.vimState as VimStateMachineImpl).isReplaceCharacter = isReplaceCharacter
|
|
||||||
}
|
|
||||||
|
|
||||||
override val lfMakesNewLine: Boolean = true
|
override val lfMakesNewLine: Boolean = true
|
||||||
override var vimChangeActionSwitchMode: Mode?
|
override var vimChangeActionSwitchMode: Mode?
|
||||||
get() = editor.vimChangeActionSwitchMode
|
get() = editor.vimChangeActionSwitchMode
|
||||||
set(value) {
|
set(value) {
|
||||||
editor.vimChangeActionSwitchMode = value
|
editor.vimChangeActionSwitchMode = value
|
||||||
}
|
}
|
||||||
override val indentConfig: VimIndentConfig
|
|
||||||
get() = create(editor)
|
|
||||||
|
|
||||||
override fun fileSize(): Long = editor.fileSize.toLong()
|
override fun fileSize(): Long = editor.fileSize.toLong()
|
||||||
|
|
||||||
@@ -133,7 +119,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
||||||
if (injector.vimState.mode is Mode.INSERT) {
|
if (editor.isInsertMode) {
|
||||||
injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
||||||
}
|
}
|
||||||
editor.document.insertString(atPosition, text)
|
editor.document.insertString(atPosition, text)
|
||||||
@@ -165,7 +151,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
return editor.caretModel.allCarets.map { IjVimCaret(it) }
|
return editor.caretModel.allCarets.map { IjVimCaret(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override var isFirstCaret = true
|
override var isFirstCaret = false
|
||||||
override var isReversingCarets = false
|
override var isReversingCarets = false
|
||||||
|
|
||||||
@Suppress("ideavimRunForEachCaret")
|
@Suppress("ideavimRunForEachCaret")
|
||||||
@@ -173,6 +159,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
if (editor.vim.inBlockSelection) {
|
if (editor.vim.inBlockSelection) {
|
||||||
action(IjVimCaret(editor.caretModel.primaryCaret))
|
action(IjVimCaret(editor.caretModel.primaryCaret))
|
||||||
} else {
|
} else {
|
||||||
|
isFirstCaret = true
|
||||||
try {
|
try {
|
||||||
editor.caretModel.runForEachCaret({
|
editor.caretModel.runForEachCaret({
|
||||||
if (it.isValid) {
|
if (it.isValid) {
|
||||||
@@ -181,12 +168,13 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
}
|
}
|
||||||
}, false)
|
}, false)
|
||||||
} finally {
|
} finally {
|
||||||
isFirstCaret = true
|
isFirstCaret = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
|
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
|
||||||
|
isFirstCaret = true
|
||||||
isReversingCarets = reverse
|
isReversingCarets = reverse
|
||||||
try {
|
try {
|
||||||
editor.caretModel.runForEachCaret({
|
editor.caretModel.runForEachCaret({
|
||||||
@@ -194,7 +182,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
isFirstCaret = false
|
isFirstCaret = false
|
||||||
}, reverse)
|
}, reverse)
|
||||||
} finally {
|
} finally {
|
||||||
isFirstCaret = true
|
isFirstCaret = false
|
||||||
isReversingCarets = false
|
isReversingCarets = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,7 +452,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
// This is faster than simply calling Editor#logicalToVisualPosition
|
// This is faster than simply calling Editor#logicalToVisualPosition
|
||||||
return editor.offsetToVisualLine(editor.document.getLineStartOffset(line))
|
return editor.offsetToVisualLine(editor.document.getLineStartOffset(line))
|
||||||
}
|
}
|
||||||
return super<MutableLinearEditor>.bufferLineToVisualLine(line)
|
return super.bufferLineToVisualLine(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var insertMode: Boolean
|
override var insertMode: Boolean
|
||||||
|
@@ -11,6 +11,7 @@ package com.maddyhome.idea.vim.newapi
|
|||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.openapi.components.serviceIfCreated
|
import com.intellij.openapi.components.serviceIfCreated
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
|
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
|
||||||
import com.maddyhome.idea.vim.api.EngineEditorHelper
|
import com.maddyhome.idea.vim.api.EngineEditorHelper
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContextManager
|
import com.maddyhome.idea.vim.api.ExecutionContextManager
|
||||||
@@ -22,12 +23,13 @@ import com.maddyhome.idea.vim.api.VimApplication
|
|||||||
import com.maddyhome.idea.vim.api.VimChangeGroup
|
import com.maddyhome.idea.vim.api.VimChangeGroup
|
||||||
import com.maddyhome.idea.vim.api.VimClipboardManager
|
import com.maddyhome.idea.vim.api.VimClipboardManager
|
||||||
import com.maddyhome.idea.vim.api.VimCommandGroup
|
import com.maddyhome.idea.vim.api.VimCommandGroup
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLine
|
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLineService
|
import com.maddyhome.idea.vim.api.VimCommandLineService
|
||||||
import com.maddyhome.idea.vim.api.VimDigraphGroup
|
import com.maddyhome.idea.vim.api.VimDigraphGroup
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.VimEditorGroup
|
import com.maddyhome.idea.vim.api.VimEditorGroup
|
||||||
import com.maddyhome.idea.vim.api.VimEnabler
|
import com.maddyhome.idea.vim.api.VimEnabler
|
||||||
|
import com.maddyhome.idea.vim.api.VimExOutputPanel
|
||||||
|
import com.maddyhome.idea.vim.api.VimExOutputPanelService
|
||||||
import com.maddyhome.idea.vim.api.VimExtensionRegistrator
|
import com.maddyhome.idea.vim.api.VimExtensionRegistrator
|
||||||
import com.maddyhome.idea.vim.api.VimFile
|
import com.maddyhome.idea.vim.api.VimFile
|
||||||
import com.maddyhome.idea.vim.api.VimInjector
|
import com.maddyhome.idea.vim.api.VimInjector
|
||||||
@@ -37,10 +39,8 @@ import com.maddyhome.idea.vim.api.VimKeyGroup
|
|||||||
import com.maddyhome.idea.vim.api.VimLookupManager
|
import com.maddyhome.idea.vim.api.VimLookupManager
|
||||||
import com.maddyhome.idea.vim.api.VimMarkService
|
import com.maddyhome.idea.vim.api.VimMarkService
|
||||||
import com.maddyhome.idea.vim.api.VimMessages
|
import com.maddyhome.idea.vim.api.VimMessages
|
||||||
import com.maddyhome.idea.vim.api.VimModalInputService
|
|
||||||
import com.maddyhome.idea.vim.api.VimMotionGroup
|
import com.maddyhome.idea.vim.api.VimMotionGroup
|
||||||
import com.maddyhome.idea.vim.api.VimOptionGroup
|
import com.maddyhome.idea.vim.api.VimOptionGroup
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanelService
|
|
||||||
import com.maddyhome.idea.vim.api.VimProcessGroup
|
import com.maddyhome.idea.vim.api.VimProcessGroup
|
||||||
import com.maddyhome.idea.vim.api.VimPsiService
|
import com.maddyhome.idea.vim.api.VimPsiService
|
||||||
import com.maddyhome.idea.vim.api.VimRedrawService
|
import com.maddyhome.idea.vim.api.VimRedrawService
|
||||||
@@ -58,9 +58,8 @@ import com.maddyhome.idea.vim.api.VimrcFileState
|
|||||||
import com.maddyhome.idea.vim.api.VimscriptExecutor
|
import com.maddyhome.idea.vim.api.VimscriptExecutor
|
||||||
import com.maddyhome.idea.vim.api.VimscriptFunctionService
|
import com.maddyhome.idea.vim.api.VimscriptFunctionService
|
||||||
import com.maddyhome.idea.vim.api.VimscriptParser
|
import com.maddyhome.idea.vim.api.VimscriptParser
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.api.isInjectorInitialized
|
|
||||||
import com.maddyhome.idea.vim.diagnostic.VimLogger
|
import com.maddyhome.idea.vim.diagnostic.VimLogger
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
|
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
|
||||||
import com.maddyhome.idea.vim.group.CommandGroup
|
import com.maddyhome.idea.vim.group.CommandGroup
|
||||||
import com.maddyhome.idea.vim.group.EditorGroup
|
import com.maddyhome.idea.vim.group.EditorGroup
|
||||||
@@ -80,13 +79,14 @@ import com.maddyhome.idea.vim.helper.IjActionExecutor
|
|||||||
import com.maddyhome.idea.vim.helper.IjEditorHelper
|
import com.maddyhome.idea.vim.helper.IjEditorHelper
|
||||||
import com.maddyhome.idea.vim.helper.IjVimStringParser
|
import com.maddyhome.idea.vim.helper.IjVimStringParser
|
||||||
import com.maddyhome.idea.vim.helper.UndoRedoHelper
|
import com.maddyhome.idea.vim.helper.UndoRedoHelper
|
||||||
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.history.VimHistory
|
import com.maddyhome.idea.vim.history.VimHistory
|
||||||
|
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
|
||||||
import com.maddyhome.idea.vim.macro.VimMacro
|
import com.maddyhome.idea.vim.macro.VimMacro
|
||||||
import com.maddyhome.idea.vim.put.VimPut
|
import com.maddyhome.idea.vim.put.VimPut
|
||||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
||||||
import com.maddyhome.idea.vim.state.VimStateMachine
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
import com.maddyhome.idea.vim.ui.VimRcFileState
|
import com.maddyhome.idea.vim.ui.VimRcFileState
|
||||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanelService
|
|
||||||
import com.maddyhome.idea.vim.undo.VimUndoRedo
|
import com.maddyhome.idea.vim.undo.VimUndoRedo
|
||||||
import com.maddyhome.idea.vim.vimscript.Executor
|
import com.maddyhome.idea.vim.vimscript.Executor
|
||||||
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
||||||
@@ -94,16 +94,6 @@ import com.maddyhome.idea.vim.yank.VimYankGroup
|
|||||||
import com.maddyhome.idea.vim.yank.YankGroupBase
|
import com.maddyhome.idea.vim.yank.YankGroupBase
|
||||||
import javax.swing.JTextArea
|
import javax.swing.JTextArea
|
||||||
|
|
||||||
/**
|
|
||||||
* Currently, injector has to be initialized in all "entry points" from the IJ platform.
|
|
||||||
* This means Project Activities, listeners, status bar widgets, statistic collectors, etc.
|
|
||||||
* This is a bad pattern and we need to find a solution where the plugin doesn't have an "uninitialized state"
|
|
||||||
*/
|
|
||||||
internal fun initInjector() {
|
|
||||||
if (isInjectorInitialized()) return
|
|
||||||
injector = IjVimInjector()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class IjVimInjector : VimInjectorBase() {
|
internal class IjVimInjector : VimInjectorBase() {
|
||||||
override fun <T : Any> getLogger(clazz: Class<T>): VimLogger = IjVimLogger(Logger.getInstance(clazz))
|
override fun <T : Any> getLogger(clazz: Class<T>): VimLogger = IjVimLogger(Logger.getInstance(clazz))
|
||||||
|
|
||||||
@@ -115,6 +105,12 @@ internal class IjVimInjector : VimInjectorBase() {
|
|||||||
|
|
||||||
override val actionExecutor: VimActionExecutor
|
override val actionExecutor: VimActionExecutor
|
||||||
get() = service<IjActionExecutor>()
|
get() = service<IjActionExecutor>()
|
||||||
|
override val exOutputPanel: VimExOutputPanelService
|
||||||
|
get() = object : VimExOutputPanelService {
|
||||||
|
override fun getPanel(editor: VimEditor): VimExOutputPanel {
|
||||||
|
return ExOutputModel.getInstance(editor.ij)
|
||||||
|
}
|
||||||
|
}
|
||||||
override val historyGroup: VimHistory
|
override val historyGroup: VimHistory
|
||||||
get() = service<HistoryGroup>()
|
get() = service<HistoryGroup>()
|
||||||
override val extensionRegistrator: VimExtensionRegistrator
|
override val extensionRegistrator: VimExtensionRegistrator
|
||||||
@@ -197,10 +193,6 @@ internal class IjVimInjector : VimInjectorBase() {
|
|||||||
get() = com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
|
get() = com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
|
||||||
override val commandLine: VimCommandLineService
|
override val commandLine: VimCommandLineService
|
||||||
get() = service()
|
get() = service()
|
||||||
override val modalInput: VimModalInputService
|
|
||||||
get() = commandLine as ExEntryPanelService
|
|
||||||
override val outputPanel: VimOutputPanelService
|
|
||||||
get() = service()
|
|
||||||
|
|
||||||
override val optionGroup: VimOptionGroup
|
override val optionGroup: VimOptionGroup
|
||||||
get() = service()
|
get() = service()
|
||||||
@@ -214,14 +206,21 @@ internal class IjVimInjector : VimInjectorBase() {
|
|||||||
override val redrawService: VimRedrawService
|
override val redrawService: VimRedrawService
|
||||||
get() = service()
|
get() = service()
|
||||||
|
|
||||||
@Deprecated("Please use VimInjector.vimState", replaceWith = ReplaceWith("vimState"))
|
|
||||||
override fun commandStateFor(editor: VimEditor): VimStateMachine {
|
override fun commandStateFor(editor: VimEditor): VimStateMachine {
|
||||||
return vimState
|
var res = editor.ij.vimStateMachine
|
||||||
|
if (res == null) {
|
||||||
|
res = VimStateMachineImpl()
|
||||||
|
editor.ij.vimStateMachine = res
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Please use VimInjector.vimState", replaceWith = ReplaceWith("vimState"))
|
|
||||||
override fun commandStateFor(editor: Any): VimStateMachine {
|
override fun commandStateFor(editor: Any): VimStateMachine {
|
||||||
return vimState
|
return when (editor) {
|
||||||
|
is VimEditor -> this.commandStateFor(editor)
|
||||||
|
is Editor -> this.commandStateFor(IjVimEditor(editor))
|
||||||
|
else -> error("Unexpected type: $editor")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val engineEditorHelper: EngineEditorHelper
|
override val engineEditorHelper: EngineEditorHelper
|
||||||
|
@@ -97,6 +97,59 @@ open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Ele
|
|||||||
updateSearchHighlights(getLastUsedPattern(), lastIgnoreSmartCase, showSearchHighlight, true)
|
updateSearchHighlights(getLastUsedPattern(), lastIgnoreSmartCase, showSearchHighlight, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun confirmChoice(
|
||||||
|
editor: VimEditor,
|
||||||
|
context: ExecutionContext,
|
||||||
|
match: String,
|
||||||
|
caret: VimCaret,
|
||||||
|
startOffset: Int,
|
||||||
|
): ReplaceConfirmationChoice {
|
||||||
|
val result: Ref<ReplaceConfirmationChoice> = Ref.create(ReplaceConfirmationChoice.QUIT)
|
||||||
|
val keyStrokeProcessor: Function1<KeyStroke, Boolean> = label@{ key: KeyStroke ->
|
||||||
|
val choice: ReplaceConfirmationChoice
|
||||||
|
val c = key.keyChar
|
||||||
|
choice = if (key.isCloseKeyStroke() || c == 'q') {
|
||||||
|
ReplaceConfirmationChoice.QUIT
|
||||||
|
} else if (c == 'y') {
|
||||||
|
ReplaceConfirmationChoice.SUBSTITUTE_THIS
|
||||||
|
} else if (c == 'l') {
|
||||||
|
ReplaceConfirmationChoice.SUBSTITUTE_LAST
|
||||||
|
} else if (c == 'n') {
|
||||||
|
ReplaceConfirmationChoice.SKIP
|
||||||
|
} else if (c == 'a') {
|
||||||
|
ReplaceConfirmationChoice.SUBSTITUTE_ALL
|
||||||
|
} else {
|
||||||
|
return@label true
|
||||||
|
}
|
||||||
|
// TODO: Handle <C-E> and <C-Y>
|
||||||
|
result.set(choice)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
|
caret.moveToOffset(startOffset)
|
||||||
|
val inputModel = getInstance(editor.ij)
|
||||||
|
var key = inputModel.nextKeyStroke()
|
||||||
|
while (key != null) {
|
||||||
|
if (!keyStrokeProcessor.invoke(key)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key = inputModel.nextKeyStroke()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// XXX: The Ex entry panel is used only for UI here, its logic might be inappropriate for this method
|
||||||
|
val exEntryPanel = injector.commandLine.createWithoutShortcuts(
|
||||||
|
editor,
|
||||||
|
context,
|
||||||
|
MessageHelper.message("replace.with.0", match),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
caret.moveToOffset(startOffset)
|
||||||
|
ModalEntry.activate(editor, keyStrokeProcessor)
|
||||||
|
exEntryPanel.deactivate(refocusOwningEditor = true, resetCaret = false)
|
||||||
|
}
|
||||||
|
return result.get()
|
||||||
|
}
|
||||||
|
|
||||||
override fun addSubstitutionConfirmationHighlight(
|
override fun addSubstitutionConfirmationHighlight(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
|
718
src/main/java/com/maddyhome/idea/vim/package-info.java
Normal file
718
src/main/java/com/maddyhome/idea/vim/package-info.java
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IdeaVim command index.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 1. Insert mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |i_CTRL-@| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertExitAction}
|
||||||
|
* |i_CTRL-A| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertAction}
|
||||||
|
* |i_CTRL-C| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-D| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftLinesAction}
|
||||||
|
* |i_CTRL-E| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterBelowCursorAction}
|
||||||
|
* |i_CTRL-G_j| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-G_k| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-G_u| TO BE IMPLEMENTED
|
||||||
|
* |i_<BS>| {@link com.maddyhome.idea.vim.action.editor.VimEditorBackSpace}
|
||||||
|
* |i_digraph| IdeaVim enter digraph
|
||||||
|
* |i_CTRL-H| IntelliJ editor backspace
|
||||||
|
* |i_<Tab>| {@link com.maddyhome.idea.vim.action.editor.VimEditorTab}
|
||||||
|
* |i_CTRL-I| IntelliJ editor tab
|
||||||
|
* |i_<NL>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-J| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-K| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction}
|
||||||
|
* |i_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |i_<CR>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-M| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-N| {@link com.maddyhome.idea.vim.action.window.LookupDownAction}
|
||||||
|
* |i_CTRL-O| {@link com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction}
|
||||||
|
* |i_CTRL-P| {@link com.maddyhome.idea.vim.action.window.LookupUpAction}
|
||||||
|
* |i_CTRL-Q| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R| {@link com.maddyhome.idea.vim.action.change.insert.InsertRegisterAction}
|
||||||
|
* |i_CTRL-R_CTRL-R| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R_CTRL-P| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-T| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightLinesAction}
|
||||||
|
* |i_CTRL-U| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeleteInsertedTextAction}
|
||||||
|
* |i_CTRL-V| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
|
||||||
|
* |i_CTRL-V_digit| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
|
||||||
|
* |i_CTRL-W| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeletePreviousWordAction}
|
||||||
|
* |i_CTRL-X| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-Y| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterAboveCursorAction}
|
||||||
|
* |i_CTRL-Z| TO BE IMPLEMENTED
|
||||||
|
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
|
||||||
|
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-]} TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-^| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-_| TO BE IMPLEMENTED
|
||||||
|
* |i_0_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |i_^_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |i_<Del>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDelete}
|
||||||
|
* |i_<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction}
|
||||||
|
* |i_<S-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
|
||||||
|
* |i_<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
|
||||||
|
* |i_<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction}
|
||||||
|
* |i_<S-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
|
||||||
|
* |i_<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
|
||||||
|
* |i_<Up>| {@link com.maddyhome.idea.vim.action.editor.VimEditorUp}
|
||||||
|
* |i_<S-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
|
||||||
|
* |i_<Down>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDown}
|
||||||
|
* |i_<S-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
|
||||||
|
* |i_<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnInsertModeAction}
|
||||||
|
* |i_<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstInsertAction}
|
||||||
|
* |i_<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnInsertAction}
|
||||||
|
* |i_<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndInsertAction}
|
||||||
|
* |i_<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertInsertAction}
|
||||||
|
* |i_<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
|
||||||
|
* |i_<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
|
||||||
|
* |i_<F1>| IntelliJ help
|
||||||
|
* |i_<Insert>| IntelliJ editor toggle insert/replace
|
||||||
|
* |i_CTRL-X_index| TO BE IMPLEMENTED
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2. Normal mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberIncAction}
|
||||||
|
* |CTRL-B| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
|
||||||
|
* |CTRL-C| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-D| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageDownAction}
|
||||||
|
* |CTRL-E| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineDownAction}
|
||||||
|
* |CTRL-F| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
|
||||||
|
* |CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetFileInfoAction}
|
||||||
|
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
|
||||||
|
* |CTRL-H| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
|
||||||
|
* |<Tab>| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-I| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpNextAction}
|
||||||
|
* |<NL>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownNotLineWiseAction}
|
||||||
|
* |CTRL-J| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-L| not applicable
|
||||||
|
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.updown.EnterNormalAction}
|
||||||
|
* |CTRL-M| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
|
||||||
|
* |CTRL-N| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction}
|
||||||
|
* |CTRL-O| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpPreviousAction}
|
||||||
|
* |CTRL-P| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpCtrlPAction}
|
||||||
|
* |CTRL-R| {@link com.maddyhome.idea.vim.action.change.RedoAction}
|
||||||
|
* |CTRL-T| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-U| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageUpAction}
|
||||||
|
* |CTRL-V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleBlockModeAction}
|
||||||
|
* |CTRL-W| see window commands
|
||||||
|
* |CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberDecAction}
|
||||||
|
* |CTRL-Y| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineUpAction}
|
||||||
|
* |CTRL-Z| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-]| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |CTRL-6| {@link com.maddyhome.idea.vim.action.file.FilePreviousAction}
|
||||||
|
* |CTRL-\CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
|
||||||
|
* |<Space>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionSpaceAction}
|
||||||
|
* |!| {@link com.maddyhome.idea.vim.action.change.change.FilterMotionAction}
|
||||||
|
* |!!| translated to !_
|
||||||
|
* |quote| handled by command key parser
|
||||||
|
* |#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordBackwardAction}
|
||||||
|
* |$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction}
|
||||||
|
* |%| {@link com.maddyhome.idea.vim.action.motion.updown.MotionPercentOrMatchAction}
|
||||||
|
* |&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastSearchReplaceAction}
|
||||||
|
* |'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineAction}
|
||||||
|
* |''| ?
|
||||||
|
* ...
|
||||||
|
* |(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousStartAction}
|
||||||
|
* |)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextStartAction}
|
||||||
|
* |star| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction}
|
||||||
|
* |+| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
|
||||||
|
* |,| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharReverseAction}
|
||||||
|
* |-| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpFirstNonSpaceAction}
|
||||||
|
* |.| {@link com.maddyhome.idea.vim.action.change.RepeatChangeAction}
|
||||||
|
* |/| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction}
|
||||||
|
* |:| {@link com.maddyhome.idea.vim.action.ex.ExEntryAction}
|
||||||
|
* |;| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharAction}
|
||||||
|
* |<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftMotionAction}
|
||||||
|
* |<<| translated to <_
|
||||||
|
* |=| {@link com.maddyhome.idea.vim.action.change.shift.AutoIndentMotionAction}
|
||||||
|
* |==| translated to =_
|
||||||
|
* |>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightMotionAction}
|
||||||
|
* |>>| translated to >_
|
||||||
|
* |?| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction}
|
||||||
|
* |@| {@link com.maddyhome.idea.vim.action.macro.PlaybackRegisterAction}
|
||||||
|
* |A| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterLineEndAction}
|
||||||
|
* |B| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordLeftAction}
|
||||||
|
* |C| {@link com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction}
|
||||||
|
* |D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteEndOfLineAction}
|
||||||
|
* |E| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndRightAction}
|
||||||
|
* |F| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftMatchCharAction}
|
||||||
|
* |G| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastAction}
|
||||||
|
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionFirstScreenLineAction}
|
||||||
|
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingFirstScreenLineAction}
|
||||||
|
* |I| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeFirstNonBlankAction}
|
||||||
|
* |J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction}
|
||||||
|
* |K| {@link com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc}
|
||||||
|
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionLastScreenLineAction}
|
||||||
|
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingLastScreenLineAction}
|
||||||
|
* |M| {@link com.maddyhome.idea.vim.action.motion.screen.MotionMiddleScreenLineAction}
|
||||||
|
* |N| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainPreviousAction}
|
||||||
|
* |O| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineAboveAction}
|
||||||
|
* |P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorAction}
|
||||||
|
* |Q| TO BE IMPLEMENTED
|
||||||
|
* |R| {@link com.maddyhome.idea.vim.action.change.change.ChangeReplaceAction}
|
||||||
|
* |S| {@link com.maddyhome.idea.vim.action.change.change.ChangeLineAction}
|
||||||
|
* |T| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftTillMatchCharAction}
|
||||||
|
* |U| ?
|
||||||
|
* |V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleLineModeAction}
|
||||||
|
* |W| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordRightAction}
|
||||||
|
* |X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterLeftAction}
|
||||||
|
* |Y| {@link com.maddyhome.idea.vim.action.copy.YankLineAction}
|
||||||
|
* |ZZ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
|
||||||
|
* |ZQ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
|
||||||
|
* |[| see bracket commands
|
||||||
|
* |]| see bracket commands
|
||||||
|
* |^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstNonSpaceAction}
|
||||||
|
* |_| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction}
|
||||||
|
* |`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkAction}
|
||||||
|
* |``| ?
|
||||||
|
* ...
|
||||||
|
* |0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnAction}
|
||||||
|
* |a| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterCursorAction}
|
||||||
|
* |b| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
|
||||||
|
* |c| {@link com.maddyhome.idea.vim.action.change.change.ChangeMotionAction}
|
||||||
|
* |cc| translated to c_
|
||||||
|
* |d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteMotionAction}
|
||||||
|
* |dd| translated to d_
|
||||||
|
* |do| TO BE IMPLEMENTED
|
||||||
|
* |dp| TO BE IMPLEMENTED
|
||||||
|
* |e| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndRightAction}
|
||||||
|
* |f| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction}
|
||||||
|
* |g| see commands starting with 'g'
|
||||||
|
* |h| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction}
|
||||||
|
* |i| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
|
||||||
|
* |j| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownAction}
|
||||||
|
* |k| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpAction}
|
||||||
|
* |l| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction}
|
||||||
|
* |m| {@link com.maddyhome.idea.vim.action.motion.mark.MotionMarkAction}
|
||||||
|
* |n| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainNextAction}
|
||||||
|
* |o| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineBelowAction}
|
||||||
|
* |p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorAction}
|
||||||
|
* |q| {@link com.maddyhome.idea.vim.action.macro.ToggleRecordingAction}
|
||||||
|
* |r| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction}
|
||||||
|
* |s| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction}
|
||||||
|
* |t| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction}
|
||||||
|
* |u| {@link com.maddyhome.idea.vim.action.change.UndoAction}
|
||||||
|
* |v| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction}
|
||||||
|
* |w| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
|
||||||
|
* |x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterRightAction}
|
||||||
|
* |y| {@link com.maddyhome.idea.vim.action.copy.YankMotionAction}
|
||||||
|
* |yy| translated to y_
|
||||||
|
* |z| see commands starting with 'z'
|
||||||
|
* |{| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphPreviousAction}
|
||||||
|
* |bar| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionColumnAction}
|
||||||
|
* |}| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphNextAction}
|
||||||
|
* |~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction}
|
||||||
|
* |<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndAction}
|
||||||
|
* |<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
|
||||||
|
* |<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
|
||||||
|
* |<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
|
||||||
|
* |<C-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlDownAction}
|
||||||
|
* |<C-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlUpAction}
|
||||||
|
* |<Del>| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction}
|
||||||
|
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
|
||||||
|
* |<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction}
|
||||||
|
* |<F1>| IntelliJ help
|
||||||
|
* |<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction}
|
||||||
|
* |<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
|
||||||
|
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction}
|
||||||
|
* |<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
|
||||||
|
* |<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
|
||||||
|
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction}
|
||||||
|
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
|
||||||
|
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
|
||||||
|
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
|
||||||
|
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
|
||||||
|
* |<S-Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction}
|
||||||
|
* |<S-End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction}
|
||||||
|
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.1. Text objects
|
||||||
|
*
|
||||||
|
* Text object commands are listed in the visual mode section.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.2. Window commands
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |CTRL-W_+| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_-| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_<| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_=| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_>| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_H| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_J| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_K| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_L| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_P| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_R| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_S| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
|
||||||
|
* |CTRL-W_T| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_W| {@link com.maddyhome.idea.vim.action.window.WindowPrevAction}
|
||||||
|
* |CTRL-W_]| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_^| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W__| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_b| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_c| {@link com.maddyhome.idea.vim.action.window.CloseWindowAction}
|
||||||
|
* |CTRL-W_d| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_f| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-F| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-g]| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-g}| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-gf| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-gF| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_h| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_i| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_j| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_k| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_l| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
* |CTRL-W_n| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_o| {@link com.maddyhome.idea.vim.action.window.WindowOnlyAction}
|
||||||
|
* |CTRL-W_p| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_q| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_r| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_s| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
|
||||||
|
* |CTRL-W_t| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_v| {@link com.maddyhome.idea.vim.action.window.VerticalSplitAction}
|
||||||
|
* |CTRL-W_w| {@link com.maddyhome.idea.vim.action.window.WindowNextAction}
|
||||||
|
* |CTRL-W_x| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_z| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_bar| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_}| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_<Down>| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_<Up>| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_<Left>| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_<Right>| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
* |CTRL-W_CTRL-H| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_CTRL-J| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_CTRL-K| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_CTRL-L| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.3. Square bracket commands
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |[_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |[_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |[#| TO BE IMPLEMENTED
|
||||||
|
* |['| TO BE IMPLEMENTED
|
||||||
|
* |[(| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenOpenAction}
|
||||||
|
* |[star| TO BE IMPLEMENTED
|
||||||
|
* |[`| TO BE IMPLEMENTED
|
||||||
|
* |[/| TO BE IMPLEMENTED
|
||||||
|
* |[D| TO BE IMPLEMENTED
|
||||||
|
* |[I| TO BE IMPLEMENTED
|
||||||
|
* |[M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousEndAction}
|
||||||
|
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
|
||||||
|
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
|
||||||
|
* |[[| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardStartAction}
|
||||||
|
* |[]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardEndAction}
|
||||||
|
* |[c| TO BE IMPLEMENTED
|
||||||
|
* |[d| TO BE IMPLEMENTED
|
||||||
|
* |[f| TO BE IMPLEMENTED
|
||||||
|
* |[i| TO BE IMPLEMENTED
|
||||||
|
* |[m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
|
||||||
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
|
* |[s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
|
||||||
|
* |[z| TO BE IMPLEMENTED
|
||||||
|
* |[{| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
|
||||||
|
* |]_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |]_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |]#| TO BE IMPLEMENTED
|
||||||
|
* |]'| TO BE IMPLEMENTED
|
||||||
|
* |])| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenCloseAction}
|
||||||
|
* |]star| TO BE IMPLEMENTED
|
||||||
|
* |]`| TO BE IMPLEMENTED
|
||||||
|
* |]/| TO BE IMPLEMENTED
|
||||||
|
* |]D| TO BE IMPLEMENTED
|
||||||
|
* |]I| TO BE IMPLEMENTED
|
||||||
|
* |]M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction}
|
||||||
|
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
|
||||||
|
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
|
||||||
|
* |][| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardEndAction}
|
||||||
|
* |]]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardStartAction}
|
||||||
|
* |]c| TO BE IMPLEMENTED
|
||||||
|
* |]d| TO BE IMPLEMENTED
|
||||||
|
* |]f| TO BE IMPLEMENTED
|
||||||
|
* |]i| TO BE IMPLEMENTED
|
||||||
|
* |]m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
|
||||||
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
|
* |]s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
|
||||||
|
* |]z| TO BE IMPLEMENTED
|
||||||
|
* |]}| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.4. Commands starting with 'g'
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |g_CTRL-A| not applicable
|
||||||
|
* |g_CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetLocationInfoAction}
|
||||||
|
* |g_CTRL-H| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableBlockModeAction}
|
||||||
|
* |g_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |g#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordBackwardAction}
|
||||||
|
* |g$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
|
||||||
|
* |g&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastGlobalSearchReplaceAction}
|
||||||
|
* |v_g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineNoSaveJumpAction}
|
||||||
|
* |g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineNoSaveJumpAction}
|
||||||
|
* |g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkNoSaveJumpAction}
|
||||||
|
* |gstar| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordForwardAction}
|
||||||
|
* |g+| TO BE IMPLEMENTED
|
||||||
|
* |g,| TO BE IMPLEMENTED
|
||||||
|
* |g-| TO BE IMPLEMENTED
|
||||||
|
* |g0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
|
||||||
|
* |g8| {@link com.maddyhome.idea.vim.action.file.FileGetHexAction}
|
||||||
|
* |g;| TO BE IMPLEMENTED
|
||||||
|
* |g<| TO BE IMPLEMENTED
|
||||||
|
* |g?| TO BE IMPLEMENTED
|
||||||
|
* |g?g?| TO BE IMPLEMENTED
|
||||||
|
* |gD| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |gE| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndLeftAction}
|
||||||
|
* |gF| TO BE IMPLEMENTED
|
||||||
|
* |gH| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableLineModeAction}
|
||||||
|
* |gI| {@link com.maddyhome.idea.vim.action.change.insert.InsertLineStartAction}
|
||||||
|
* |gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction}
|
||||||
|
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch}
|
||||||
|
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject}
|
||||||
|
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorMoveCursorAction}
|
||||||
|
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorActionMoveCursor}
|
||||||
|
* |gQ| TO BE IMPLEMENTED
|
||||||
|
* |gR| TO BE IMPLEMENTED
|
||||||
|
* |gT| {@link com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction}
|
||||||
|
* |gU| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction}
|
||||||
|
* |gV| TO BE IMPLEMENTED
|
||||||
|
* |g]| TO BE IMPLEMENTED
|
||||||
|
* |g^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenNonSpaceAction}
|
||||||
|
* |g_| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastNonSpaceAction}
|
||||||
|
* |ga| {@link com.maddyhome.idea.vim.action.file.FileGetAsciiAction}
|
||||||
|
* |gd| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |ge| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndLeftAction}
|
||||||
|
* |gf| TO BE IMPLEMENTED
|
||||||
|
* |gg| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
|
||||||
|
* |gh| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableCharacterModeAction}
|
||||||
|
* |gi| {@link com.maddyhome.idea.vim.action.change.insert.InsertAtPreviousInsertAction}
|
||||||
|
* |gj| TO BE IMPLEMENTED
|
||||||
|
* |gk| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
|
||||||
|
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch}
|
||||||
|
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject}
|
||||||
|
* |gm| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionMiddleColumnAction}
|
||||||
|
* |go| {@link com.maddyhome.idea.vim.action.motion.text.MotionNthCharacterAction}
|
||||||
|
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorMoveCursorAction}
|
||||||
|
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorActionMoveCursor}
|
||||||
|
* |gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeMotionAction}
|
||||||
|
* |gr| TO BE IMPLEMENTED
|
||||||
|
* |gs| TO BE IMPLEMENTED
|
||||||
|
* |gt| {@link com.maddyhome.idea.vim.action.window.tabs.NextTabAction}
|
||||||
|
* |gu| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction}
|
||||||
|
* |gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSelectPreviousAction}
|
||||||
|
* |gw| TO BE IMPLEMENTED
|
||||||
|
* |g@| {@link com.maddyhome.idea.vim.action.change.OperatorAction}
|
||||||
|
* |g~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction}
|
||||||
|
* |g<Down>| TO BE IMPLEMENTED
|
||||||
|
* |g<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
|
||||||
|
* |g<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
|
||||||
|
* |g<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.5. Commands starting with 'z'
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |z<CR>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineStartAction}
|
||||||
|
* |z+| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLinePageStartAction}
|
||||||
|
* |z-| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineStartAction}
|
||||||
|
* |z.| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineStartAction}
|
||||||
|
* |z=| TO BE IMPLEMENTED
|
||||||
|
* |zA| TO BE IMPLEMENTED
|
||||||
|
* |zC| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegionRecursively}
|
||||||
|
* |zD| TO BE IMPLEMENTED
|
||||||
|
* |zE| TO BE IMPLEMENTED
|
||||||
|
* |zF| TO BE IMPLEMENTED
|
||||||
|
* |zG| TO BE IMPLEMENTED
|
||||||
|
* |zH| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction}
|
||||||
|
* |zL| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction}
|
||||||
|
* |zM| {@link com.maddyhome.idea.vim.action.fold.VimCollapseAllRegions}
|
||||||
|
* |zN| TO BE IMPLEMENTED
|
||||||
|
* |zO| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegionRecursively}
|
||||||
|
* |zR| {@link com.maddyhome.idea.vim.action.fold.VimExpandAllRegions}
|
||||||
|
* |zW| TO BE IMPLEMENTED
|
||||||
|
* |zX| TO BE IMPLEMENTED
|
||||||
|
* |z^| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLinePageStartAction}
|
||||||
|
* |za| TO BE IMPLEMENTED
|
||||||
|
* |zb| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineAction}
|
||||||
|
* |zc| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegion}
|
||||||
|
* |zd| not applicable
|
||||||
|
* |ze| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenColumnAction}
|
||||||
|
* |zf| not applicable
|
||||||
|
* |zg| TO BE IMPLEMENTED
|
||||||
|
* |zh| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
|
||||||
|
* |zi| TO BE IMPLEMENTED
|
||||||
|
* |zj| TO BE IMPLEMENTED
|
||||||
|
* |zk| TO BE IMPLEMENTED
|
||||||
|
* |zl| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
|
||||||
|
* |zm| TO BE IMPLEMENTED
|
||||||
|
* |zn| TO BE IMPLEMENTED
|
||||||
|
* |zo| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegion}
|
||||||
|
* |zr| TO BE IMPLEMENTED
|
||||||
|
* |zs| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenColumnAction}
|
||||||
|
* |zt| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineAction}
|
||||||
|
* |zv| TO BE IMPLEMENTED
|
||||||
|
* |zw| TO BE IMPLEMENTED
|
||||||
|
* |zx| TO BE IMPLEMENTED
|
||||||
|
* |zz| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineAction}
|
||||||
|
* |z<Left>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
|
||||||
|
* |z<Right>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 3. Visual mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |v_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |v_CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberIncAction}
|
||||||
|
* |v_CTRL-C| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-G| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
|
||||||
|
* |v_<BS>| NVO mapping
|
||||||
|
* |v_CTRL-H| NVO mapping
|
||||||
|
* |v_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |v_CTRL-V| NVO mapping
|
||||||
|
* |v_<Esc>| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberDecAction}
|
||||||
|
* |v_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |v_!| {@link com.maddyhome.idea.vim.action.change.change.FilterVisualLinesAction}
|
||||||
|
* |v_:| NVO mapping
|
||||||
|
* |v_<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftVisualAction}
|
||||||
|
* |v_=| {@link com.maddyhome.idea.vim.action.change.change.AutoIndentLinesVisualAction}
|
||||||
|
* |v_>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightVisualAction}
|
||||||
|
* |v_b_A| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction}
|
||||||
|
* |v_C| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesEndAction}
|
||||||
|
* |v_D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesEndAction}
|
||||||
|
* |v_b_I| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction}
|
||||||
|
* |v_J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction}
|
||||||
|
* |v_K| TO BE IMPLEMENTED
|
||||||
|
* |v_O| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsBlockAction}
|
||||||
|
* |v_P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorAction}
|
||||||
|
* |v_R| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
|
||||||
|
* |v_S| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
|
||||||
|
* |v_U| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction}
|
||||||
|
* |v_V| NV mapping
|
||||||
|
* |v_X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesAction}
|
||||||
|
* |v_Y| {@link com.maddyhome.idea.vim.action.copy.YankVisualLinesAction}
|
||||||
|
* |v_aquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockDoubleQuoteAction}
|
||||||
|
* |v_a'| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockSingleQuoteAction}
|
||||||
|
* |v_a(| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_a)| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_a<| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
|
||||||
|
* |v_a>| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
|
||||||
|
* |v_aB| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_aW| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction}
|
||||||
|
* |v_a[| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
|
||||||
|
* |v_a]| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
|
||||||
|
* |v_a`| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBackQuoteAction}
|
||||||
|
* |v_ab| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_ap| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterParagraphAction}
|
||||||
|
* |v_as| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterSentenceAction}
|
||||||
|
* |v_at| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockTagAction}
|
||||||
|
* |v_aw| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction}
|
||||||
|
* |v_a{| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_a}| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_c| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
|
||||||
|
* |v_d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
|
||||||
|
* |v_gCTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheIncAction}
|
||||||
|
* |v_gCTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheDecAction}
|
||||||
|
* |v_gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction}
|
||||||
|
* |v_gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeVisualAction}
|
||||||
|
* |v_gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapSelectionsAction}
|
||||||
|
* |v_g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkNoSaveJumpAction}
|
||||||
|
* |v_g@| {@link com.maddyhome.idea.vim.action.change.VisualOperatorAction}
|
||||||
|
* |v_iquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockDoubleQuoteAction}
|
||||||
|
* |v_i'| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockSingleQuoteAction}
|
||||||
|
* |v_i(| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_i)| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_i<| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
|
||||||
|
* |v_i>| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
|
||||||
|
* |v_iB| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_iW| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBigWordAction}
|
||||||
|
* |v_i[| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
|
||||||
|
* |v_i]| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
|
||||||
|
* |v_i`| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBackQuoteAction}
|
||||||
|
* |v_ib| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_ip| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerParagraphAction}
|
||||||
|
* |v_is| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerSentenceAction}
|
||||||
|
* |v_it| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockTagAction}
|
||||||
|
* |v_iw| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerWordAction}
|
||||||
|
* |v_i{| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_i}| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_o| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsAction}
|
||||||
|
* |v_p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorAction}
|
||||||
|
* |v_r| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction}
|
||||||
|
* |v_s| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
|
||||||
|
* |v_u| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction}
|
||||||
|
* |v_v| NV mapping
|
||||||
|
* |v_x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
|
||||||
|
* |v_y| {@link com.maddyhome.idea.vim.action.copy.YankVisualAction}
|
||||||
|
* |v_~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction}
|
||||||
|
* |v_`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkAction}
|
||||||
|
* |v_'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 4. Select mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
|
||||||
|
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnterAction}
|
||||||
|
* |<DEL>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
|
||||||
|
* |<ESC>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEscapeAction}
|
||||||
|
* |<C-G>| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
|
||||||
|
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
|
||||||
|
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
|
||||||
|
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
|
||||||
|
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
|
||||||
|
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
|
||||||
|
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction}
|
||||||
|
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction}
|
||||||
|
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
|
||||||
|
*
|
||||||
|
* 5. Command line editing
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |c_CTRL-A| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-B| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
|
||||||
|
* |c_CTRL-C| {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
|
||||||
|
* |c_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-E| {@link javax.swing.text.DefaultEditorKit#endLineAction}
|
||||||
|
* |c_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-H| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
|
||||||
|
* |c_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-J| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_CTRL-K| Handled by KeyHandler
|
||||||
|
* |c_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-M| {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
|
||||||
|
* |c_CTRL-N| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_CTRL-P| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_CTRL-Q| Handled by KeyHandler
|
||||||
|
* |c_CTRL-R_CTRL-A| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-F| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-P| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-R| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-W| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-T| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-U| {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
|
||||||
|
* |c_CTRL-V| Handled by KeyHandler
|
||||||
|
* |c_CTRL-W| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
|
||||||
|
* |c_CTRL-Y| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_e| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_CTRL-N| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-_| not applicable
|
||||||
|
* |c_CTRL-^| not applicable
|
||||||
|
* |c_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-[| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
|
||||||
|
* |c_<BS>| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
|
||||||
|
* |c_<CR>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_<C-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
|
||||||
|
* |c_<C-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
|
||||||
|
* |c_<Del>| {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
|
||||||
|
* |c_<Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
|
||||||
|
* |c_<End>| {@link javax.swing.text.DefaultEditorKit#endLineAction}
|
||||||
|
* |c_<Esc>| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
|
||||||
|
* |c_<Home>| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
|
||||||
|
* |c_<Insert>| {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
|
||||||
|
* |c_<Left>| {@link javax.swing.text.DefaultEditorKit#backwardAction}
|
||||||
|
* |c_<LeftMouse>| not applicable
|
||||||
|
* |c_<MiddleMouse>| TO BE IMPLEMENTED
|
||||||
|
* |c_<NL>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_<PageUp>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_<PageDown>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_<Right>| {@link javax.swing.text.DefaultEditorKit#forwardAction}
|
||||||
|
* |c_<S-Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_<S-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
|
||||||
|
* |c_<S-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
|
||||||
|
* |c_<S-Tab>| TO BE IMPLEMENTED
|
||||||
|
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_<Tab>| TO BE IMPLEMENTED
|
||||||
|
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
|
||||||
|
* |c_digraph| {char1} <BS> {char2}
|
||||||
|
* |c_wildchar| TO BE IMPLEMENTED
|
||||||
|
* |'cedit'| TO BE IMPLEMENTED
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 6. Ex commands
|
||||||
|
*
|
||||||
|
* tag handler
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |:map| {@link com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand}
|
||||||
|
* |:nmap| ...
|
||||||
|
* |:vmap| ...
|
||||||
|
* |:omap| ...
|
||||||
|
* |:imap| ...
|
||||||
|
* |:cmap| ...
|
||||||
|
* |:noremap| ...
|
||||||
|
* |:nnoremap| ...
|
||||||
|
* |:vnoremap| ...
|
||||||
|
* |:onoremap| ...
|
||||||
|
* |:inoremap| ...
|
||||||
|
* |:cnoremap| ...
|
||||||
|
* |:shell| {@link com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand}
|
||||||
|
* |:sort| {@link com.maddyhome.idea.vim.vimscript.model.commands.SortCommand}
|
||||||
|
* |:source| {@link com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand}
|
||||||
|
* |:qall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:wqall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:xall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:command| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand}
|
||||||
|
* |:delcommand| {@link com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand}
|
||||||
|
* |:comclear| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand}
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* The list of supported Ex commands is incomplete.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* A. Misc commands
|
||||||
|
*
|
||||||
|
* tag handler
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |]b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndLeftAction}
|
||||||
|
* |]w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndRightAction}
|
||||||
|
* |[b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelLeftAction}
|
||||||
|
* |[w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelRightAction}
|
||||||
|
* |g(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousEndAction}
|
||||||
|
* |g)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextEndAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See also :help index.
|
||||||
|
*
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
package com.maddyhome.idea.vim;
|
@@ -19,16 +19,11 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.group.IjOptionConstants
|
import com.maddyhome.idea.vim.group.IjOptionConstants
|
||||||
import com.maddyhome.idea.vim.group.IjOptions
|
import com.maddyhome.idea.vim.group.IjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.options.OptionAccessScope
|
import com.maddyhome.idea.vim.options.OptionAccessScope
|
||||||
import com.maddyhome.idea.vim.options.OptionConstants
|
import com.maddyhome.idea.vim.options.OptionConstants
|
||||||
|
|
||||||
internal class OptionsState : ApplicationUsagesCollector() {
|
internal class OptionsState : ApplicationUsagesCollector() {
|
||||||
|
|
||||||
init {
|
|
||||||
initInjector()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getGroup(): EventLogGroup = GROUP
|
override fun getGroup(): EventLogGroup = GROUP
|
||||||
|
|
||||||
override fun getMetrics(): Set<MetricEvent> {
|
override fun getMetrics(): Set<MetricEvent> {
|
||||||
|
@@ -13,16 +13,11 @@ import com.intellij.internal.statistic.eventLog.EventLogGroup
|
|||||||
import com.intellij.internal.statistic.eventLog.events.EventFields
|
import com.intellij.internal.statistic.eventLog.events.EventFields
|
||||||
import com.intellij.internal.statistic.eventLog.events.VarargEventId
|
import com.intellij.internal.statistic.eventLog.events.VarargEventId
|
||||||
import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector
|
import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.statistic.PluginState.Util.extensionNames
|
import com.maddyhome.idea.vim.statistic.PluginState.Util.extensionNames
|
||||||
import com.maddyhome.idea.vim.vimscript.services.VimRcService
|
import com.maddyhome.idea.vim.vimscript.services.VimRcService
|
||||||
|
|
||||||
internal class VimscriptState : ApplicationUsagesCollector() {
|
internal class VimscriptState : ApplicationUsagesCollector() {
|
||||||
|
|
||||||
init {
|
|
||||||
initInjector()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getGroup(): EventLogGroup = GROUP
|
override fun getGroup(): EventLogGroup = GROUP
|
||||||
|
|
||||||
override fun getMetrics(): Set<MetricEvent> {
|
override fun getMetrics(): Set<MetricEvent> {
|
||||||
|
@@ -44,7 +44,7 @@ internal class Troubleshooter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getInstance() = service<Troubleshooter>()
|
val instance = service<Troubleshooter>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ import com.maddyhome.idea.vim.KeyHandler;
|
|||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext;
|
import com.maddyhome.idea.vim.api.ExecutionContext;
|
||||||
import com.maddyhome.idea.vim.api.VimEditor;
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanel;
|
|
||||||
import com.maddyhome.idea.vim.diagnostic.VimLogger;
|
import com.maddyhome.idea.vim.diagnostic.VimLogger;
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper;
|
import com.maddyhome.idea.vim.helper.MessageHelper;
|
||||||
import com.maddyhome.idea.vim.helper.UiHelper;
|
import com.maddyhome.idea.vim.helper.UiHelper;
|
||||||
@@ -47,18 +46,19 @@ import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
|
|||||||
public class ExOutputPanel extends JPanel {
|
public class ExOutputPanel extends JPanel {
|
||||||
private final @NotNull Editor myEditor;
|
private final @NotNull Editor myEditor;
|
||||||
|
|
||||||
public final @NotNull JLabel myLabel = new JLabel("more");
|
private final @NotNull JLabel myLabel = new JLabel("more");
|
||||||
private final @NotNull JTextArea myText = new JTextArea();
|
private final @NotNull JTextArea myText = new JTextArea();
|
||||||
private final @NotNull JScrollPane myScrollPane =
|
private final @NotNull JScrollPane myScrollPane =
|
||||||
new JBScrollPane(myText, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
new JBScrollPane(myText, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
private final @NotNull ComponentAdapter myAdapter;
|
private final @NotNull ComponentAdapter myAdapter;
|
||||||
|
private boolean myAtEnd = false;
|
||||||
private int myLineHeight = 0;
|
private int myLineHeight = 0;
|
||||||
|
|
||||||
private @Nullable JComponent myOldGlass = null;
|
private @Nullable JComponent myOldGlass = null;
|
||||||
private @Nullable LayoutManager myOldLayout = null;
|
private @Nullable LayoutManager myOldLayout = null;
|
||||||
private boolean myWasOpaque = false;
|
private boolean myWasOpaque = false;
|
||||||
|
|
||||||
public boolean myActive = false;
|
private boolean myActive = false;
|
||||||
|
|
||||||
private static final VimLogger LOG = injector.getLogger(ExOutputPanel.class);
|
private static final VimLogger LOG = injector.getLogger(ExOutputPanel.class);
|
||||||
|
|
||||||
@@ -90,16 +90,12 @@ public class ExOutputPanel extends JPanel {
|
|||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable ExOutputPanel getNullablePanel(@NotNull Editor editor) {
|
|
||||||
return UserDataManager.getVimMorePanel(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPanelActive(@NotNull Editor editor) {
|
public static boolean isPanelActive(@NotNull Editor editor) {
|
||||||
return getNullablePanel(editor) != null;
|
return UserDataManager.getVimMorePanel(editor) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull ExOutputPanel getInstance(@NotNull Editor editor) {
|
public static @NotNull ExOutputPanel getInstance(@NotNull Editor editor) {
|
||||||
ExOutputPanel panel = getNullablePanel(editor);
|
ExOutputPanel panel = UserDataManager.getVimMorePanel(editor);
|
||||||
if (panel == null) {
|
if (panel == null) {
|
||||||
panel = new ExOutputPanel(editor);
|
panel = new ExOutputPanel(editor);
|
||||||
UserDataManager.setVimMorePanel(editor, panel);
|
UserDataManager.setVimMorePanel(editor, panel);
|
||||||
@@ -196,7 +192,7 @@ public class ExOutputPanel extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Turns on the more window for the given editor
|
* Turns on the more window for the given editor
|
||||||
*/
|
*/
|
||||||
public void activate() {
|
private void activate() {
|
||||||
JRootPane root = SwingUtilities.getRootPane(myEditor.getContentComponent());
|
JRootPane root = SwingUtilities.getRootPane(myEditor.getContentComponent());
|
||||||
myOldGlass = (JComponent)root.getGlassPane();
|
myOldGlass = (JComponent)root.getGlassPane();
|
||||||
if (myOldGlass != null) {
|
if (myOldGlass != null) {
|
||||||
@@ -224,31 +220,42 @@ public class ExOutputPanel extends JPanel {
|
|||||||
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollLine() {
|
private void scrollLine() {
|
||||||
scrollOffset(myLineHeight);
|
scrollOffset(myLineHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollPage() {
|
private void scrollPage() {
|
||||||
scrollOffset(myScrollPane.getVerticalScrollBar().getVisibleAmount());
|
scrollOffset(myScrollPane.getVerticalScrollBar().getVisibleAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollHalfPage() {
|
private void scrollHalfPage() {
|
||||||
double sa = myScrollPane.getVerticalScrollBar().getVisibleAmount() / 2.0;
|
double sa = myScrollPane.getVerticalScrollBar().getVisibleAmount() / 2.0;
|
||||||
double offset = Math.ceil(sa / myLineHeight) * myLineHeight;
|
double offset = Math.ceil(sa / myLineHeight) * myLineHeight;
|
||||||
scrollOffset((int)offset);
|
scrollOffset((int)offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBadKey() {
|
private void handleEnter() {
|
||||||
|
if (myAtEnd) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void badKey() {
|
||||||
myLabel.setText(MessageHelper.message("more.ret.line.space.page.d.half.page.q.quit"));
|
myLabel.setText(MessageHelper.message("more.ret.line.space.page.d.half.page.q.quit"));
|
||||||
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollOffset(int more) {
|
private void scrollOffset(int more) {
|
||||||
|
myAtEnd = false;
|
||||||
int val = myScrollPane.getVerticalScrollBar().getValue();
|
int val = myScrollPane.getVerticalScrollBar().getValue();
|
||||||
myScrollPane.getVerticalScrollBar().setValue(val + more);
|
myScrollPane.getVerticalScrollBar().setValue(val + more);
|
||||||
myScrollPane.getHorizontalScrollBar().setValue(0);
|
myScrollPane.getHorizontalScrollBar().setValue(0);
|
||||||
if (val + more >=
|
if (val + more >=
|
||||||
myScrollPane.getVerticalScrollBar().getMaximum() - myScrollPane.getVerticalScrollBar().getVisibleAmount()) {
|
myScrollPane.getVerticalScrollBar().getMaximum() - myScrollPane.getVerticalScrollBar().getVisibleAmount()) {
|
||||||
|
myAtEnd = true;
|
||||||
myLabel.setText(MessageHelper.message("hit.enter.or.type.command.to.continue"));
|
myLabel.setText(MessageHelper.message("hit.enter.or.type.command.to.continue"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -257,11 +264,6 @@ public class ExOutputPanel extends JPanel {
|
|||||||
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAtEnd() {
|
|
||||||
int val = myScrollPane.getVerticalScrollBar().getValue();
|
|
||||||
return val >= myScrollPane.getVerticalScrollBar().getMaximum() - myScrollPane.getVerticalScrollBar().getVisibleAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void positionPanel() {
|
private void positionPanel() {
|
||||||
final JComponent contentComponent = myEditor.getContentComponent();
|
final JComponent contentComponent = myEditor.getContentComponent();
|
||||||
Container scroll = SwingUtilities.getAncestorOfClass(JScrollPane.class, contentComponent);
|
Container scroll = SwingUtilities.getAncestorOfClass(JScrollPane.class, contentComponent);
|
||||||
@@ -302,13 +304,14 @@ public class ExOutputPanel extends JPanel {
|
|||||||
close(null);
|
close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close(final @Nullable KeyStroke key) {
|
private void close(final @Nullable KeyEvent e) {
|
||||||
ApplicationManager.getApplication().invokeLater(() -> {
|
ApplicationManager.getApplication().invokeLater(() -> {
|
||||||
deactivate(true);
|
deactivate(true);
|
||||||
|
|
||||||
final Project project = myEditor.getProject();
|
final Project project = myEditor.getProject();
|
||||||
|
|
||||||
if (project != null && key != null && key.getKeyChar() != '\n') {
|
if (project != null && e != null && e.getKeyChar() != '\n') {
|
||||||
|
final KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
|
||||||
final List<KeyStroke> keys = new ArrayList<>(1);
|
final List<KeyStroke> keys = new ArrayList<>(1);
|
||||||
keys.add(key);
|
keys.add(key);
|
||||||
if (LOG.isTrace()) {
|
if (LOG.isTrace()) {
|
||||||
@@ -317,9 +320,7 @@ public class ExOutputPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
KeyHandler.getInstance().getKeyStack().addKeys(keys);
|
KeyHandler.getInstance().getKeyStack().addKeys(keys);
|
||||||
ExecutionContext context = injector.getExecutionContextManager().getEditorExecutionContext(new IjVimEditor(myEditor));
|
ExecutionContext context = injector.getExecutionContextManager().getEditorExecutionContext(new IjVimEditor(myEditor));
|
||||||
injector.getApplication().runWriteAction(() -> { VimPlugin.getMacro().playbackKeys(new IjVimEditor(myEditor), context, 1);
|
VimPlugin.getMacro().playbackKeys(new IjVimEditor(myEditor), context, 1);
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -336,14 +337,40 @@ public class ExOutputPanel extends JPanel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void keyTyped(@NotNull KeyEvent e) {
|
public void keyTyped(@NotNull KeyEvent e) {
|
||||||
VimOutputPanel currentPanel = injector.getOutputPanel().getCurrentOutputPanel();
|
if (myExOutputPanel.myAtEnd) {
|
||||||
if (currentPanel == null) return;
|
myExOutputPanel.close(e);
|
||||||
|
}
|
||||||
int keyCode = e.getKeyCode();
|
else {
|
||||||
Character keyChar = e.getKeyChar();
|
switch (e.getKeyChar()) {
|
||||||
int modifiers = e.getModifiersEx();
|
case ' ':
|
||||||
KeyStroke keyStroke = (keyChar == KeyEvent.CHAR_UNDEFINED) ? KeyStroke.getKeyStroke(keyCode, modifiers) : KeyStroke.getKeyStroke(keyChar, modifiers);
|
myExOutputPanel.scrollPage();
|
||||||
currentPanel.handleKey(keyStroke);
|
break;
|
||||||
|
case 'd':
|
||||||
|
myExOutputPanel.scrollHalfPage();
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
case '\u001b':
|
||||||
|
myExOutputPanel.close();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
myExOutputPanel.handleEnter();
|
||||||
|
break;
|
||||||
|
case KeyEvent.CHAR_UNDEFINED: {
|
||||||
|
switch (e.getKeyCode()) {
|
||||||
|
case KeyEvent.VK_ENTER:
|
||||||
|
myExOutputPanel.handleEnter();
|
||||||
|
break;
|
||||||
|
case KeyEvent.VK_ESCAPE:
|
||||||
|
myExOutputPanel.close();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
myExOutputPanel.badKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
myExOutputPanel.badKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -150,7 +150,7 @@ internal class ReloadVimRc : DumbAwareAction() {
|
|||||||
override fun actionPerformed(e: AnActionEvent) {
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
val editor = e.getData(PlatformDataKeys.EDITOR) ?: return
|
val editor = e.getData(PlatformDataKeys.EDITOR) ?: return
|
||||||
injector.keyGroup.removeKeyMapping(MappingOwner.IdeaVim.InitScript)
|
injector.keyGroup.removeKeyMapping(MappingOwner.IdeaVim.InitScript)
|
||||||
Troubleshooter.getInstance().removeByType("old-action-notation-in-mappings")
|
Troubleshooter.instance.removeByType("old-action-notation-in-mappings")
|
||||||
|
|
||||||
// Reload the ideavimrc in the context of the current window, as though we had called `:source ~/.ideavimrc`
|
// Reload the ideavimrc in the context of the current window, as though we had called `:source ~/.ideavimrc`
|
||||||
executeIdeaVimRc(editor.vim)
|
executeIdeaVimRc(editor.vim)
|
||||||
|
@@ -20,6 +20,7 @@ import com.intellij.openapi.wm.WindowManager
|
|||||||
import com.intellij.openapi.wm.impl.status.EditorBasedWidget
|
import com.intellij.openapi.wm.impl.status.EditorBasedWidget
|
||||||
import com.intellij.util.Consumer
|
import com.intellij.util.Consumer
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
@@ -27,7 +28,6 @@ import com.maddyhome.idea.vim.common.EditorListener
|
|||||||
import com.maddyhome.idea.vim.helper.EngineStringHelper
|
import com.maddyhome.idea.vim.helper.EngineStringHelper
|
||||||
import com.maddyhome.idea.vim.helper.VimNlsSafe
|
import com.maddyhome.idea.vim.helper.VimNlsSafe
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.initInjector
|
|
||||||
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
|
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
@@ -72,11 +72,6 @@ internal object ShowCmdOptionChangeListener : GlobalOptionChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class ShowCmdStatusBarWidgetFactory : StatusBarWidgetFactory/*, LightEditCompatible*/ {
|
internal class ShowCmdStatusBarWidgetFactory : StatusBarWidgetFactory/*, LightEditCompatible*/ {
|
||||||
|
|
||||||
init {
|
|
||||||
initInjector()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getId() = ShowCmd.ID
|
override fun getId() = ShowCmd.ID
|
||||||
|
|
||||||
override fun getDisplayName(): String = ShowCmd.displayName
|
override fun getDisplayName(): String = ShowCmd.displayName
|
||||||
@@ -86,6 +81,7 @@ internal class ShowCmdStatusBarWidgetFactory : StatusBarWidgetFactory/*, LightEd
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isAvailable(project: Project): Boolean {
|
override fun isAvailable(project: Project): Boolean {
|
||||||
|
VimPlugin.getInstance()
|
||||||
return injector.globalOptions().showcmd
|
return injector.globalOptions().showcmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -267,7 +267,7 @@ private object ShortcutConflictsSettings : DumbAwareAction(MessageHelper.message
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal object JoinEap : DumbAwareAction()/*, LightEditCompatible*/ {
|
internal object JoinEap : DumbAwareAction()/*, LightEditCompatible*/ {
|
||||||
const val EAP_LINK = "https://plugins.jetbrains.com/plugins/eap/ideavim"
|
private const val EAP_LINK = "https://plugins.jetbrains.com/plugins/eap/ideavim"
|
||||||
|
|
||||||
fun eapActive() = EAP_LINK in UpdateSettings.getInstance().storedPluginHosts
|
fun eapActive() = EAP_LINK in UpdateSettings.getInstance().storedPluginHosts
|
||||||
|
|
||||||
|
263
src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
Normal file
263
src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.maddyhome.idea.vim.ui.ex
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.logger
|
||||||
|
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
|
||||||
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
|
import com.maddyhome.idea.vim.api.LocalOptionInitialisationScenario
|
||||||
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import java.awt.event.ActionEvent
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
import javax.swing.Action
|
||||||
|
import javax.swing.KeyStroke
|
||||||
|
import javax.swing.text.BadLocationException
|
||||||
|
import javax.swing.text.DefaultEditorKit
|
||||||
|
import javax.swing.text.Document
|
||||||
|
import javax.swing.text.TextAction
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal interface MultiStepAction : Action {
|
||||||
|
fun reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryUpAction : TextAction(ExEditorKit.HistoryUp) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(true, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryDownAction : TextAction(ExEditorKit.HistoryDown) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryUpFilterAction : TextAction(ExEditorKit.HistoryUpFilter) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryDownFilterAction : TextAction(ExEditorKit.HistoryDownFilter) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(false, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class CompleteEntryAction : TextAction(ExEditorKit.CompleteEntry) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
logger.debug("complete entry")
|
||||||
|
val stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
|
||||||
|
|
||||||
|
// We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
|
||||||
|
// We do this for a couple of reasons:
|
||||||
|
// * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
|
||||||
|
// write action
|
||||||
|
// * The key handler routines get the chance to clean up and reset state
|
||||||
|
val entry = ExEntryPanel.getInstance().entry
|
||||||
|
val keyHandler = KeyHandler.getInstance()
|
||||||
|
keyHandler.handleKey(entry.editor!!.vim, stroke, entry.context.vim, keyHandler.keyHandlerState)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<CompleteEntryAction>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class CancelEntryAction : TextAction(ExEditorKit.CancelEntry) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class EscapeCharAction : TextAction(ExEditorKit.EscapeChar) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.escape()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal abstract class DeleteCharAction internal constructor(name: String?) : TextAction(name) {
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deleteSelection(doc: Document, dot: Int, mark: Int): Boolean {
|
||||||
|
if (dot != mark) {
|
||||||
|
doc.remove(min(dot, mark), abs(dot - mark))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deleteNextChar(doc: Document, dot: Int): Boolean {
|
||||||
|
if (dot < doc.length) {
|
||||||
|
var delChars = 1
|
||||||
|
if (dot < doc.length - 1) {
|
||||||
|
val dotChars = doc.getText(dot, 2)
|
||||||
|
val c0 = dotChars[0]
|
||||||
|
val c1 = dotChars[1]
|
||||||
|
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
|
||||||
|
delChars = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc.remove(dot, delChars)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deletePrevChar(doc: Document, dot: Int): Boolean {
|
||||||
|
if (dot > 0) {
|
||||||
|
var delChars = 1
|
||||||
|
if (dot > 1) {
|
||||||
|
val dotChars = doc.getText(dot - 2, 2)
|
||||||
|
val c0 = dotChars[0]
|
||||||
|
val c1 = dotChars[1]
|
||||||
|
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
|
||||||
|
delChars = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc.remove(dot - delChars, delChars)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeleteNextCharAction : DeleteCharAction(DefaultEditorKit.deleteNextCharAction) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
try {
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val dot = caret.dot
|
||||||
|
val mark = caret.mark
|
||||||
|
if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeletePreviousCharAction : DeleteCharAction(DefaultEditorKit.deletePrevCharAction) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
try {
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val dot = caret.dot
|
||||||
|
val mark = caret.mark
|
||||||
|
if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
|
||||||
|
if (dot == 0 && doc.length == 0) {
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (bl: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeletePreviousWordAction : TextAction(DefaultEditorKit.deletePrevWordAction) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val project = target.editor!!.project
|
||||||
|
|
||||||
|
// Create a VimEditor instance on the Swing text field which we can pass to the search helpers. We need an editor
|
||||||
|
// rather than just working on a buffer because the search helpers need local options (specifically the local to
|
||||||
|
// buffer 'iskeyword'). We use the CMD_LINE scenario to initialise local options from the main editor. The options
|
||||||
|
// service will copy all local-to-buffer and local-to-window options, effectively cloning the options.
|
||||||
|
// TODO: Over time, we should migrate all ex actions to be based on VimEditor
|
||||||
|
// This will mean we always have an editor that has been initialised for options, etc. But also means that we can
|
||||||
|
// share the command line entry actions between IdeaVim implementations
|
||||||
|
val editor = TextComponentEditorImpl(project, target).vim
|
||||||
|
injector.optionGroup.initialiseLocalOptions(editor, target.editor!!.vim, LocalOptionInitialisationScenario.CMD_LINE)
|
||||||
|
|
||||||
|
val offset = injector.searchHelper.findNextWord(editor, caret.dot, -1, bigWord = false, spaceWords = false)
|
||||||
|
if (logger.isDebugEnabled) logger.debug("offset=$offset")
|
||||||
|
try {
|
||||||
|
val pos = caret.dot
|
||||||
|
doc.remove(offset, pos - offset)
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<DeletePreviousWordAction>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeleteToCursorAction : TextAction(ExEditorKit.DeleteToCursor) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
try {
|
||||||
|
doc.remove(0, caret.dot)
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class ToggleInsertReplaceAction : TextAction(ExEditorKit.ToggleInsertReplace) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
logger.debug("actionPerformed")
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.toggleInsertReplace()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
logger.debug("ToggleInsertReplaceAction()")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<ToggleInsertReplaceAction>()
|
||||||
|
}
|
||||||
|
}
|
@@ -34,7 +34,7 @@ public class ExDocument extends PlainDocument {
|
|||||||
void toggleInsertReplace() {
|
void toggleInsertReplace() {
|
||||||
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
||||||
if (commandLine != null) {
|
if (commandLine != null) {
|
||||||
((ExEntryPanel) commandLine).isReplaceMode = !((ExEntryPanel)commandLine).isReplaceMode;
|
commandLine.toggleReplaceMode();
|
||||||
}
|
}
|
||||||
overwrite = !overwrite;
|
overwrite = !overwrite;
|
||||||
}
|
}
|
||||||
|
@@ -7,19 +7,57 @@
|
|||||||
*/
|
*/
|
||||||
package com.maddyhome.idea.vim.ui.ex
|
package com.maddyhome.idea.vim.ui.ex
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.debug
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
|
import javax.swing.Action
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
import javax.swing.text.DefaultEditorKit
|
import javax.swing.text.DefaultEditorKit
|
||||||
import javax.swing.text.Document
|
import javax.swing.text.Document
|
||||||
|
import javax.swing.text.TextAction
|
||||||
|
|
||||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
internal object ExEditorKit : DefaultEditorKit() {
|
internal object ExEditorKit : DefaultEditorKit() {
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val CancelEntry: String = "cancel-entry"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val CompleteEntry: String = "complete-entry"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val EscapeChar: String = "escape"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val DeleteToCursor: String = "delete-to-cursor"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val ToggleInsertReplace: String = "toggle-insert"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryUp: String = "history-up"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryDown: String = "history-down"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryUpFilter: String = "history-up-filter"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryDownFilter: String = "history-down-filter"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val StartDigraph: String = "start-digraph"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val StartLiteral: String = "start-literal"
|
||||||
|
|
||||||
|
private val logger = logger<ExEditorKit>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the MIME type of the data that this
|
* Gets the MIME type of the data that this
|
||||||
* kit represents support for.
|
* kit represents support for.
|
||||||
@@ -31,6 +69,19 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
return "text/ideavim"
|
return "text/ideavim"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the set of commands that can be used
|
||||||
|
* on a text component that is using a model and
|
||||||
|
* view produced by this kit.
|
||||||
|
*
|
||||||
|
* @return the set of actions
|
||||||
|
*/
|
||||||
|
override fun getActions(): Array<Action> {
|
||||||
|
val res = TextAction.augmentList(super.getActions(), exActions)
|
||||||
|
logger.debug { "res.length=${res.size}" }
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an uninitialized text storage model
|
* Creates an uninitialized text storage model
|
||||||
* that is appropriate for this type of editor.
|
* that is appropriate for this type of editor.
|
||||||
@@ -41,29 +92,47 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
return ExDocument()
|
return ExDocument()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val exActions = arrayOf<Action>(
|
||||||
|
CancelEntryAction(),
|
||||||
|
CompleteEntryAction(),
|
||||||
|
EscapeCharAction(),
|
||||||
|
DeleteNextCharAction(),
|
||||||
|
DeletePreviousCharAction(),
|
||||||
|
DeletePreviousWordAction(),
|
||||||
|
DeleteToCursorAction(),
|
||||||
|
HistoryUpAction(),
|
||||||
|
HistoryDownAction(),
|
||||||
|
HistoryUpFilterAction(),
|
||||||
|
HistoryDownFilterAction(),
|
||||||
|
ToggleInsertReplaceAction(),
|
||||||
|
)
|
||||||
|
|
||||||
class DefaultExKeyHandler : DefaultKeyTypedAction() {
|
class DefaultExKeyHandler : DefaultKeyTypedAction() {
|
||||||
override fun actionPerformed(e: ActionEvent) {
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
val target = getTextComponent(e) as ExTextField
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
val currentAction = target.currentAction
|
||||||
val key = convert(e)
|
if (currentAction != null) {
|
||||||
if (key != null) {
|
currentAction.actionPerformed(e)
|
||||||
val c = key.keyChar
|
} else {
|
||||||
if (c.code > 0) {
|
val key = convert(e)
|
||||||
if (target.useHandleKeyFromEx) {
|
if (key != null) {
|
||||||
val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
|
val c = key.keyChar
|
||||||
val entry = panel.entry
|
if (c.code > 0) {
|
||||||
val editor = entry.editor
|
if (target.useHandleKeyFromEx) {
|
||||||
val keyHandler = KeyHandler.getInstance()
|
val entry = ExEntryPanel.getInstance().entry
|
||||||
keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
|
val editor = entry.editor
|
||||||
} else {
|
val keyHandler = KeyHandler.getInstance()
|
||||||
val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
|
keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
|
||||||
super.actionPerformed(event)
|
} else {
|
||||||
|
val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
|
||||||
|
super.actionPerformed(event)
|
||||||
|
}
|
||||||
|
target.saveLastEntry()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
super.actionPerformed(e)
|
||||||
target.saveLastEntry()
|
target.saveLastEntry()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
super.actionPerformed(e)
|
|
||||||
target.saveLastEntry()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,12 +25,10 @@ import com.maddyhome.idea.vim.VimPlugin;
|
|||||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLine;
|
import com.maddyhome.idea.vim.api.VimCommandLine;
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
|
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
|
||||||
import com.maddyhome.idea.vim.api.VimEditor;
|
|
||||||
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
|
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
|
||||||
import com.maddyhome.idea.vim.ex.ranges.LineRange;
|
import com.maddyhome.idea.vim.ex.ranges.LineRange;
|
||||||
import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
|
import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
|
||||||
import com.maddyhome.idea.vim.helper.UiHelper;
|
import com.maddyhome.idea.vim.helper.UiHelper;
|
||||||
import com.maddyhome.idea.vim.key.interceptors.VimInputInterceptor;
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret;
|
import com.maddyhome.idea.vim.newapi.IjVimCaret;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
import com.maddyhome.idea.vim.ui.ExPanelBorder;
|
import com.maddyhome.idea.vim.ui.ExPanelBorder;
|
||||||
@@ -38,8 +36,6 @@ import com.maddyhome.idea.vim.vimscript.model.commands.Command;
|
|||||||
import com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand;
|
import com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand;
|
||||||
import com.maddyhome.idea.vim.vimscript.model.commands.SubstituteCommand;
|
import com.maddyhome.idea.vim.vimscript.model.commands.SubstituteCommand;
|
||||||
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser;
|
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser;
|
||||||
import kotlin.Unit;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -63,13 +59,9 @@ import static com.maddyhome.idea.vim.group.KeyGroup.toShortcutSet;
|
|||||||
public class ExEntryPanel extends JPanel implements VimCommandLine {
|
public class ExEntryPanel extends JPanel implements VimCommandLine {
|
||||||
public static ExEntryPanel instance;
|
public static ExEntryPanel instance;
|
||||||
public static ExEntryPanel instanceWithoutShortcuts;
|
public static ExEntryPanel instanceWithoutShortcuts;
|
||||||
public boolean isReplaceMode = false;
|
private boolean isReplaceMode = false;
|
||||||
private WeakReference<Editor> weakEditor = null;
|
private WeakReference<Editor> weakEditor = null;
|
||||||
|
|
||||||
private VimInputInterceptor myInputInterceptor = null;
|
|
||||||
public Function1<String, Unit> inputProcessing = null;
|
|
||||||
public Character finishOn = null;
|
|
||||||
|
|
||||||
private ExEntryPanel(boolean enableShortcuts) {
|
private ExEntryPanel(boolean enableShortcuts) {
|
||||||
label = new JLabel(" ");
|
label = new JLabel(" ");
|
||||||
entry = new ExTextField();
|
entry = new ExTextField();
|
||||||
@@ -87,13 +79,15 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
layout.setConstraints(entry, gbc);
|
layout.setConstraints(entry, gbc);
|
||||||
add(entry);
|
add(entry);
|
||||||
|
|
||||||
// This does not need to be unregistered, it's registered as a custom UI property on this
|
if (enableShortcuts) {
|
||||||
EventFacade.getInstance().registerCustomShortcutSet(
|
// This does not need to be unregistered, it's registered as a custom UI property on this
|
||||||
VimShortcutKeyAction.getInstance(),
|
EventFacade.getInstance().registerCustomShortcutSet(
|
||||||
toShortcutSet(((VimKeyGroupBase) injector.getKeyGroup()).getRequiredShortcutKeys()),
|
VimShortcutKeyAction.getInstance(),
|
||||||
entry
|
toShortcutSet(((VimKeyGroupBase) injector.getKeyGroup()).getRequiredShortcutKeys()),
|
||||||
);
|
entry
|
||||||
new ExShortcutKeyAction(this).registerCustomShortcutSet();
|
);
|
||||||
|
new ExShortcutKeyAction(this).registerCustomShortcutSet();
|
||||||
|
}
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -133,18 +127,10 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Editor getIjEditor() {
|
public @Nullable Editor getEditor() {
|
||||||
return weakEditor != null ? weakEditor.get() : null;
|
return weakEditor != null ? weakEditor.get() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull VimEditor getEditor() {
|
|
||||||
Editor editor = getIjEditor();
|
|
||||||
if (editor == null) {
|
|
||||||
throw new RuntimeException("Editor was disposed for active command line");
|
|
||||||
}
|
|
||||||
return new IjVimEditor(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEditor(@Nullable Editor editor) {
|
public void setEditor(@Nullable Editor editor) {
|
||||||
if (editor == null) {
|
if (editor == null) {
|
||||||
weakEditor = null;
|
weakEditor = null;
|
||||||
@@ -153,14 +139,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link ExEntryPanel#activate(Editor, DataContext, String, String)}
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
public void activate(@NotNull Editor editor, DataContext context, @NotNull String label, String initText, int count) {
|
|
||||||
activate(editor, context, label, initText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns on the ex entry field for the given editor
|
* Turns on the ex entry field for the given editor
|
||||||
*
|
*
|
||||||
@@ -271,9 +249,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
|
|
||||||
// We have this in the end, because `entry.deactivate()` communicates with active panel during deactivation
|
// We have this in the end, because `entry.deactivate()` communicates with active panel during deactivation
|
||||||
active = false;
|
active = false;
|
||||||
finishOn = null;
|
|
||||||
myInputInterceptor = null;
|
|
||||||
inputProcessing = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset() {
|
private void reset() {
|
||||||
@@ -298,7 +273,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
@Override
|
@Override
|
||||||
protected void textChanged(@NotNull DocumentEvent e) {
|
protected void textChanged(@NotNull DocumentEvent e) {
|
||||||
String text = entry.getText();
|
String text = entry.getText();
|
||||||
Font newFont = UiHelper.selectEditorFont(getIjEditor(), text);
|
Font newFont = UiHelper.selectEditorFont(getEditor(), text);
|
||||||
if (newFont != entry.getFont()) {
|
if (newFont != entry.getFont()) {
|
||||||
entry.setFont(newFont);
|
entry.setFont(newFont);
|
||||||
}
|
}
|
||||||
@@ -351,7 +326,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
// coerced to at least 1.
|
// coerced to at least 1.
|
||||||
int count1 = KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder().getAggregatedUncommittedCount();
|
int count1 = KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder().getAggregatedUncommittedCount();
|
||||||
|
|
||||||
if ((labelText.equals("/") || labelText.equals("?") || searchCommand) && !injector.getMacro().isExecutingMacro()) {
|
if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
|
||||||
final boolean forwards = !labelText.equals("?"); // :s, :g, :v are treated as forwards
|
final boolean forwards = !labelText.equals("?"); // :s, :g, :v are treated as forwards
|
||||||
int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
||||||
final String pattern = searchText.substring(0, pattenEnd);
|
final String pattern = searchText.substring(0, pattenEnd);
|
||||||
@@ -405,7 +380,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toggleReplaceMode() {
|
public void toggleReplaceMode() {
|
||||||
entry.toggleInsertReplace();
|
isReplaceMode = !isReplaceMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -417,14 +392,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use getVisibleText()
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
public @NotNull String getText() {
|
|
||||||
return entry.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull String getVisibleText() {
|
public @NotNull String getVisibleText() {
|
||||||
return entry.getText();
|
return entry.getText();
|
||||||
@@ -442,10 +409,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
@Override
|
@Override
|
||||||
public void handleKey(@NotNull KeyStroke stroke) {
|
public void handleKey(@NotNull KeyStroke stroke) {
|
||||||
entry.handleKey(stroke);
|
entry.handleKey(stroke);
|
||||||
if (finishOn != null && stroke.getKeyChar() == finishOn && inputProcessing != null) {
|
|
||||||
inputProcessing.invoke(getActualText());
|
|
||||||
close(true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called automatically when the LAF is changed and the component is visible, and manually by the LAF listener handler
|
// Called automatically when the LAF is changed and the component is visible, and manually by the LAF listener handler
|
||||||
@@ -483,8 +446,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setFontForElements() {
|
private void setFontForElements() {
|
||||||
label.setFont(UiHelper.selectEditorFont(getIjEditor(), label.getText()));
|
label.setFont(UiHelper.selectEditorFont(getEditor(), label.getText()));
|
||||||
entry.setFont(UiHelper.selectEditorFont(getIjEditor(), getVisibleText()));
|
entry.setFont(UiHelper.selectEditorFont(getEditor(), getVisibleText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionPanel() {
|
private void positionPanel() {
|
||||||
@@ -538,11 +501,10 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setText(@NotNull String string, boolean updateLastEntry) {
|
public void setText(@NotNull String string) {
|
||||||
// It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
|
// It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
|
||||||
int offset = getCaret().getOffset();
|
int offset = getCaret().getOffset();
|
||||||
entry.updateText(string);
|
entry.updateText(string);
|
||||||
if (updateLastEntry) entry.saveLastEntry();
|
|
||||||
getCaret().setOffset(Math.min(offset, getVisibleText().length()));
|
getCaret().setOffset(Math.min(offset, getVisibleText().length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,53 +535,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
IdeFocusManager.findInstance().requestFocus(entry, true);
|
IdeFocusManager.findInstance().requestFocus(entry, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public VimInputInterceptor<?> getInputInterceptor() {
|
|
||||||
return myInputInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertText(int offset, @NotNull String string) {
|
|
||||||
VimCommandLine.super.insertText(offset, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInputInterceptor(@Nullable VimInputInterceptor<?> vimInputInterceptor) {
|
|
||||||
myInputInterceptor = vimInputInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Function1<String, Unit> getInputProcessing() {
|
|
||||||
return inputProcessing;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Character getFinishOn() {
|
|
||||||
return finishOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHistIndex() {
|
|
||||||
return entry.histIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHistIndex(int i) {
|
|
||||||
entry.histIndex = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getLastEntry() {
|
|
||||||
return entry.lastEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLastEntry(@NotNull String s) {
|
|
||||||
entry.lastEntry = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LafListener implements LafManagerListener {
|
public static class LafListener implements LafManagerListener {
|
||||||
@Override
|
@Override
|
||||||
public void lookAndFeelChanged(@NotNull LafManager source) {
|
public void lookAndFeelChanged(@NotNull LafManager source) {
|
||||||
|
@@ -11,35 +11,27 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import com.maddyhome.idea.vim.action.change.Extension
|
import com.maddyhome.idea.vim.action.change.Extension
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLine
|
import com.maddyhome.idea.vim.api.VimCommandLine
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret
|
import com.maddyhome.idea.vim.api.VimCommandLineService
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLineServiceBase
|
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.VimModalInput
|
|
||||||
import com.maddyhome.idea.vim.api.VimModalInputBase
|
|
||||||
import com.maddyhome.idea.vim.api.VimModalInputService
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.helper.TestInputModel
|
import com.maddyhome.idea.vim.helper.TestInputModel
|
||||||
import com.maddyhome.idea.vim.helper.inRepeatMode
|
|
||||||
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
|
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
|
||||||
import com.maddyhome.idea.vim.key.interceptors.VimInputInterceptor
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import com.maddyhome.idea.vim.state.mode.ReturnableFromCmd
|
|
||||||
import com.maddyhome.idea.vim.ui.ModalEntry
|
import com.maddyhome.idea.vim.ui.ModalEntry
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
class ExEntryPanelService : VimCommandLineServiceBase(), VimModalInputService {
|
class ExEntryPanelService : VimCommandLineService {
|
||||||
override fun getActiveCommandLine(): VimCommandLine? {
|
override fun getActiveCommandLine(): VimCommandLine? {
|
||||||
val instance = ExEntryPanel.instance ?: return null
|
val instance = ExEntryPanel.instance ?: ExEntryPanel.instanceWithoutShortcuts ?: return null
|
||||||
return if (instance.isActive) instance else null
|
return if (instance.isActive) instance else null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Please use readInputAndProcess")
|
override fun inputString(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?): String? {
|
||||||
fun inputString(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?): String? {
|
|
||||||
val editor = vimEditor.ij
|
val editor = vimEditor.ij
|
||||||
if (vimEditor.inRepeatMode) {
|
if (vimEditor.vimStateMachine.isDotRepeatInProgress) {
|
||||||
val input = Extension.consumeString()
|
val input = Extension.consumeString()
|
||||||
return input ?: error("Not enough strings saved: ${Extension.lastExtensionHandler}")
|
return input ?: error("Not enough strings saved: ${Extension.lastExtensionHandler}")
|
||||||
}
|
}
|
||||||
@@ -66,7 +58,7 @@ class ExEntryPanelService : VimCommandLineServiceBase(), VimModalInputService {
|
|||||||
} else {
|
} else {
|
||||||
var text: String? = null
|
var text: String? = null
|
||||||
// XXX: The Ex entry panel is used only for UI here, its logic might be inappropriate for input()
|
// XXX: The Ex entry panel is used only for UI here, its logic might be inappropriate for input()
|
||||||
val commandLine = injector.commandLine.createSearchPrompt(vimEditor, context, prompt.ifEmpty { " " }, "")
|
val commandLine = injector.commandLine.create(vimEditor, context, prompt.ifEmpty { " " }, "")
|
||||||
ModalEntry.activate(editor.vim) { key: KeyStroke ->
|
ModalEntry.activate(editor.vim) { key: KeyStroke ->
|
||||||
return@activate when {
|
return@activate when {
|
||||||
key.isCloseKeyStroke() -> {
|
key.isCloseKeyStroke() -> {
|
||||||
@@ -97,40 +89,7 @@ class ExEntryPanelService : VimCommandLineServiceBase(), VimModalInputService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readInputAndProcess(
|
override fun create(editor: VimEditor, context: ExecutionContext, label: String, initText: String): VimCommandLine {
|
||||||
editor: VimEditor,
|
|
||||||
context: ExecutionContext,
|
|
||||||
prompt: String,
|
|
||||||
finishOn: Char?,
|
|
||||||
processing: (String) -> Unit,
|
|
||||||
) {
|
|
||||||
val currentMode = editor.mode
|
|
||||||
check(currentMode is ReturnableFromCmd) {
|
|
||||||
"Cannot enable cmd mode from current mode $currentMode"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the Visual selection marks are up to date before we use them.
|
|
||||||
injector.markService.setVisualSelectionMarks(editor)
|
|
||||||
|
|
||||||
// Note that we should remove selection and reset caret offset before we switch back to Normal mode and then enter
|
|
||||||
// Command-line mode. However, some IdeaVim commands can handle multiple carets, including multiple carets with
|
|
||||||
// selection (which might or might not be a block selection). Unfortunately, because we're just entering
|
|
||||||
// Command-line mode, we don't know which command is going to be entered, so we can't remove selection here.
|
|
||||||
// Therefore, we switch to Normal and then Command-line even though we might still have a Visual selection...
|
|
||||||
// On the plus side, it means we still show selection while editing the command line, which Vim also does
|
|
||||||
// (Normal then Command-line is not strictly necessary, but done for completeness and autocmd)
|
|
||||||
// Caret selection is finally handled in Command.execute
|
|
||||||
editor.mode = Mode.NORMAL()
|
|
||||||
editor.mode = Mode.CMD_LINE(currentMode)
|
|
||||||
|
|
||||||
val panel = ExEntryPanel.getInstance()
|
|
||||||
panel as ExEntryPanel
|
|
||||||
panel.finishOn = finishOn
|
|
||||||
panel.inputProcessing = processing
|
|
||||||
panel.activate(editor.ij, context.ij, prompt, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createPanel(editor: VimEditor, context: ExecutionContext, label: String, initText: String): VimCommandLine {
|
|
||||||
val panel = ExEntryPanel.getInstance()
|
val panel = ExEntryPanel.getInstance()
|
||||||
panel.activate(editor.ij, context.ij, label, initText)
|
panel.activate(editor.ij, context.ij, label, initText)
|
||||||
return panel
|
return panel
|
||||||
@@ -145,31 +104,4 @@ class ExEntryPanelService : VimCommandLineServiceBase(), VimModalInputService {
|
|||||||
override fun fullReset() {
|
override fun fullReset() {
|
||||||
ExEntryPanel.fullReset()
|
ExEntryPanel.fullReset()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCurrentModalInput(): VimModalInput? {
|
|
||||||
return ExEntryPanel.getInstanceWithoutShortcuts()?.takeIf { it.isActive && it.inputInterceptor != null }?.let { WrappedAsModalInputExEntryPanel(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun create(editor: VimEditor, context: ExecutionContext, label: String, inputInterceptor: VimInputInterceptor<*>): VimModalInput {
|
|
||||||
val panel = ExEntryPanel.getInstanceWithoutShortcuts()
|
|
||||||
panel.inputInterceptor = inputInterceptor
|
|
||||||
panel.activate(editor.ij, context.ij, label, "")
|
|
||||||
return WrappedAsModalInputExEntryPanel(panel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class WrappedAsModalInputExEntryPanel(internal val exEntryPanel: ExEntryPanel) : VimModalInputBase() {
|
|
||||||
override var inputInterceptor: VimInputInterceptor<*>
|
|
||||||
get() = exEntryPanel.inputInterceptor!!
|
|
||||||
set(value) { exEntryPanel.inputInterceptor = value }
|
|
||||||
override val caret: VimCommandLineCaret = exEntryPanel.caret
|
|
||||||
override val label: String = exEntryPanel.label
|
|
||||||
|
|
||||||
override fun deactivate(refocusOwningEditor: Boolean, resetCaret: Boolean) {
|
|
||||||
exEntryPanel.deactivate(refocusOwningEditor, resetCaret)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun focus() {
|
|
||||||
exEntryPanel.focus()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -21,6 +21,57 @@ internal object ExKeyBindings {
|
|||||||
|
|
||||||
val bindings: Array<KeyBinding> by lazy {
|
val bindings: Array<KeyBinding> by lazy {
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
// Escape will cancel a pending insert digraph/register before cancelling
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ExEditorKit.EscapeChar),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.EscapeChar),
|
||||||
|
|
||||||
|
// Cancel entry, ignoring any pending actions such as digraph/registry entry
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CancelEntry),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ExEditorKit.CompleteEntry),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x02.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), DefaultEditorKit.beginLineAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x05.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), DefaultEditorKit.endLineAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x08.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DefaultEditorKit.deleteNextCharAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevWordAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.DeleteToCursor),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ExEditorKit.HistoryUpFilter),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ExEditorKit.HistoryDownFilter),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryDown),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ExEditorKit.HistoryDown),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryDown),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), ExEditorKit.ToggleInsertReplace),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.previousWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.previousWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), DefaultEditorKit.forwardAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.nextWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.nextWordAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartDigraph),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
|
||||||
|
|
||||||
// These appear to be non-Vim shortcuts
|
// These appear to be non-Vim shortcuts
|
||||||
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
|
||||||
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
|
||||||
|
@@ -59,45 +59,9 @@ internal class ExShortcutKeyAction(private val exEntryPanel: ExEntryPanel) : Dum
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun registerCustomShortcutSet() {
|
fun registerCustomShortcutSet() {
|
||||||
val shortcuts = listOf(
|
val shortcuts = ExKeyBindings.bindings.map {
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
KeyboardShortcut(it.key, null)
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK),
|
}.toTypedArray()
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
)
|
|
||||||
.map { KeyboardShortcut(it, null) }
|
|
||||||
.toTypedArray()
|
|
||||||
|
|
||||||
registerCustomShortcutSet({ shortcuts }, exEntryPanel)
|
registerCustomShortcutSet({ shortcuts }, exEntryPanel)
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ import com.maddyhome.idea.vim.api.VimCommandLineCaret;
|
|||||||
import com.maddyhome.idea.vim.helper.UiHelper;
|
import com.maddyhome.idea.vim.helper.UiHelper;
|
||||||
import com.maddyhome.idea.vim.history.HistoryConstants;
|
import com.maddyhome.idea.vim.history.HistoryConstants;
|
||||||
import com.maddyhome.idea.vim.history.HistoryEntry;
|
import com.maddyhome.idea.vim.history.HistoryEntry;
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorAttributes;
|
import com.maddyhome.idea.vim.options.helpers.GuiCursorAttributes;
|
||||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorMode;
|
import com.maddyhome.idea.vim.options.helpers.GuiCursorMode;
|
||||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper;
|
import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper;
|
||||||
@@ -65,6 +66,9 @@ public class ExTextField extends JTextField {
|
|||||||
// If we're in the middle of an action (e.g. entering a register to paste, or inserting a digraph), cancel it if
|
// If we're in the middle of an action (e.g. entering a register to paste, or inserting a digraph), cancel it if
|
||||||
// the mouse is clicked anywhere. Vim's behavior is to use the mouse click as an event, which can lead to
|
// the mouse is clicked anywhere. Vim's behavior is to use the mouse click as an event, which can lead to
|
||||||
// something like : !%!C, which I don't believe is documented, or useful
|
// something like : !%!C, which I don't believe is documented, or useful
|
||||||
|
if (currentAction != null) {
|
||||||
|
clearCurrentAction();
|
||||||
|
}
|
||||||
super.mouseClicked(e);
|
super.mouseClicked(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -207,7 +211,7 @@ public class ExTextField extends JTextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Editor getEditor() {
|
public @Nullable Editor getEditor() {
|
||||||
return ExEntryPanel.getInstance().getIjEditor();
|
return ExEntryPanel.getInstance().getEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataContext getContext() {
|
public DataContext getContext() {
|
||||||
@@ -235,15 +239,20 @@ public class ExTextField extends JTextField {
|
|||||||
// This gets called for ALL events, before the IDE starts to process key events for the action system. We can add a
|
// This gets called for ALL events, before the IDE starts to process key events for the action system. We can add a
|
||||||
// dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField,
|
// dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField,
|
||||||
// dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed.
|
// dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed.
|
||||||
KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :
|
if (currentAction != null) {
|
||||||
(stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED),
|
currentAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, String.valueOf(c), modifiers));
|
||||||
(new Date()).getTime(), modifiers, keyCode, c);
|
}
|
||||||
|
else {
|
||||||
|
KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :
|
||||||
|
(stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED),
|
||||||
|
(new Date()).getTime(), modifiers, keyCode, c);
|
||||||
|
|
||||||
useHandleKeyFromEx = false;
|
useHandleKeyFromEx = false;
|
||||||
try {
|
try {
|
||||||
super.processKeyEvent(event);
|
super.processKeyEvent(event);
|
||||||
} finally {
|
}finally {
|
||||||
useHandleKeyFromEx = true;
|
useHandleKeyFromEx = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +278,12 @@ public class ExTextField extends JTextField {
|
|||||||
* Cancels current action, if there is one. If not, cancels entry.
|
* Cancels current action, if there is one. If not, cancels entry.
|
||||||
*/
|
*/
|
||||||
void escape() {
|
void escape() {
|
||||||
cancel();
|
if (currentAction != null) {
|
||||||
|
clearCurrentAction();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,17 +291,26 @@ public class ExTextField extends JTextField {
|
|||||||
*/
|
*/
|
||||||
void cancel() {
|
void cancel() {
|
||||||
clearCurrentAction();
|
clearCurrentAction();
|
||||||
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
Editor editor = ExEntryPanel.instance.getEditor();
|
||||||
if (commandLine != null) {
|
if (editor != null) {
|
||||||
commandLine.close(true, true);
|
VimPlugin.getProcess().cancelExEntry(new IjVimEditor(editor), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearCurrentAction() {
|
public void clearCurrentAction() {
|
||||||
|
if (currentAction != null) {
|
||||||
|
currentAction.reset();
|
||||||
|
}
|
||||||
|
currentAction = null;
|
||||||
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
||||||
if (commandLine != null) commandLine.clearPromptCharacter();
|
if (commandLine != null) commandLine.clearPromptCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Action getCurrentAction() {
|
||||||
|
return currentAction;
|
||||||
|
}
|
||||||
|
|
||||||
private void setInsertMode() {
|
private void setInsertMode() {
|
||||||
ExDocument doc = (ExDocument)getDocument();
|
ExDocument doc = (ExDocument)getDocument();
|
||||||
if (doc.isOverwrite()) {
|
if (doc.isOverwrite()) {
|
||||||
@@ -518,9 +541,10 @@ public class ExTextField extends JTextField {
|
|||||||
|
|
||||||
private DataContext context;
|
private DataContext context;
|
||||||
private final CommandLineCaret caret;
|
private final CommandLineCaret caret;
|
||||||
String lastEntry;
|
private String lastEntry;
|
||||||
private List<HistoryEntry> history;
|
private List<HistoryEntry> history;
|
||||||
int histIndex = 0;
|
private int histIndex = 0;
|
||||||
|
private @Nullable MultiStepAction currentAction;
|
||||||
int currentActionPromptCharacterOffset = -1;
|
int currentActionPromptCharacterOffset = -1;
|
||||||
|
|
||||||
private static final Logger logger = Logger.getInstance(ExTextField.class.getName());
|
private static final Logger logger = Logger.getInstance(ExTextField.class.getName());
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2024 The IdeaVim authors
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE.txt file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.maddyhome.idea.vim.ui.ex
|
|
||||||
|
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanel
|
|
||||||
import com.maddyhome.idea.vim.api.VimOutputPanelServiceBase
|
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel
|
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
|
|
||||||
class IjOutputPanelService : VimOutputPanelServiceBase() {
|
|
||||||
private var activeOutputPanel: VimOutputPanel? = null
|
|
||||||
|
|
||||||
override fun getCurrentOutputPanel(): VimOutputPanel? {
|
|
||||||
return activeOutputPanel?.takeIf {
|
|
||||||
(it as ExOutputModel)
|
|
||||||
it.isActive && it.editor != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun create(editor: VimEditor, context: ExecutionContext): VimOutputPanel {
|
|
||||||
val panel = ExOutputModel(WeakReference(editor.ij))
|
|
||||||
activeOutputPanel = panel
|
|
||||||
return panel
|
|
||||||
}
|
|
||||||
}
|
|
@@ -352,8 +352,7 @@ class ModeWidgetPopup : AnAction() {
|
|||||||
|
|
||||||
enum class ModeWidgetTheme(private var value: String) {
|
enum class ModeWidgetTheme(private var value: String) {
|
||||||
TERM("Term"),
|
TERM("Term"),
|
||||||
COLORLESS("Colorless"),
|
COLORLESS("Colorless");
|
||||||
DRACULA("Dracula");
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return value
|
return value
|
||||||
|
@@ -31,16 +31,6 @@ fun getModeBackground(mode: Mode?): Color {
|
|||||||
is Mode.OP_PENDING, null -> UIUtil.getPanelBackground()
|
is Mode.OP_PENDING, null -> UIUtil.getPanelBackground()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModeWidgetTheme.DRACULA -> {
|
|
||||||
return when (mode) {
|
|
||||||
Mode.INSERT -> Color.decode("#50FA7B")
|
|
||||||
Mode.REPLACE -> Color.decode("#FF5555")
|
|
||||||
is Mode.NORMAL -> Color.decode("#BD93F9")
|
|
||||||
is Mode.CMD_LINE -> Color.decode("#FFB86C")
|
|
||||||
is Mode.VISUAL, is Mode.SELECT -> Color.decode("#F1FA8C")
|
|
||||||
is Mode.OP_PENDING, null -> UIUtil.getPanelBackground()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ModeWidgetTheme.COLORLESS -> {
|
ModeWidgetTheme.COLORLESS -> {
|
||||||
return UIUtil.getPanelBackground()
|
return UIUtil.getPanelBackground()
|
||||||
}
|
}
|
||||||
@@ -93,7 +83,6 @@ fun getModeForeground(mode: Mode?): Color {
|
|||||||
val theme = ModeWidgetTheme.parseString(themeString) ?: ModeWidgetTheme.getDefaultTheme()
|
val theme = ModeWidgetTheme.parseString(themeString) ?: ModeWidgetTheme.getDefaultTheme()
|
||||||
return when (theme) {
|
return when (theme) {
|
||||||
ModeWidgetTheme.TERM -> if (isLight) Color.WHITE else Color.BLACK
|
ModeWidgetTheme.TERM -> if (isLight) Color.WHITE else Color.BLACK
|
||||||
ModeWidgetTheme.DRACULA -> Color.BLACK
|
|
||||||
ModeWidgetTheme.COLORLESS -> UIUtil.getLabelForeground()
|
ModeWidgetTheme.COLORLESS -> UIUtil.getLabelForeground()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -8,20 +8,114 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.vimscript
|
package com.maddyhome.idea.vim.vimscript
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.openapi.components.Service
|
import com.intellij.openapi.components.Service
|
||||||
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.VimScriptExecutorBase
|
import com.maddyhome.idea.vim.api.VimScriptExecutorBase
|
||||||
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.ex.ExException
|
||||||
|
import com.maddyhome.idea.vim.ex.FinishException
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
|
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
|
||||||
|
import com.maddyhome.idea.vim.history.HistoryConstants
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.VimLContext
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.commands.Command
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.commands.RepeatCommand
|
||||||
|
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
internal class Executor : VimScriptExecutorBase() {
|
internal class Executor : VimScriptExecutorBase() {
|
||||||
override fun enableDelayedExtensions() {
|
private val logger = logger<Executor>()
|
||||||
VimExtensionRegistrar.enableDelayedExtensions()
|
override var executingVimscript = false
|
||||||
|
override var executingIdeaVimRcConfiguration = false
|
||||||
|
|
||||||
|
@Throws(ExException::class)
|
||||||
|
override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
|
||||||
|
try {
|
||||||
|
injector.vimscriptExecutor.executingVimscript = true
|
||||||
|
var finalResult: ExecutionResult = ExecutionResult.Success
|
||||||
|
|
||||||
|
val myScript = VimscriptParser.parse(script)
|
||||||
|
myScript.units.forEach { it.vimContext = vimContext ?: myScript }
|
||||||
|
|
||||||
|
for (unit in myScript.units) {
|
||||||
|
try {
|
||||||
|
val result = unit.execute(editor, context)
|
||||||
|
if (result is ExecutionResult.Error) {
|
||||||
|
finalResult = ExecutionResult.Error
|
||||||
|
if (indicateErrors) {
|
||||||
|
VimPlugin.indicateError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: ExException) {
|
||||||
|
if (e is FinishException) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
finalResult = ExecutionResult.Error
|
||||||
|
if (indicateErrors) {
|
||||||
|
VimPlugin.showMessage(e.message)
|
||||||
|
VimPlugin.indicateError()
|
||||||
|
} else {
|
||||||
|
logger.warn("Failed while executing $unit. " + e.message)
|
||||||
|
}
|
||||||
|
} catch (e: NotImplementedError) {
|
||||||
|
if (indicateErrors) {
|
||||||
|
VimPlugin.showMessage("Not implemented yet :(")
|
||||||
|
VimPlugin.indicateError()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn(e)
|
||||||
|
if (injector.application.isUnitTest()) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipHistory) {
|
||||||
|
VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
|
||||||
|
if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
|
||||||
|
VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalResult
|
||||||
|
} finally {
|
||||||
|
injector.vimscriptExecutor.executingVimscript = false
|
||||||
|
|
||||||
|
// Initialize any extensions that were enabled during execution of this vimscript
|
||||||
|
// See the doc of this function for details
|
||||||
|
VimExtensionRegistrar.enableDelayedExtensions()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ensureFileIsSaved(file: File) {
|
override fun executeFile(file: File, editor: VimEditor, fileIsIdeaVimRcConfig: Boolean, indicateErrors: Boolean) {
|
||||||
|
val context = DataContext.EMPTY_CONTEXT.vim
|
||||||
|
try {
|
||||||
|
if (fileIsIdeaVimRcConfig) {
|
||||||
|
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
|
||||||
|
}
|
||||||
|
ensureFileIsSaved(file)
|
||||||
|
execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
|
||||||
|
} catch (ignored: IOException) {
|
||||||
|
LOG.error(ignored)
|
||||||
|
} finally {
|
||||||
|
if (fileIsIdeaVimRcConfig) {
|
||||||
|
injector.vimrcFileState.saveFileState(file.absolutePath)
|
||||||
|
injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureFileIsSaved(file: File) {
|
||||||
val documentManager = FileDocumentManager.getInstance()
|
val documentManager = FileDocumentManager.getInstance()
|
||||||
|
|
||||||
VirtualFileManager.getInstance().findFileByNioPath(file.toPath())
|
VirtualFileManager.getInstance().findFileByNioPath(file.toPath())
|
||||||
@@ -29,4 +123,16 @@ internal class Executor : VimScriptExecutorBase() {
|
|||||||
?.takeIf(documentManager::isDocumentUnsaved)
|
?.takeIf(documentManager::isDocumentUnsaved)
|
||||||
?.let(documentManager::saveDocumentAsIs)
|
?.let(documentManager::saveDocumentAsIs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(ExException::class)
|
||||||
|
override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
|
||||||
|
val reg = VimPlugin.getRegister().getRegister(':') ?: return false
|
||||||
|
val text = reg.text ?: return false
|
||||||
|
execute(text, editor, context, skipHistory = false, indicateErrors = true, CommandLineVimLContext)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val LOG = logger<Executor>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,9 +45,7 @@ internal data class ActionListCommand(val range: Range, val argument: String) :
|
|||||||
.filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } }
|
.filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } }
|
||||||
.joinToString(lineSeparator)
|
.joinToString(lineSeparator)
|
||||||
|
|
||||||
val outputPanel = injector.outputPanel.getOrCreate(editor, context)
|
ExOutputModel.getInstance(editor.ij).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
|
||||||
outputPanel.addText(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
|
|
||||||
outputPanel.show()
|
|
||||||
return ExecutionResult.Success
|
return ExecutionResult.Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,8 @@ import com.intellij.vim.annotations.ExCommand
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||||
import com.maddyhome.idea.vim.ex.ranges.Range
|
import com.maddyhome.idea.vim.ex.ranges.Range
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper
|
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||||
import com.maddyhome.idea.vim.helper.vimLine
|
import com.maddyhome.idea.vim.helper.vimLine
|
||||||
@@ -45,9 +45,7 @@ internal data class BufferListCommand(val range: Range, val argument: String) :
|
|||||||
val filter = pruneUnsupportedFilters(arg)
|
val filter = pruneUnsupportedFilters(arg)
|
||||||
val bufferList = getBufferList(context, filter)
|
val bufferList = getBufferList(context, filter)
|
||||||
|
|
||||||
val outputPanel = injector.outputPanel.getOrCreate(editor, context)
|
ExOutputModel.getInstance(editor.ij).output(bufferList.joinToString(separator = "\n"))
|
||||||
outputPanel.addText(bufferList.joinToString(separator = "\n"))
|
|
||||||
outputPanel.show()
|
|
||||||
|
|
||||||
return ExecutionResult.Success
|
return ExecutionResult.Success
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@ import com.intellij.vim.annotations.ExCommand
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.ex.ExException
|
import com.maddyhome.idea.vim.ex.ExException
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel
|
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||||
@@ -40,7 +39,7 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
argument.forEach { c ->
|
argument.forEach { c ->
|
||||||
when {
|
when {
|
||||||
!inBackslash && c == '!' -> {
|
!inBackslash && c == '!' -> {
|
||||||
val last = lastCommand
|
val last = VimPlugin.getProcess().lastCommand
|
||||||
if (last.isNullOrEmpty()) {
|
if (last.isNullOrEmpty()) {
|
||||||
VimPlugin.showMessage(MessageHelper.message("e_noprev"))
|
VimPlugin.showMessage(MessageHelper.message("e_noprev"))
|
||||||
return ExecutionResult.Error
|
return ExecutionResult.Error
|
||||||
@@ -75,11 +74,8 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
if (range.size() == 0) {
|
if (range.size() == 0) {
|
||||||
// Show command output in a window
|
// Show command output in a window
|
||||||
VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
|
VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
|
||||||
val outputPanel = injector.outputPanel.getOrCreate(editor, context)
|
ExOutputModel.getInstance(editor.ij).output(it)
|
||||||
outputPanel.addText(it)
|
|
||||||
outputPanel.show()
|
|
||||||
}
|
}
|
||||||
lastCommand = command
|
|
||||||
ExecutionResult.Success
|
ExecutionResult.Success
|
||||||
} else {
|
} else {
|
||||||
// Filter
|
// Filter
|
||||||
@@ -96,7 +92,6 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastCommand = command
|
|
||||||
ExecutionResult.Success
|
ExecutionResult.Success
|
||||||
}
|
}
|
||||||
} catch (e: ProcessCanceledException) {
|
} catch (e: ProcessCanceledException) {
|
||||||
@@ -108,6 +103,5 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = Logger.getInstance(CmdFilterCommand::class.java.name)
|
private val logger = Logger.getInstance(CmdFilterCommand::class.java.name)
|
||||||
private var lastCommand: String? = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,6 @@
|
|||||||
serviceInterface="com.maddyhome.idea.vim.api.VimProcessGroup"/>
|
serviceInterface="com.maddyhome.idea.vim.api.VimProcessGroup"/>
|
||||||
<applicationService serviceImplementation="com.maddyhome.idea.vim.ui.ex.ExEntryPanelService"
|
<applicationService serviceImplementation="com.maddyhome.idea.vim.ui.ex.ExEntryPanelService"
|
||||||
serviceInterface="com.maddyhome.idea.vim.api.VimCommandLineService"/>
|
serviceInterface="com.maddyhome.idea.vim.api.VimCommandLineService"/>
|
||||||
<applicationService serviceImplementation="com.maddyhome.idea.vim.ui.ex.IjOutputPanelService"
|
|
||||||
serviceInterface="com.maddyhome.idea.vim.api.VimOutputPanelService"/>
|
|
||||||
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.DigraphGroup"
|
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.DigraphGroup"
|
||||||
serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/>
|
serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/>
|
||||||
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/>
|
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user