mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2024-11-24 22:42:53 +01:00
Compare commits
160 Commits
9101ca1afc
...
3da1cc300f
Author | SHA1 | Date | |
---|---|---|---|
3da1cc300f | |||
4d535c4148 | |||
5768209a33 | |||
fe0f4fde9d | |||
25e4eb9078 | |||
9b507e6033 | |||
4d0a54221a | |||
17d49bc35d | |||
ba9966d996 | |||
ae1cb45854 | |||
27c8d9e610 | |||
5a247843e4 | |||
4438c654d0 | |||
705530fdfd | |||
a1c0cfda52 | |||
9261d17491 | |||
c89099bb0c | |||
00f73f52bd | |||
b0474cec7d | |||
|
fbbd1ebc0d | ||
|
8d5df11372 | ||
|
dfebe542d8 | ||
|
7fde47c08b | ||
|
629919f634 | ||
|
43fff1c73e | ||
|
d02f0e17ca | ||
|
5dc860f61e | ||
|
956e726c31 | ||
|
446067e2fe | ||
|
bd53a895c0 | ||
|
e61fed2467 | ||
|
f5e125759f | ||
|
622eb887c8 | ||
|
9fb614e16c | ||
|
1e0fa07768 | ||
|
bfb1d5b7f5 | ||
|
2fad8790a9 | ||
|
9719106a14 | ||
|
870a0da2a2 | ||
|
d3c315d299 | ||
|
2583b6e792 | ||
|
89417eb4f6 | ||
|
560700c9aa | ||
|
24514039e1 | ||
|
ff44596c1a | ||
|
b001d63fd9 | ||
|
5db96bef28 | ||
|
39c615cddd | ||
|
961173a93b | ||
|
92741c6356 | ||
|
643eb2a85f | ||
|
883744e4ee | ||
|
66173e03be | ||
|
e455722758 | ||
|
823bdc1561 | ||
|
f91fda2ca5 | ||
|
92abd76615 | ||
|
57c45ca153 | ||
|
7c623ae4b5 | ||
|
f2ef92cdef | ||
|
e8e6eabe97 | ||
|
ef1c915264 | ||
|
a5e2168f7f | ||
|
83e5470b3a | ||
|
c446de8979 | ||
|
13426915f4 | ||
|
d766c3b8ee | ||
|
844bc01537 | ||
|
3d2d32b022 | ||
|
a8677d3dd7 | ||
|
7217fdf734 | ||
|
0c867b3869 | ||
|
b3bcab4336 | ||
|
fe1b48a9b3 | ||
|
b5a0862520 | ||
|
babc1f54e5 | ||
|
32b910a65b | ||
|
2aa71a0008 | ||
|
c2c0c2aba2 | ||
|
6a10cf5e0d | ||
|
90474a3a4f | ||
|
be43f74bc6 | ||
|
5916c42cd1 | ||
|
a43c7ece32 | ||
|
40c1070b1a | ||
|
75ccdb2a4d | ||
|
3de7b0ca78 | ||
|
448e32a6cc | ||
|
4a85058ba2 | ||
|
7e28deb328 | ||
|
f3767b53b7 | ||
|
1026e27e64 | ||
|
18d653a9ae | ||
|
fcf4b44443 | ||
|
907e44b1d7 | ||
|
6c9b39a623 | ||
|
a3cb093b42 | ||
|
524e854c61 | ||
|
5588c27037 | ||
|
90d36eea98 | ||
|
f4414de86c | ||
|
d46102ccaf | ||
|
82347f5f0d | ||
|
c594f28acb | ||
|
bf6517e58f | ||
|
aec2f4c435 | ||
|
8f905758d5 | ||
|
80cc236f48 | ||
|
e432a02a45 | ||
|
d7894fa7f4 | ||
|
853d7032f0 | ||
|
5f9f57e1c0 | ||
|
f4381c8216 | ||
|
20eee7cae7 | ||
|
33392c2148 | ||
|
bb67564fbe | ||
|
61ccbcd788 | ||
|
1dbaa3be6d | ||
|
872bc22830 | ||
|
ce23ed814c | ||
|
82cd534756 | ||
|
673809d6b9 | ||
|
cdbaf73b1e | ||
|
7f911b7e72 | ||
|
c03a2dfe7e | ||
|
75935ce4d1 | ||
|
f0b203409e | ||
|
b3b369eb59 | ||
|
96072982cf | ||
|
de016fc445 | ||
|
554d9b5f7b | ||
|
149edefad5 | ||
|
52d3840c83 | ||
|
793677d4fd | ||
|
2376ee4877 | ||
|
68dcab6262 | ||
|
f38fd3512c | ||
|
e515278ba3 | ||
|
9cc69e41ee | ||
|
2109ff235c | ||
|
d6910aa81d | ||
|
8369391902 | ||
|
f336807498 | ||
|
14ba5d7126 | ||
|
288394d25f | ||
|
fb08b5fd65 | ||
|
3465e11c3a | ||
|
e07a16863e | ||
|
64f7532510 | ||
|
dd892e77fb | ||
|
65aeeba521 | ||
|
ca3e56d0d6 | ||
|
bcbfb0dc32 | ||
|
46a4a10e63 | ||
|
d5bddd077f | ||
|
e22fd263cc | ||
|
f3902d0ae0 | ||
|
f9213ee45d | ||
|
281bc2573e | ||
|
ae8c7f6bfa |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
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 integrationsTest
|
run: ./gradlew --no-configuration-cache 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 testIdeUi -Doctopus.handler=false > build/reports/idea.log &
|
gradle --no-configuration-cache 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/system/log sandbox-idea-log
|
run: mv build/idea-sandbox/IC-2024.1.2/log_runIdeForUiTests idea-sandbox-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
|
||||||
sandbox-idea-log
|
idea-sandbox-log
|
||||||
# build-for-ui-test-linux:
|
# build-for-ui-test-linux:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
# steps:
|
# steps:
|
||||||
@ -63,7 +63,7 @@ jobs:
|
|||||||
# export DISPLAY=:99.0
|
# export DISPLAY=:99.0
|
||||||
# Xvfb -ac :99 -screen 0 1920x1080x16 &
|
# Xvfb -ac :99 -screen 0 1920x1080x16 &
|
||||||
# mkdir -p build/reports
|
# mkdir -p build/reports
|
||||||
# gradle :testIdeUi #> 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@1.5
|
# uses: jtalk/url-health-check-action@1.5
|
||||||
# with:
|
# with:
|
||||||
|
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 :testIdeUi -PideaType=PC > build/reports/idea.log &
|
gradle --no-configuration-cache :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/system/log sandbox-idea-log
|
run: mv build/idea-sandbox/PC-2024.1.2/log_runIdeForUiTests idea-sandbox-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
|
||||||
sandbox-idea-log
|
idea-sandbox-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 testIdeUi > build/reports/idea.log &
|
gradle --no-configuration-cache 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/system/log sandbox-idea-log
|
run: mv build/idea-sandbox/IC-2024.1.2/log_runIdeForUiTests idea-sandbox-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
|
||||||
sandbox-idea-log
|
idea-sandbox-log
|
||||||
# build-for-ui-test-linux:
|
# build-for-ui-test-linux:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
# steps:
|
# steps:
|
||||||
@ -63,7 +63,7 @@ jobs:
|
|||||||
# export DISPLAY=:99.0
|
# export DISPLAY=:99.0
|
||||||
# Xvfb -ac :99 -screen 0 1920x1080x16 &
|
# Xvfb -ac :99 -screen 0 1920x1080x16 &
|
||||||
# mkdir -p build/reports
|
# mkdir -p build/reports
|
||||||
# gradle :testIdeUi #> 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@1.5
|
# uses: jtalk/url-health-check-action@1.5
|
||||||
# with:
|
# with:
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,3 +33,5 @@ vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
|||||||
|
|
||||||
# Created by github automation
|
# Created by github automation
|
||||||
settings.xml
|
settings.xml
|
||||||
|
|
||||||
|
.kotlin
|
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()
|
||||||
|
1
.teamcity/_Self/buildTypes/ReleasePlugin.kt
vendored
1
.teamcity/_Self/buildTypes/ReleasePlugin.kt
vendored
@ -144,6 +144,7 @@ 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"
|
||||||
|
@ -222,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"/>
|
||||||
@ -369,6 +369,8 @@ 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 "1.9.22"
|
kotlin("plugin.serialization") version "2.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
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.22")
|
compileOnly("com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.24")
|
||||||
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")
|
||||||
|
@ -45,7 +45,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0")
|
||||||
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,14 +66,14 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
kotlin("jvm") version "1.9.22"
|
kotlin("jvm") version "2.0.0"
|
||||||
application
|
application
|
||||||
id("java-test-fixtures")
|
id("java-test-fixtures")
|
||||||
id("org.jetbrains.intellij.platform") version "2.0.0-beta8"
|
id("org.jetbrains.intellij.platform") version "2.0.0-rc2"
|
||||||
id("org.jetbrains.changelog") version "2.2.0"
|
id("org.jetbrains.changelog") version "2.2.1"
|
||||||
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 "1.9.22-1.0.17"
|
id("com.google.devtools.ksp") version "2.0.0-1.0.23"
|
||||||
}
|
}
|
||||||
|
|
||||||
val moduleSources by configurations.registering
|
val moduleSources by configurations.registering
|
||||||
@ -124,7 +124,7 @@ dependencies {
|
|||||||
testFramework(TestFrameworkType.JUnit5)
|
testFramework(TestFrameworkType.JUnit5)
|
||||||
|
|
||||||
// AceJump is an optional dependency. We use their SessionManager class to check if it's active
|
// AceJump is an optional dependency. We use their SessionManager class to check if it's active
|
||||||
plugin("AceJump", "3.8.11")
|
plugin("AceJump", "3.8.19")
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
|
moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
|
||||||
@ -144,7 +144,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.3.1")
|
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
|
||||||
|
|
||||||
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")
|
||||||
@ -152,6 +152,12 @@ 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 {
|
||||||
@ -191,7 +197,14 @@ 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("-Xjvm-default=all-compatibility")
|
freeCompilerArgs = listOf(
|
||||||
|
"-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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,6 +213,10 @@ tasks {
|
|||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,6 +239,25 @@ tasks {
|
|||||||
// localPath = file("/Users/{user}/Applications/WebStorm.app")
|
// 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 {
|
val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
|
||||||
splitMode = true
|
splitMode = true
|
||||||
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
|
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
|
||||||
@ -231,19 +267,6 @@ tasks {
|
|||||||
version.set(splitModeVersion)
|
version.set(splitModeVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the default IDE with both IdeaVim and the robot server plugin installed, ready to run a UI test task. The
|
|
||||||
// robot server plugin is automatically added as a dependency to this task, and Gradle will take care of downloading.
|
|
||||||
// Note that the CustomTestIdeUiTask can be used to run tests against a different IDE
|
|
||||||
testIdeUi {
|
|
||||||
systemProperty("robot-server.port", "8082")
|
|
||||||
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")
|
|
||||||
|
|
||||||
systemProperty("octopus.handler", System.getProperty("octopus.handler") ?: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 sourcesJar by registering(Jar::class) {
|
||||||
dependsOn(moduleSources)
|
dependsOn(moduleSources)
|
||||||
@ -288,7 +311,14 @@ intellijPlatform {
|
|||||||
pluginConfiguration {
|
pluginConfiguration {
|
||||||
name = "IdeaVim"
|
name = "IdeaVim"
|
||||||
changeNotes.set(
|
changeNotes.set(
|
||||||
"""<a href="https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20Fix%20versions:%20${version.get()}">Changelog</a>"""
|
"""
|
||||||
|
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 {
|
ideaVersion {
|
||||||
|
@ -5,7 +5,7 @@ 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"/>
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
# 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.1.1
|
ideaVersion=2024.2
|
||||||
# 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
|
||||||
instrumentPluginCode=true
|
instrumentPluginCode=true
|
||||||
version=SNAPSHOT
|
version=chylex-38
|
||||||
javaVersion=17
|
javaVersion=17
|
||||||
remoteRobotVersion=0.11.22
|
remoteRobotVersion=0.11.23
|
||||||
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 +34,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=1.9.22
|
kotlinVersion=2.0.0
|
||||||
publishToken=token
|
publishToken=token
|
||||||
publishChannels=eap
|
publishChannels=eap
|
||||||
|
|
||||||
@ -47,7 +47,6 @@ youtrackToken=
|
|||||||
|
|
||||||
# Gradle settings
|
# Gradle settings
|
||||||
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||||
org.gradle.configuration-cache=true
|
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
|
|
||||||
# Disable warning from gradle-intellij-plugin. Kotlin stdlib is included as compileOnly, so the warning is unnecessary
|
# Disable warning from gradle-intellij-plugin. Kotlin stdlib is included as compileOnly, so the warning is unnecessary
|
||||||
|
@ -19,9 +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
|
- 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.24")
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.25")
|
||||||
|
|
||||||
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,14 +8,19 @@
|
|||||||
|
|
||||||
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
|
||||||
@ -28,6 +33,11 @@ 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()
|
||||||
}
|
}
|
||||||
@ -36,6 +46,7 @@ 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,6 +37,7 @@ 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;
|
||||||
@ -67,7 +68,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 {
|
||||||
VimInjectorKt.setInjector(new IjVimInjector());
|
IjVimInjectorKt.initInjector();
|
||||||
}
|
}
|
||||||
|
|
||||||
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().editor = null
|
ExEntryPanel.getInstance().setEditor(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -43,6 +43,7 @@ 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
|
||||||
@ -61,10 +62,13 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +261,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().editor
|
ExEntryPanel.getInstance().ijEditor
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -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(IdeActions.ACTION_QUICK_JAVADOC, context)
|
injector.actionExecutor.executeAction(editor, IdeActions.ACTION_QUICK_JAVADOC, context)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
72
src/main/java/com/maddyhome/idea/vim/command/CommandState.kt
Normal file
72
src/main/java/com/maddyhome/idea/vim/command/CommandState.kt
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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) {
|
internal class IndentConfig private constructor(indentOptions: IndentOptions): VimIndentConfig {
|
||||||
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
|
||||||
|
|
||||||
fun getTotalIndent(count: Int): Int = indentSize * count
|
override fun getIndentSize(depth: Int): Int = indentSize * depth
|
||||||
|
override fun createIndentByDepth(depth: Int): String = createIndentBySize(getIndentSize(depth))
|
||||||
|
|
||||||
fun createIndentByCount(count: Int): String = createIndentBySize(getTotalIndent(count))
|
override fun createIndentBySize(size: Int): String {
|
||||||
|
|
||||||
fun createIndentBySize(size: Int): String {
|
|
||||||
val tabCount: Int
|
val tabCount: Int
|
||||||
val spaceCount: Int
|
val spaceCount: Int
|
||||||
if (isUseTabs) {
|
if (isUseTabs) {
|
||||||
|
@ -18,6 +18,8 @@ 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,14 +9,15 @@ 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.VimOutputPanel
|
import com.maddyhome.idea.vim.api.VimOutputPanelBase
|
||||||
import com.maddyhome.idea.vim.api.injector
|
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 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>) : VimOutputPanel {
|
class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPanelBase() {
|
||||||
private var isActiveInTestMode = false
|
private var isActiveInTestMode = false
|
||||||
|
|
||||||
val editor get() = myEditor.get()
|
val editor get() = myEditor.get()
|
||||||
@ -48,6 +49,24 @@ class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPane
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = ""
|
override var text: String = ""
|
||||||
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
get() = if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
editor?.let { ExOutputPanel.getInstance(it).text } ?: ""
|
editor?.let { ExOutputPanel.getInstance(it).text } ?: ""
|
||||||
@ -66,6 +85,17 @@ class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPane
|
|||||||
isActiveInTestMode = newValue.isNotEmpty()
|
isActiveInTestMode = newValue.isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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) {
|
fun output(text: String) {
|
||||||
this.text = text
|
this.text = text
|
||||||
@ -75,6 +105,25 @@ class ExOutputModel(private val myEditor: WeakReference<Editor>) : VimOutputPane
|
|||||||
text = ""
|
text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() }
|
editor?.let { ExOutputPanel.getInstance(it).close() }
|
||||||
|
@ -31,6 +31,7 @@ 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
|
||||||
@ -68,7 +69,8 @@ object VimExtensionFacade {
|
|||||||
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
|
@Deprecated(
|
||||||
|
"Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
|
||||||
ReplaceWith(
|
ReplaceWith(
|
||||||
"VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
|
"VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
|
||||||
"com.maddyhome.idea.vim.VimPlugin"
|
"com.maddyhome.idea.vim.VimPlugin"
|
||||||
@ -182,7 +184,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.inputString(editor.vim, context.vim, prompt, finishOn) ?: ""
|
return (injector.commandLine as ExEntryPanelService).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()'. */
|
||||||
@ -194,7 +196,7 @@ object VimExtensionFacade {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
|
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
|
||||||
val reg = caret.registerStorage.getRegister(register) ?: return null
|
val reg = injector.registerGroup.getRegister(register) ?: return null
|
||||||
return reg.keys
|
return reg.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +209,7 @@ object VimExtensionFacade {
|
|||||||
/** Set the current contents of the given register */
|
/** Set the current contents of the given register */
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
|
fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
|
||||||
caret.registerStorage.setKeys(register, keys?.filterNotNull() ?: emptyList())
|
injector.registerGroup.setKeys(register, keys?.filterNotNull() ?: emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the current contents of the given register */
|
/** Set the current contents of the given register */
|
||||||
|
@ -79,11 +79,12 @@ 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(it, project, context, callback) }
|
actions.any { executeActionWithCallbackOnSuccess(editor, it, project, context, callback) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeActionWithCallbackOnSuccess(
|
private fun executeActionWithCallbackOnSuccess(
|
||||||
|
editor: VimEditor,
|
||||||
action: String,
|
action: String,
|
||||||
project: Project,
|
project: Project,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
@ -92,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(action, context)) },
|
{ res.set(injector.actionExecutor.executeAction(editor, name = action, context = context)) },
|
||||||
{ if (res.get()) callback() })
|
{ if (res.get()) callback() })
|
||||||
return res.get()
|
return res.get()
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,15 @@ 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
|
||||||
@ -75,7 +77,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, VimInsertListener {
|
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
|
||||||
private val highlightHandler = HighlightHandler()
|
private val highlightHandler = HighlightHandler()
|
||||||
private var initialised = false
|
private var initialised = false
|
||||||
|
|
||||||
@ -83,8 +85,8 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, VimInsertList
|
|||||||
|
|
||||||
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
|
||||||
VimPlugin.getYank().addListener(this)
|
injector.listenersNotifier.modeChangeListeners.add(this)
|
||||||
VimPlugin.getChange().addInsertListener(this)
|
injector.listenersNotifier.yankListeners.add(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
|
||||||
@ -105,8 +107,8 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, VimInsertList
|
|||||||
|
|
||||||
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
|
||||||
VimPlugin.getYank().removeListener(this)
|
injector.listenersNotifier.modeChangeListeners.remove(this)
|
||||||
VimPlugin.getChange().removeInsertListener(this)
|
injector.listenersNotifier.yankListeners.remove(this)
|
||||||
|
|
||||||
highlightHandler.clearYankHighlighters()
|
highlightHandler.clearYankHighlighters()
|
||||||
initialised = false
|
initialised = false
|
||||||
@ -117,7 +119,8 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, VimInsertList
|
|||||||
highlightHandler.highlightYankRange(editor.ij, range)
|
highlightHandler.highlightYankRange(editor.ij, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun insertModeStarted(editor: Editor) {
|
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
||||||
|
if (editor.mode !is Mode.INSERT) return
|
||||||
ensureInitialised()
|
ensureInitialised()
|
||||||
highlightHandler.clearYankHighlighters()
|
highlightHandler.clearYankHighlighters()
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ private object FileTypePatterns {
|
|||||||
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
|
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
|
||||||
this.cMakePatterns
|
this.cMakePatterns
|
||||||
} else {
|
} else {
|
||||||
return null
|
this.htmlPatterns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,6 +481,9 @@ 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"))
|
||||||
|
@ -144,7 +144,7 @@ internal class ReplaceWithRegister : VimExtension {
|
|||||||
private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
|
private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
|
||||||
val registerGroup = injector.registerGroup
|
val registerGroup = injector.registerGroup
|
||||||
val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
|
val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
|
||||||
val savedRegister = caret.registerStorage.getRegister(lastRegisterChar) ?: return
|
val savedRegister = registerGroup.getRegister(lastRegisterChar) ?: return
|
||||||
|
|
||||||
var usedType = savedRegister.type
|
var usedType = savedRegister.type
|
||||||
var usedText = savedRegister.text
|
var usedText = savedRegister.text
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.maddyhome.idea.vim.extension.surround
|
||||||
|
|
||||||
|
import com.intellij.util.text.CharSequenceSubSequence
|
||||||
|
|
||||||
|
internal data class RepeatedCharSequence(val text: CharSequence, val count: Int) : CharSequence {
|
||||||
|
override val length = text.length * count
|
||||||
|
|
||||||
|
override fun get(index: Int): Char {
|
||||||
|
if (index < 0 || index >= length) throw IndexOutOfBoundsException()
|
||||||
|
return text[index % text.length]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
||||||
|
return CharSequenceSubSequence(this, startIndex, endIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return text.repeat(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun of(text: CharSequence, count: Int): CharSequence {
|
||||||
|
return when (count) {
|
||||||
|
0 -> ""
|
||||||
|
1 -> text
|
||||||
|
else -> RepeatedCharSequence(text, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
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.VimCaret
|
import com.maddyhome.idea.vim.api.VimCaret
|
||||||
|
import com.maddyhome.idea.vim.api.VimChangeGroup
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.endsWithNewLine
|
import com.maddyhome.idea.vim.api.endsWithNewLine
|
||||||
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
|
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
|
||||||
@ -35,7 +36,11 @@ 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.key.OperatorFunction
|
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
|
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.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
|
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
|
||||||
@ -46,6 +51,7 @@ 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.
|
||||||
@ -78,7 +84,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
putKeyMappingIfMissing(MappingMode.XO, injector.parser.parseKeys("S"), owner, injector.parser.parseKeys("<Plug>VSurround"), true)
|
putKeyMappingIfMissing(MappingMode.XO, injector.parser.parseKeys("S"), owner, injector.parser.parseKeys("<Plug>VSurround"), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator())
|
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator(supportsMultipleCursors = false, count = 1)) // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
private class YSurroundHandler : ExtensionHandler {
|
private class YSurroundHandler : ExtensionHandler {
|
||||||
@ -106,11 +112,14 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
|
val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
|
||||||
if (lastNonWhiteSpaceOffset != null) {
|
if (lastNonWhiteSpaceOffset != null) {
|
||||||
val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
|
val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
|
||||||
performSurround(pair, range, it)
|
performSurround(pair, range, it, count = operatorArguments.count1)
|
||||||
}
|
}
|
||||||
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,15 +135,13 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
|
|
||||||
private class VSurroundHandler : ExtensionHandler {
|
private class VSurroundHandler : ExtensionHandler {
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart
|
|
||||||
// NB: Operator ignores SelectionType anyway
|
// NB: Operator ignores SelectionType anyway
|
||||||
if (!Operator().apply(editor, context, editor.mode.selectionType)) {
|
if (!Operator(supportsMultipleCursors = true, count = operatorArguments.count1).apply(editor, context, editor.mode.selectionType)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
// Leave visual mode
|
// Leave visual mode
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
|
editor.exitVisualMode()
|
||||||
editor.ij.caretModel.moveToOffset(selectionStart)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,6 +162,10 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
||||||
|
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
||||||
// Save old register values for carets
|
// Save old register values for carets
|
||||||
val surroundings = editor.sortedCarets()
|
val surroundings = editor.sortedCarets()
|
||||||
.map {
|
.map {
|
||||||
@ -262,25 +273,48 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Operator : OperatorFunction {
|
private class Operator(private val supportsMultipleCursors: Boolean, private val count: Int) : OperatorFunction {
|
||||||
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
|
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
|
||||||
val ijEditor = editor.ij
|
val ijEditor = vimEditor.ij
|
||||||
val c = getChar(ijEditor)
|
val c = getChar(ijEditor)
|
||||||
if (c.code == 0) return true
|
if (c.code == 0) return true
|
||||||
|
|
||||||
val pair = getOrInputPair(c, ijEditor, context.ij) ?: return false
|
val pair = getOrInputPair(c, ijEditor, context.ij) ?: return false
|
||||||
// XXX: Will it work with line-wise or block-wise selections?
|
|
||||||
val range = getSurroundRange(editor.currentCaret()) ?: return false
|
runWriteAction {
|
||||||
performSurround(pair, range, editor.currentCaret(), selectionType == SelectionType.LINE_WISE)
|
val change = VimPlugin.getChange()
|
||||||
|
if (supportsMultipleCursors) {
|
||||||
|
ijEditor.runWithEveryCaretAndRestore {
|
||||||
|
applyOnce(ijEditor, change, pair, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
applyOnce(ijEditor, change, pair, count)
|
||||||
// Jump back to start
|
// Jump back to start
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
|
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
|
||||||
|
// XXX: Will it work with line-wise or block-wise selections?
|
||||||
|
val primaryCaret = editor.caretModel.primaryCaret
|
||||||
|
val range = getSurroundRange(primaryCaret.vim)
|
||||||
|
if (range != null) {
|
||||||
|
val start = RepeatedCharSequence.of(pair.first, count)
|
||||||
|
val end = RepeatedCharSequence.of(pair.second, count)
|
||||||
|
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, start)
|
||||||
|
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + start.length, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
||||||
val editor = caret.editor
|
val editor = caret.editor
|
||||||
val ijEditor = editor.ij
|
if (editor.mode is Mode.CMD_LINE) {
|
||||||
return when (ijEditor.vim.mode) {
|
editor.mode = (editor.mode as Mode.CMD_LINE).returnTo()
|
||||||
|
}
|
||||||
|
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
|
||||||
@ -323,6 +357,9 @@ 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)
|
||||||
@ -339,6 +376,9 @@ 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 ")"
|
||||||
}
|
}
|
||||||
@ -362,15 +402,15 @@ private fun getChar(editor: Editor): Char {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, tagsOnNewLines: Boolean = false) {
|
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) {
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
val editor = caret.editor
|
val editor = caret.editor
|
||||||
val change = VimPlugin.getChange()
|
val change = VimPlugin.getChange()
|
||||||
val leftSurround = pair.first + if (tagsOnNewLines) "\n" else ""
|
val leftSurround = RepeatedCharSequence.of(pair.first + if (tagsOnNewLines) "\n" else "", count)
|
||||||
|
|
||||||
val isEOF = range.endOffset == editor.text().length
|
val isEOF = range.endOffset == editor.text().length
|
||||||
val hasNewLine = editor.endsWithNewLine()
|
val hasNewLine = editor.endsWithNewLine()
|
||||||
val rightSurround = if (tagsOnNewLines) {
|
val rightSurround = (if (tagsOnNewLines) {
|
||||||
if (isEOF && !hasNewLine) {
|
if (isEOF && !hasNewLine) {
|
||||||
"\n" + pair.second
|
"\n" + pair.second
|
||||||
} else {
|
} else {
|
||||||
@ -378,7 +418,7 @@ private fun performSurround(pair: Pair<String, String>, range: TextRange, caret:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pair.second
|
pair.second
|
||||||
}
|
}).let { RepeatedCharSequence.of(it, count) }
|
||||||
|
|
||||||
change.insertText(editor, caret, range.startOffset, leftSurround)
|
change.insertText(editor, caret, range.startOffset, leftSurround)
|
||||||
change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
|
change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
|
||||||
|
@ -15,78 +15,35 @@ 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
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -146,163 +103,6 @@ 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(
|
||||||
@ -311,94 +111,20 @@ 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,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
range: TextRange,
|
range: TextRange,
|
||||||
) {
|
) {
|
||||||
|
val startPos = editor.offsetToBufferPosition(caret.offset)
|
||||||
val startOffset = editor.getLineStartForOffset(range.startOffset)
|
val startOffset = editor.getLineStartForOffset(range.startOffset)
|
||||||
val endOffset = editor.getLineEndForOffset(range.endOffset)
|
val endOffset = editor.getLineEndForOffset(range.endOffset)
|
||||||
val ijEditor = (editor as IjVimEditor).editor
|
val ijEditor = (editor as IjVimEditor).editor
|
||||||
@ -423,11 +149,7 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val afterAction = {
|
val afterAction = {
|
||||||
val firstLine = editor.offsetToBufferPosition(
|
caret.moveToOffset(injector.motion.moveCaretToLineStartSkipLeading(editor, startPos.line))
|
||||||
min(startOffset.toDouble(), endOffset.toDouble()).toInt()
|
|
||||||
).line
|
|
||||||
val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
|
|
||||||
caret.moveToOffset(newOffset)
|
|
||||||
restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
|
restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
|
||||||
}
|
}
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
@ -450,361 +172,14 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun indentLines(
|
@Deprecated(message = "Please use listenersNotifier", replaceWith = ReplaceWith("injector.listenersNotifier.modeChangeListeners.add", imports = ["import com.maddyhome.idea.vim.api.injector"]))
|
||||||
editor: VimEditor,
|
|
||||||
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) {
|
fun addInsertListener(listener: VimInsertListener) {
|
||||||
insertListeners.add(listener)
|
injector.listenersNotifier.modeChangeListeners.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) {
|
||||||
insertListeners.remove(listener)
|
injector.listenersNotifier.modeChangeListeners.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 {
|
||||||
|
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
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;
|
||||||
@ -23,12 +21,10 @@ 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;
|
||||||
@ -218,8 +214,10 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
editorEx.addPropertyChangeListener(FontSizeChangeListener.INSTANCE);
|
editorEx.addPropertyChangeListener(FontSizeChangeListener.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (injector.getApplication().isUnitTest()) {
|
||||||
updateCaretsVisualAttributes(new IjVimEditor(editor));
|
updateCaretsVisualAttributes(new IjVimEditor(editor));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void editorDeinit(@NotNull Editor editor) {
|
public void editorDeinit(@NotNull Editor editor) {
|
||||||
deinitLineNumbers(editor);
|
deinitLineNumbers(editor);
|
||||||
@ -240,9 +238,8 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
VimPlugin.getNotifications(project).notifyAboutIdeaJoin(editor);
|
VimPlugin.getNotifications(project).notifyAboutIdeaJoin(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public Element getState() {
|
public @Nullable Element getState() {
|
||||||
Element element = new Element("editor");
|
Element element = new Element("editor");
|
||||||
saveData(element);
|
saveData(element);
|
||||||
return element;
|
return element;
|
||||||
@ -318,18 +315,16 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<VimEditor> getEditors() {
|
public @NotNull 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 Collection<VimEditor> getEditors(@NotNull VimDocument buffer) {
|
public @NotNull 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))
|
||||||
@ -349,7 +344,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.ALL);
|
List<ClientAppSession> appSessions = ClientSessionsManager.getAppSessions(ClientKind.LOCAL);
|
||||||
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();
|
||||||
@ -377,12 +372,16 @@ 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) {
|
||||||
injector.getProcessGroup().cancelExEntry(new IjVimEditor(editor), true, false);
|
activeCommandLine.close(true, false);
|
||||||
}
|
}
|
||||||
ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
|
ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
|
||||||
if (exOutputModel != null) {
|
if (exOutputModel != null) {
|
||||||
exOutputModel.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(context: ExecutionContext) {
|
override fun saveFile(editor: VimEditor, 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(context)
|
action.execute(editor, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves all files in the project.
|
* Saves all files in the project.
|
||||||
*/
|
*/
|
||||||
override fun saveFiles(context: ExecutionContext) {
|
override fun saveFiles(editor: VimEditor, context: ExecutionContext) {
|
||||||
injector.nativeActionManager.saveAll.execute(context)
|
injector.nativeActionManager.saveAll.execute(editor, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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)
|
val commenter = LanguageCommenters.INSTANCE.forLanguage(language) ?: return null
|
||||||
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
|
||||||
|
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.maddyhome.idea.vim.group
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.ReferenceImporter
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.application.ReadAction
|
||||||
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.openapi.progress.Task
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
|
||||||
|
import java.util.function.BooleanSupplier
|
||||||
|
|
||||||
|
internal object MacroAutoImport {
|
||||||
|
fun run(editor: Editor, dataContext: DataContext) {
|
||||||
|
val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
|
||||||
|
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return
|
||||||
|
|
||||||
|
if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val importers = ReferenceImporter.EP_NAME.extensionList
|
||||||
|
if (importers.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Auto import", true) {
|
||||||
|
override fun run(indicator: ProgressIndicator) {
|
||||||
|
val fixes = ReadAction.nonBlocking<List<BooleanSupplier>> {
|
||||||
|
val fixes = mutableListOf<BooleanSupplier>()
|
||||||
|
|
||||||
|
file.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||||
|
override fun visitElement(element: PsiElement) {
|
||||||
|
for (reference in element.references) {
|
||||||
|
if (reference.resolve() != null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (importer in importers) {
|
||||||
|
importer.computeAutoImportAtOffset(editor, file, element.textRange.startOffset, true)
|
||||||
|
?.let(fixes::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitElement(element)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return@nonBlocking fixes
|
||||||
|
}.executeSynchronously()
|
||||||
|
|
||||||
|
ApplicationManager.getApplication().invokeAndWait {
|
||||||
|
WriteCommandAction.writeCommandAction(project)
|
||||||
|
.withName("Auto Import")
|
||||||
|
.withGroupId("IdeaVimAutoImportAfterMacro")
|
||||||
|
.shouldRecordActionForActiveDocument(true)
|
||||||
|
.run<RuntimeException> {
|
||||||
|
fixes.forEach { it.asBoolean }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.helper.MessageHelper.message
|
import com.maddyhome.idea.vim.helper.MessageHelper.message
|
||||||
import com.maddyhome.idea.vim.macro.VimMacroBase
|
import com.maddyhome.idea.vim.macro.VimMacroBase
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to handle playback of macros
|
* Used to handle playback of macros
|
||||||
@ -93,6 +94,9 @@ internal class MacroGroup : VimMacroBase() {
|
|||||||
} finally {
|
} finally {
|
||||||
keyStack.removeFirst()
|
keyStack.removeFirst()
|
||||||
}
|
}
|
||||||
|
if (!isInternalMacro) {
|
||||||
|
MacroAutoImport.run(editor.ij, context.ij)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInternalMacro) {
|
if (isInternalMacro) {
|
||||||
|
@ -47,11 +47,14 @@ 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.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
|
||||||
@ -312,13 +315,26 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
KeyHandler.getInstance().reset(vimEditor)
|
KeyHandler.getInstance().reset(vimEditor)
|
||||||
}
|
}
|
||||||
is Mode.CMD_LINE -> {
|
is Mode.CMD_LINE -> {
|
||||||
injector.processGroup.cancelExEntry(vimEditor, refocusOwningEditor = false, resetCaret = false)
|
val commandLine = injector.commandLine.getActiveCommandLine() ?: return
|
||||||
|
commandLine.close(refocusOwningEditor = false, resetCaret = false)
|
||||||
ExOutputModel.tryGetInstance(editor)?.close()
|
ExOutputModel.tryGetInstance(editor)?.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,6 +62,25 @@ 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,
|
||||||
@ -182,8 +201,8 @@ internal class NotificationService(private val project: Project?) {
|
|||||||
).notify(project)
|
).notify(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyActionId(id: String?) {
|
fun notifyActionId(id: String?, candidates: List<String>? = null) {
|
||||||
ActionIdNotifier.notifyActionId(id, project)
|
ActionIdNotifier.notifyActionId(id, project, candidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyKeymapIssues(issues: ArrayList<KeyMapIssue>) {
|
fun notifyKeymapIssues(issues: ArrayList<KeyMapIssue>) {
|
||||||
@ -259,20 +278,31 @@ 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?) {
|
fun notifyActionId(id: String?, project: Project?, candidates: List<String>? = null) {
|
||||||
notification?.expire()
|
notification?.expire()
|
||||||
|
|
||||||
val content = if (id != null) "Action id: $id" else NO_ID
|
val possibleIDs = candidates?.distinct()?.sorted()
|
||||||
Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let {
|
val content = when {
|
||||||
notification = it
|
id != null -> "Action ID: <code>$id</code><br><br>"
|
||||||
it.whenExpired { notification = null }
|
possibleIDs.isNullOrEmpty() -> "<i>Cannot detect action ID</i><br><br>"
|
||||||
it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>")
|
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.addAction(StopTracking())
|
it.addAction(StopTracking())
|
||||||
|
|
||||||
if (id != null) it.addAction(CopyActionId(id, project))
|
if (id != null || possibleIDs?.size == 1) {
|
||||||
|
it.addAction(CopyActionId(id ?: possibleIDs?.get(0), project))
|
||||||
|
}
|
||||||
|
|
||||||
it.notify(project)
|
it.notify(project)
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,6 @@ 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,6 +14,8 @@ 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;
|
||||||
@ -35,6 +37,10 @@ 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,6 +25,7 @@ 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)])
|
||||||
@ -65,6 +66,7 @@ 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>()
|
||||||
@ -89,6 +91,7 @@ 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,6 +46,7 @@ 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
|
||||||
@ -83,7 +84,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 (editor.isInsertMode) {
|
if (injector.vimState.mode is Mode.INSERT) {
|
||||||
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,6 +16,7 @@ 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
|
||||||
@ -34,6 +35,8 @@ 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(actionName, context)
|
injector.actionExecutor.executeAction(editor, name = actionName, context = context)
|
||||||
injector.scroll.scrollCaretIntoView(editor)
|
injector.scroll.scrollCaretIntoView(editor)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ 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
|
||||||
@ -86,6 +87,7 @@ 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
|
||||||
@ -99,6 +101,7 @@ 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 {
|
||||||
@ -144,24 +147,28 @@ private object AttributesCache {
|
|||||||
@TestOnly
|
@TestOnly
|
||||||
internal fun getGuiCursorMode(editor: Editor) = editor.guicursorMode()
|
internal fun getGuiCursorMode(editor: Editor) = editor.guicursorMode()
|
||||||
|
|
||||||
class CaretVisualAttributesListener : IsReplaceCharListener, ModeChangeListener {
|
class CaretVisualAttributesListener : IsReplaceCharListener, ModeChangeListener, EditorListener {
|
||||||
override fun isReplaceCharChanged(editor: VimEditor) {
|
override fun isReplaceCharChanged(editor: VimEditor) {
|
||||||
updateCaretsVisual()
|
updateCaretsVisual(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
||||||
updateCaretsVisual()
|
updateCaretsVisual(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCaretsVisual() {
|
override fun focusGained(editor: VimEditor) {
|
||||||
updateAllEditorsCaretsVisual()
|
updateCaretsVisual(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateAllEditorsCaretsVisual() {
|
private fun updateCaretsVisual(editor: VimEditor) {
|
||||||
injector.editorGroup.getEditors().forEach { editor ->
|
|
||||||
val ijEditor = (editor as IjVimEditor).editor
|
val ijEditor = (editor as IjVimEditor).editor
|
||||||
ijEditor.updateCaretsVisualAttributes()
|
ijEditor.updateCaretsVisualAttributes()
|
||||||
ijEditor.updateCaretsVisualPosition()
|
ijEditor.updateCaretsVisualPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateAllEditorsCaretsVisual() {
|
||||||
|
injector.editorGroup.getEditors().forEach { editor ->
|
||||||
|
updateCaretsVisual(editor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -326,7 +326,7 @@ public class EditorHelper {
|
|||||||
|
|
||||||
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
||||||
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
||||||
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
|
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
|
||||||
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
||||||
|
|
||||||
// For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
|
// For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
|
||||||
|
@ -12,6 +12,7 @@ package com.maddyhome.idea.vim.helper
|
|||||||
|
|
||||||
import com.intellij.codeWithMe.ClientId
|
import com.intellij.codeWithMe.ClientId
|
||||||
import com.intellij.openapi.editor.Caret
|
import com.intellij.openapi.editor.Caret
|
||||||
|
import com.intellij.openapi.editor.CaretState
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||||
@ -20,6 +21,8 @@ import com.maddyhome.idea.vim.api.StringListOptionValue
|
|||||||
import com.maddyhome.idea.vim.api.injector
|
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.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
import javax.swing.JTable
|
import javax.swing.JTable
|
||||||
@ -96,3 +99,41 @@ internal val Caret.vimLine: Int
|
|||||||
*/
|
*/
|
||||||
internal val Editor.vimLine: Int
|
internal val Editor.vimLine: Int
|
||||||
get() = this.caretModel.currentCaret.vimLine
|
get() = this.caretModel.currentCaret.vimLine
|
||||||
|
|
||||||
|
internal inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) {
|
||||||
|
val caretModel = this.caretModel
|
||||||
|
val carets = if (this.vim.inBlockSelection) null else caretModel.allCarets
|
||||||
|
if (carets == null || carets.size == 1) {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var initialDocumentSize = this.document.textLength
|
||||||
|
var documentSizeDifference = 0
|
||||||
|
|
||||||
|
val caretOffsets = carets.map { it.selectionStart to it.selectionEnd }
|
||||||
|
val restoredCarets = mutableListOf<CaretState>()
|
||||||
|
|
||||||
|
caretModel.removeSecondaryCarets()
|
||||||
|
|
||||||
|
for ((selectionStart, selectionEnd) in caretOffsets) {
|
||||||
|
if (selectionStart == selectionEnd) {
|
||||||
|
caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
caretModel.primaryCaret.setSelection(
|
||||||
|
selectionStart + documentSizeDifference,
|
||||||
|
selectionEnd + documentSizeDifference
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
action()
|
||||||
|
restoredCarets.add(caretModel.caretsAndSelections.single())
|
||||||
|
|
||||||
|
val documentLength = this.document.textLength
|
||||||
|
documentSizeDifference += documentLength - initialDocumentSize
|
||||||
|
initialDocumentSize = documentLength
|
||||||
|
}
|
||||||
|
|
||||||
|
caretModel.caretsAndSelections = restoredCarets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,22 +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.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.project.IndexNotReadyException
|
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
|
||||||
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
|
||||||
@ -68,6 +69,12 @@ 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +93,7 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
ActionManager.getInstance(),
|
ActionManager.getInstance(),
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
Utils.initUpdateSession(event)
|
||||||
// beforeActionPerformedUpdate should be called to update the action. It fixes some rider-specific problems.
|
// beforeActionPerformedUpdate should be called to update the action. It fixes some rider-specific problems.
|
||||||
// because rider use async update method. See VIM-1819.
|
// because rider use async update method. See VIM-1819.
|
||||||
// This method executes inside of lastUpdateAndCheckDumb
|
// This method executes inside of lastUpdateAndCheckDumb
|
||||||
@ -119,51 +127,15 @@ 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(name: @NonNls String, context: ExecutionContext): Boolean {
|
override fun executeAction(editor: VimEditor, name: @NonNls String, context: ExecutionContext): Boolean {
|
||||||
val action = getAction(name, context)
|
val action = getAction(name, context)
|
||||||
return action != null && executeAction(null, IjNativeAction(action), context)
|
return action != null && executeAction(editor, IjNativeAction(action), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAction(name: String, context: ExecutionContext): AnAction? {
|
private fun getAction(name: String, context: ExecutionContext): AnAction? {
|
||||||
@ -209,8 +181,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(context: ExecutionContext): Boolean {
|
override fun executeEsc(editor: VimEditor, context: ExecutionContext): Boolean {
|
||||||
return executeAction(IdeActions.ACTION_EDITOR_ESCAPE, context)
|
return executeAction(editor, IdeActions.ACTION_EDITOR_ESCAPE, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeVimAction(
|
override fun executeVimAction(
|
||||||
|
@ -14,6 +14,7 @@ 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
|
||||||
@ -22,7 +23,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 : EngineEditorHelper {
|
internal class IjEditorHelper : EngineEditorHelperBase() {
|
||||||
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(
|
||||||
@ -51,10 +52,6 @@ internal class IjEditorHelper : EngineEditorHelper {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ internal object ScrollViewHelper {
|
|||||||
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
||||||
val topLine = getVisualLineAtTopOfScreen(editor)
|
val topLine = getVisualLineAtTopOfScreen(editor)
|
||||||
val bottomLine = getVisualLineAtBottomOfScreen(editor)
|
val bottomLine = getVisualLineAtBottomOfScreen(editor)
|
||||||
val lastLine = vimEditor.getVisualLineCount() - 1
|
val lastLine = vimEditor.getVisualLineCount() + editor.settings.additionalLinesCount
|
||||||
|
|
||||||
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
|
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
|
||||||
val scrollOffset = injector.options(vimEditor).scrolloff
|
val scrollOffset = injector.options(vimEditor).scrolloff
|
||||||
|
@ -16,18 +16,15 @@ 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.
|
||||||
@ -97,210 +94,6 @@ 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,16 +16,20 @@ 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.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.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.newapi.IjVimCaret
|
|
||||||
import com.maddyhome.idea.vim.common.InsertSequence
|
import com.maddyhome.idea.vim.common.InsertSequence
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
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.inVisualMode
|
||||||
import com.maddyhome.idea.vim.undo.UndoRedoBase
|
import com.maddyhome.idea.vim.undo.UndoRedoBase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,17 +68,10 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
|
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
|
||||||
editor.runWithChangeTracking {
|
editor.runWithChangeTracking {
|
||||||
undoManager.undo(fileEditor)
|
undoManager.undo(fileEditor)
|
||||||
|
restoreVisualMode(editor)
|
||||||
// We execute undo one more time if the previous one just restored selection
|
|
||||||
if (!hasChanges && hasSelection(editor) && undoManager.isUndoAvailable(fileEditor)) {
|
|
||||||
undoManager.undo(fileEditor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandProcessor.getInstance().runUndoTransparentAction {
|
|
||||||
removeSelections(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)
|
||||||
@ -95,6 +92,13 @@ 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()
|
||||||
}
|
}
|
||||||
@ -219,4 +223,21 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
val hasChanges: Boolean
|
val hasChanges: Boolean
|
||||||
get() = changeListener.hasChanged || initialPath != editor.getPath()
|
get() = changeListener.hasChanged || initialPath != editor.getPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreVisualMode(editor: VimEditor) {
|
||||||
|
if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
|
||||||
|
val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
|
||||||
|
|
||||||
|
// Visual block selection is restored into multiple carets, so multi-carets that form a block are always
|
||||||
|
// identified as visual block mode, leading to false positives.
|
||||||
|
// Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
|
||||||
|
// visual block mode.
|
||||||
|
val wantedMode = if (detectedMode == SelectionType.BLOCK_WISE)
|
||||||
|
SelectionType.CHARACTER_WISE
|
||||||
|
else
|
||||||
|
detectedMode
|
||||||
|
|
||||||
|
VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,12 @@ import com.intellij.openapi.editor.VisualPosition
|
|||||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.UserDataHolder
|
import com.intellij.openapi.util.UserDataHolder
|
||||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
|
|
||||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
||||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||||
|
import com.maddyhome.idea.vim.common.InsertSequence
|
||||||
import com.maddyhome.idea.vim.ex.ExOutputModel
|
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.common.InsertSequence
|
|
||||||
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.VimStateMachine
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
@ -96,7 +95,6 @@ internal var Caret.vimInsertStart: RangeMarker by userDataOr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Data could be lost during visual block motion
|
// TODO: Data could be lost during visual block motion
|
||||||
internal var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
|
|
||||||
internal var Caret.markStorage: LocalMarkStorage? by userDataCaretToEditor()
|
internal var Caret.markStorage: LocalMarkStorage? by userDataCaretToEditor()
|
||||||
internal var Caret.lastSelectionInfo: SelectionInfo? by userDataCaretToEditor()
|
internal var Caret.lastSelectionInfo: SelectionInfo? by userDataCaretToEditor()
|
||||||
|
|
||||||
|
@ -1,32 +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.helper
|
|
||||||
|
|
||||||
import com.intellij.ide.plugins.StandalonePluginUpdateChecker
|
|
||||||
import com.intellij.openapi.components.Service
|
|
||||||
import com.intellij.openapi.components.service
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
|
||||||
import com.maddyhome.idea.vim.group.NotificationService
|
|
||||||
import com.maddyhome.idea.vim.icons.VimIcons
|
|
||||||
|
|
||||||
@Service(Service.Level.APP)
|
|
||||||
internal class VimStandalonePluginUpdateChecker : StandalonePluginUpdateChecker(
|
|
||||||
VimPlugin.getPluginId(),
|
|
||||||
updateTimestampProperty = PROPERTY_NAME,
|
|
||||||
NotificationService.IDEAVIM_STICKY_GROUP,
|
|
||||||
VimIcons.IDEAVIM,
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun skipUpdateCheck(): Boolean = VimPlugin.isNotEnabled() || "dev" in VimPlugin.getVersion()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PROPERTY_NAME = "ideavim.statistics.timestamp"
|
|
||||||
val instance: VimStandalonePluginUpdateChecker = service()
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,16 +10,16 @@ package com.maddyhome.idea.vim.listener
|
|||||||
|
|
||||||
import com.intellij.execution.impl.ConsoleViewImpl
|
import com.intellij.execution.impl.ConsoleViewImpl
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.EditorKind
|
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
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.injector
|
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.common.EditorListener
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper
|
|
||||||
import com.maddyhome.idea.vim.helper.inInsertMode
|
import com.maddyhome.idea.vim.helper.inInsertMode
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
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,
|
* This listener is similar to the one we introduce in vim-engine to handle focus change,
|
||||||
@ -29,6 +29,11 @@ import com.maddyhome.idea.vim.newapi.ij
|
|||||||
*/
|
*/
|
||||||
class IJEditorFocusListener : EditorListener {
|
class IJEditorFocusListener : EditorListener {
|
||||||
override fun focusGained(editor: VimEditor) {
|
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
|
// 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
|
// 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
|
// viewers for text output, such as log files in run configurations or the Git Console tab. And editors are used for
|
||||||
@ -48,17 +53,21 @@ class IJEditorFocusListener : EditorListener {
|
|||||||
// not file based, is writable, and not a viewer, but we don't want to treat this as an interactive editor.
|
// 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
|
// 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.
|
// 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 switchToInsertMode = Runnable {
|
||||||
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||||
VimPlugin.getChange().insertBeforeCursor(editor, context)
|
VimPlugin.getChange().insertBeforeCursor(editor, context)
|
||||||
}
|
}
|
||||||
val ijEditor = editor.ij
|
if (!ijEditor.document.isWritable) {
|
||||||
if (!ijEditor.isViewer &&
|
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||||
!EditorHelper.isFileEditor(ijEditor) &&
|
val mode = injector.vimState.mode
|
||||||
ijEditor.document.isWritable &&
|
when (mode) {
|
||||||
!ijEditor.inInsertMode && ijEditor.editorKind != EditorKind.DIFF
|
is Mode.INSERT -> editor.exitInsertMode(context, OperatorArguments(false, 0, mode))
|
||||||
) {
|
else -> {}
|
||||||
switchToInsertMode.run()
|
}
|
||||||
}
|
}
|
||||||
ApplicationManager.getApplication().invokeLater {
|
ApplicationManager.getApplication().invokeLater {
|
||||||
if (ijEditor.isDisposed) return@invokeLater
|
if (ijEditor.isDisposed) return@invokeLater
|
||||||
|
@ -28,6 +28,8 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
|
|||||||
import com.intellij.openapi.actionSystem.ex.AnActionListener
|
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.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
|
||||||
@ -37,6 +39,7 @@ 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.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
|
||||||
@ -56,21 +59,41 @@ internal object IdeaSpecifics {
|
|||||||
private val surrounderAction =
|
private val surrounderAction =
|
||||||
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
|
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
|
||||||
private var editor: Editor? = null
|
private var editor: Editor? = null
|
||||||
|
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
|
||||||
|
|
||||||
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
|
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
|
||||||
if (hostEditor != null) {
|
if (hostEditor != null) {
|
||||||
editor = hostEditor
|
editor = hostEditor
|
||||||
|
caretOffset = hostEditor.caretModel.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
|
val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
|
||||||
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
|
||||||
VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
|
val candidates = if (id == null) {
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +118,8 @@ internal object IdeaSpecifics {
|
|||||||
if (VimPlugin.isNotEnabled()) return
|
if (VimPlugin.isNotEnabled()) return
|
||||||
|
|
||||||
val editor = editor
|
val editor = editor
|
||||||
if (editor != null && action is ChooseItemAction && injector.registerGroup.isRecording) {
|
if (editor != null) {
|
||||||
|
if (action is ChooseItemAction && injector.registerGroup.isRecording) {
|
||||||
val prevDocumentLength = completionPrevDocumentLength
|
val prevDocumentLength = completionPrevDocumentLength
|
||||||
val prevDocumentOffset = completionPrevDocumentOffset
|
val prevDocumentOffset = completionPrevDocumentOffset
|
||||||
|
|
||||||
@ -130,7 +154,21 @@ internal object IdeaSpecifics {
|
|||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
|
||||||
|
val scrollModel = editor.scrollingModel as ScrollingModelImpl
|
||||||
|
if (scrollModel.isScrollingNow) {
|
||||||
|
val v = scrollModel.verticalScrollOffset
|
||||||
|
val h = scrollModel.horizontalScrollOffset
|
||||||
|
scrollModel.finishAnimation()
|
||||||
|
scrollModel.scroll(h, v)
|
||||||
|
scrollModel.finishAnimation()
|
||||||
|
}
|
||||||
|
injector.scroll.scrollCaretIntoView(editor.vim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.editor = null
|
this.editor = null
|
||||||
|
this.caretOffset = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,9 +245,13 @@ 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 = injector.globalIjOptions().trackactionids
|
override fun isSelected(e: AnActionEvent): Boolean {
|
||||||
|
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-2023 The IdeaVim authors
|
* Copyright 2003-2024 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,7 +9,18 @@
|
|||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import com.intellij.openapi.editor.ex.DocumentEx
|
|||||||
import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
|
import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
|
||||||
import com.intellij.openapi.editor.ex.FocusChangeListener
|
import com.intellij.openapi.editor.ex.FocusChangeListener
|
||||||
import com.intellij.openapi.editor.impl.EditorComponentImpl
|
import com.intellij.openapi.editor.impl.EditorComponentImpl
|
||||||
|
import com.intellij.openapi.editor.impl.EditorImpl
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||||
@ -45,11 +46,14 @@ import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
|
|||||||
import com.intellij.openapi.fileEditor.impl.EditorComposite
|
import com.intellij.openapi.fileEditor.impl.EditorComposite
|
||||||
import com.intellij.openapi.fileEditor.impl.EditorWindow
|
import com.intellij.openapi.fileEditor.impl.EditorWindow
|
||||||
import com.intellij.openapi.project.ProjectManager
|
import com.intellij.openapi.project.ProjectManager
|
||||||
|
import com.intellij.openapi.rd.createLifetime
|
||||||
|
import com.intellij.openapi.rd.createNestedDisposable
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.removeUserData
|
import com.intellij.openapi.util.removeUserData
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.util.ExceptionUtil
|
import com.intellij.util.ExceptionUtil
|
||||||
|
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.VimKeyListener
|
import com.maddyhome.idea.vim.VimKeyListener
|
||||||
@ -79,7 +83,6 @@ import com.maddyhome.idea.vim.handler.keyCheckRequests
|
|||||||
import com.maddyhome.idea.vim.helper.CaretVisualAttributesListener
|
import com.maddyhome.idea.vim.helper.CaretVisualAttributesListener
|
||||||
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
|
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
|
||||||
import com.maddyhome.idea.vim.helper.StrictMode
|
import com.maddyhome.idea.vim.helper.StrictMode
|
||||||
import com.maddyhome.idea.vim.helper.VimStandalonePluginUpdateChecker
|
|
||||||
import com.maddyhome.idea.vim.helper.exitSelectMode
|
import com.maddyhome.idea.vim.helper.exitSelectMode
|
||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||||
import com.maddyhome.idea.vim.helper.forceBarCursor
|
import com.maddyhome.idea.vim.helper.forceBarCursor
|
||||||
@ -91,10 +94,11 @@ 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.InsertTimeRecorder
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
|
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
|
||||||
|
import com.maddyhome.idea.vim.newapi.InsertTimeRecorder
|
||||||
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.inSelectMode
|
import com.maddyhome.idea.vim.state.mode.inSelectMode
|
||||||
import com.maddyhome.idea.vim.state.mode.selectionType
|
import com.maddyhome.idea.vim.state.mode.selectionType
|
||||||
import com.maddyhome.idea.vim.ui.ShowCmdOptionChangeListener
|
import com.maddyhome.idea.vim.ui.ShowCmdOptionChangeListener
|
||||||
@ -103,7 +107,6 @@ import com.maddyhome.idea.vim.ui.widgets.macro.MacroWidgetListener
|
|||||||
import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
|
import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
|
||||||
import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
|
import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
|
||||||
import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
|
import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
|
||||||
import com.maddyhome.idea.vim.vimDisposable
|
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
@ -158,6 +161,7 @@ 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()
|
||||||
@ -284,12 +288,10 @@ internal object VimListenerManager {
|
|||||||
// TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
|
// TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
|
||||||
if (vimDisabled(editor)) return
|
if (vimDisabled(editor)) return
|
||||||
|
|
||||||
// As I understand, there is no need to pass a disposable that also disposes on editor close
|
val pluginLifetime = VimPlugin.getInstance().createLifetime()
|
||||||
// because all editor resources will be garbage collected anyway on editor close
|
val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
|
||||||
// Note that this uses the plugin's main disposable, rather than VimPlugin.onOffDisposable, because we don't need
|
val disposable =
|
||||||
// to - we explicitly call VimListenerManager.removeAll from VimPlugin.turnOffPlugin, and this disposes each
|
Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
|
||||||
// editor's disposable individually.
|
|
||||||
val disposable = editor.project?.vimDisposable ?: return
|
|
||||||
|
|
||||||
// Protect against double initialisation
|
// Protect against double initialisation
|
||||||
if (editor.getUserData(editorListenersDisposableKey) != null) {
|
if (editor.getUserData(editorListenersDisposableKey) != null) {
|
||||||
@ -386,6 +388,16 @@ internal object VimListenerManager {
|
|||||||
// We can't rely on being passed a non-null editor, so check for Code With Me scenarios explicitly
|
// We can't rely on being passed a non-null editor, so check for Code With Me scenarios explicitly
|
||||||
if (VimPlugin.isNotEnabled() || !ClientId.isCurrentlyUnderLocalId) return
|
if (VimPlugin.isNotEnabled() || !ClientId.isCurrentlyUnderLocalId) return
|
||||||
|
|
||||||
|
val newEditor = event.newEditor
|
||||||
|
if (newEditor is TextEditor) {
|
||||||
|
val editor = newEditor.editor
|
||||||
|
if (editor.isInsertMode) {
|
||||||
|
editor.vim.mode = Mode.NORMAL()
|
||||||
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
|
}
|
||||||
|
injector.scroll.scrollCaretIntoView(editor.vim)
|
||||||
|
}
|
||||||
|
|
||||||
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
FileGroup.fileEditorManagerSelectionChangedCallback(event)
|
FileGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
|
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
|
||||||
@ -457,8 +469,6 @@ internal object VimListenerManager {
|
|||||||
|
|
||||||
event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
|
event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
|
||||||
}
|
}
|
||||||
|
|
||||||
VimStandalonePluginUpdateChecker.instance.pluginUsed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun editorReleased(event: EditorFactoryEvent) {
|
override fun editorReleased(event: EditorFactoryEvent) {
|
||||||
@ -735,10 +745,8 @@ internal object VimListenerManager {
|
|||||||
|
|
||||||
if (event.area == EditorMouseEventArea.EDITING_AREA) {
|
if (event.area == EditorMouseEventArea.EDITING_AREA) {
|
||||||
val editor = event.editor
|
val editor = event.editor
|
||||||
val commandLine = injector.commandLine.getActiveCommandLine()
|
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
||||||
if (commandLine != null) {
|
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
||||||
injector.processGroup.cancelExEntry(editor.vim, refocusOwningEditor = true, resetCaret = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExOutputModel.tryGetInstance(editor)?.close()
|
ExOutputModel.tryGetInstance(editor)?.close()
|
||||||
|
|
||||||
@ -766,10 +774,8 @@ 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
|
||||||
) {
|
) {
|
||||||
val commandLine = injector.commandLine.getActiveCommandLine()
|
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
||||||
if (commandLine != null) {
|
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
||||||
injector.processGroup.cancelExEntry(event.editor.vim, refocusOwningEditor = true, resetCaret = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExOutputModel.getInstance(event.editor).close()
|
ExOutputModel.getInstance(event.editor).close()
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@ 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(context: ExecutionContext) {
|
internal fun NativeAction?.execute(editor: VimEditor, context: ExecutionContext) {
|
||||||
if (this == null) return
|
if (this == null) return
|
||||||
injector.actionExecutor.executeAction(null, this, context)
|
injector.actionExecutor.executeAction(editor, this, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val VisualPosition.vim: VimVisualPosition
|
internal val VisualPosition.vim: VimVisualPosition
|
||||||
|
@ -12,8 +12,6 @@ import com.intellij.openapi.editor.Caret
|
|||||||
import com.intellij.openapi.editor.LogicalPosition
|
import com.intellij.openapi.editor.LogicalPosition
|
||||||
import com.intellij.openapi.editor.VisualPosition
|
import com.intellij.openapi.editor.VisualPosition
|
||||||
import com.maddyhome.idea.vim.api.BufferPosition
|
import com.maddyhome.idea.vim.api.BufferPosition
|
||||||
import com.maddyhome.idea.vim.api.CaretRegisterStorage
|
|
||||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
|
|
||||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
||||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||||
@ -29,7 +27,6 @@ import com.maddyhome.idea.vim.helper.insertHistory
|
|||||||
import com.maddyhome.idea.vim.helper.lastSelectionInfo
|
import com.maddyhome.idea.vim.helper.lastSelectionInfo
|
||||||
import com.maddyhome.idea.vim.helper.markStorage
|
import com.maddyhome.idea.vim.helper.markStorage
|
||||||
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
|
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
|
||||||
import com.maddyhome.idea.vim.helper.registerStorage
|
|
||||||
import com.maddyhome.idea.vim.helper.resetVimLastColumn
|
import com.maddyhome.idea.vim.helper.resetVimLastColumn
|
||||||
import com.maddyhome.idea.vim.helper.vimInsertStart
|
import com.maddyhome.idea.vim.helper.vimInsertStart
|
||||||
import com.maddyhome.idea.vim.helper.vimLastColumn
|
import com.maddyhome.idea.vim.helper.vimLastColumn
|
||||||
@ -41,17 +38,6 @@ import com.maddyhome.idea.vim.state.mode.SelectionType
|
|||||||
|
|
||||||
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
|
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
|
||||||
|
|
||||||
override val registerStorage: CaretRegisterStorage
|
|
||||||
get() {
|
|
||||||
var storage = this.caret.registerStorage
|
|
||||||
if (storage == null) {
|
|
||||||
storage = CaretRegisterStorageBase(this)
|
|
||||||
this.caret.registerStorage = storage
|
|
||||||
} else if (storage.caret != this) {
|
|
||||||
storage.caret = this
|
|
||||||
}
|
|
||||||
return storage
|
|
||||||
}
|
|
||||||
override val markStorage: LocalMarkStorage
|
override val markStorage: LocalMarkStorage
|
||||||
get() {
|
get() {
|
||||||
var storage = this.caret.markStorage
|
var storage = this.caret.markStorage
|
||||||
|
@ -30,7 +30,9 @@ 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
|
||||||
@ -38,6 +40,7 @@ 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
|
||||||
@ -52,6 +55,7 @@ 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
|
||||||
@ -59,7 +63,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() {
|
internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase() {
|
||||||
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
|
||||||
@ -72,12 +76,22 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
|
|||||||
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()
|
||||||
|
|
||||||
@ -119,7 +133,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
||||||
if (editor.isInsertMode) {
|
if (injector.vimState.mode is Mode.INSERT) {
|
||||||
injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
||||||
}
|
}
|
||||||
editor.document.insertString(atPosition, text)
|
editor.document.insertString(atPosition, text)
|
||||||
@ -151,21 +165,38 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
|
|||||||
return editor.caretModel.allCarets.map { IjVimCaret(it) }
|
return editor.caretModel.allCarets.map { IjVimCaret(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var isFirstCaret = true
|
||||||
|
override var isReversingCarets = false
|
||||||
|
|
||||||
@Suppress("ideavimRunForEachCaret")
|
@Suppress("ideavimRunForEachCaret")
|
||||||
override fun forEachCaret(action: (VimCaret) -> Unit) {
|
override fun forEachCaret(action: (VimCaret) -> Unit) {
|
||||||
if (editor.vim.inBlockSelection) {
|
if (editor.vim.inBlockSelection) {
|
||||||
action(IjVimCaret(editor.caretModel.primaryCaret))
|
action(IjVimCaret(editor.caretModel.primaryCaret))
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
editor.caretModel.runForEachCaret({
|
editor.caretModel.runForEachCaret({
|
||||||
if (it.isValid) {
|
if (it.isValid) {
|
||||||
action(IjVimCaret(it))
|
action(IjVimCaret(it))
|
||||||
|
isFirstCaret = false
|
||||||
}
|
}
|
||||||
}, false)
|
}, false)
|
||||||
|
} finally {
|
||||||
|
isFirstCaret = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
|
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
|
||||||
editor.caretModel.runForEachCaret({ action(IjVimCaret(it)) }, reverse)
|
isReversingCarets = reverse
|
||||||
|
try {
|
||||||
|
editor.caretModel.runForEachCaret({
|
||||||
|
action(IjVimCaret(it))
|
||||||
|
isFirstCaret = false
|
||||||
|
}, reverse)
|
||||||
|
} finally {
|
||||||
|
isFirstCaret = true
|
||||||
|
isReversingCarets = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isInForEachCaretScope(): Boolean {
|
override fun isInForEachCaretScope(): Boolean {
|
||||||
@ -433,7 +464,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
|
|||||||
// 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.bufferLineToVisualLine(line)
|
return super<MutableLinearEditor>.bufferLineToVisualLine(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var insertMode: Boolean
|
override var insertMode: Boolean
|
||||||
|
@ -22,6 +22,7 @@ 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
|
||||||
@ -36,6 +37,7 @@ 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.VimOutputPanelService
|
||||||
@ -56,8 +58,9 @@ 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
|
||||||
@ -83,6 +86,7 @@ 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
|
||||||
@ -90,6 +94,16 @@ 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))
|
||||||
|
|
||||||
@ -183,6 +197,8 @@ 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
|
override val outputPanel: VimOutputPanelService
|
||||||
get() = service()
|
get() = service()
|
||||||
|
|
||||||
|
@ -97,59 +97,6 @@ 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,
|
||||||
|
@ -19,11 +19,16 @@ 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,11 +13,16 @@ 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 {
|
||||||
val instance = service<Troubleshooter>()
|
fun getInstance() = service<Troubleshooter>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ 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;
|
||||||
@ -46,12 +47,11 @@ 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;
|
||||||
|
|
||||||
private final @NotNull JLabel myLabel = new JLabel("more");
|
public 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;
|
||||||
@ -224,42 +224,31 @@ public class ExOutputPanel extends JPanel {
|
|||||||
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
myLabel.setFont(UiHelper.selectEditorFont(myEditor, myLabel.getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollLine() {
|
public void scrollLine() {
|
||||||
scrollOffset(myLineHeight);
|
scrollOffset(myLineHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollPage() {
|
public void scrollPage() {
|
||||||
scrollOffset(myScrollPane.getVerticalScrollBar().getVisibleAmount());
|
scrollOffset(myScrollPane.getVerticalScrollBar().getVisibleAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollHalfPage() {
|
public 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleEnter() {
|
public void onBadKey() {
|
||||||
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 {
|
||||||
@ -268,6 +257,11 @@ 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);
|
||||||
@ -308,14 +302,13 @@ public class ExOutputPanel extends JPanel {
|
|||||||
close(null);
|
close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close(final @Nullable KeyEvent e) {
|
public void close(final @Nullable KeyStroke key) {
|
||||||
ApplicationManager.getApplication().invokeLater(() -> {
|
ApplicationManager.getApplication().invokeLater(() -> {
|
||||||
deactivate(true);
|
deactivate(true);
|
||||||
|
|
||||||
final Project project = myEditor.getProject();
|
final Project project = myEditor.getProject();
|
||||||
|
|
||||||
if (project != null && e != null && e.getKeyChar() != '\n') {
|
if (project != null && key != null && key.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()) {
|
||||||
@ -324,7 +317,9 @@ 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));
|
||||||
VimPlugin.getMacro().playbackKeys(new IjVimEditor(myEditor), context, 1);
|
injector.getApplication().runWriteAction(() -> { VimPlugin.getMacro().playbackKeys(new IjVimEditor(myEditor), context, 1);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -341,40 +336,14 @@ public class ExOutputPanel extends JPanel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void keyTyped(@NotNull KeyEvent e) {
|
public void keyTyped(@NotNull KeyEvent e) {
|
||||||
if (myExOutputPanel.myAtEnd) {
|
VimOutputPanel currentPanel = injector.getOutputPanel().getCurrentOutputPanel();
|
||||||
myExOutputPanel.close(e);
|
if (currentPanel == null) return;
|
||||||
}
|
|
||||||
else {
|
int keyCode = e.getKeyCode();
|
||||||
switch (e.getKeyChar()) {
|
Character keyChar = e.getKeyChar();
|
||||||
case ' ':
|
int modifiers = e.getModifiersEx();
|
||||||
myExOutputPanel.scrollPage();
|
KeyStroke keyStroke = (keyChar == KeyEvent.CHAR_UNDEFINED) ? KeyStroke.getKeyStroke(keyCode, modifiers) : KeyStroke.getKeyStroke(keyChar, modifiers);
|
||||||
break;
|
currentPanel.handleKey(keyStroke);
|
||||||
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.instance.removeByType("old-action-notation-in-mappings")
|
Troubleshooter.getInstance().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,7 +20,6 @@ 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
|
||||||
@ -28,6 +27,7 @@ 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,6 +72,11 @@ 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
|
||||||
@ -81,7 +86,6 @@ 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*/ {
|
||||||
private const val EAP_LINK = "https://plugins.jetbrains.com/plugins/eap/ideavim"
|
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
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ package com.maddyhome.idea.vim.ui.ex
|
|||||||
import com.intellij.openapi.diagnostic.debug
|
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
|
||||||
@ -119,7 +120,8 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
val c = key.keyChar
|
val c = key.keyChar
|
||||||
if (c.code > 0) {
|
if (c.code > 0) {
|
||||||
if (target.useHandleKeyFromEx) {
|
if (target.useHandleKeyFromEx) {
|
||||||
val entry = ExEntryPanel.getInstance().entry
|
val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
|
||||||
|
val entry = panel.entry
|
||||||
val editor = entry.editor
|
val editor = entry.editor
|
||||||
val keyHandler = KeyHandler.getInstance()
|
val keyHandler = KeyHandler.getInstance()
|
||||||
keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
|
keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
|
||||||
|
@ -23,12 +23,11 @@ import com.maddyhome.idea.vim.EventFacade;
|
|||||||
import com.maddyhome.idea.vim.KeyHandler;
|
import com.maddyhome.idea.vim.KeyHandler;
|
||||||
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.api.VimCommandLine;
|
import com.maddyhome.idea.vim.api.*;
|
||||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
|
|
||||||
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;
|
||||||
@ -36,6 +35,8 @@ 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;
|
||||||
@ -62,6 +63,10 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
private 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();
|
||||||
@ -79,7 +84,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
layout.setConstraints(entry, gbc);
|
layout.setConstraints(entry, gbc);
|
||||||
add(entry);
|
add(entry);
|
||||||
|
|
||||||
if (enableShortcuts) {
|
|
||||||
// This does not need to be unregistered, it's registered as a custom UI property on this
|
// This does not need to be unregistered, it's registered as a custom UI property on this
|
||||||
EventFacade.getInstance().registerCustomShortcutSet(
|
EventFacade.getInstance().registerCustomShortcutSet(
|
||||||
VimShortcutKeyAction.getInstance(),
|
VimShortcutKeyAction.getInstance(),
|
||||||
@ -87,7 +91,6 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
entry
|
entry
|
||||||
);
|
);
|
||||||
new ExShortcutKeyAction(this).registerCustomShortcutSet();
|
new ExShortcutKeyAction(this).registerCustomShortcutSet();
|
||||||
}
|
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@ -127,10 +130,18 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Editor getEditor() {
|
public @Nullable Editor getIjEditor() {
|
||||||
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;
|
||||||
@ -139,6 +150,14 @@ 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
|
||||||
*
|
*
|
||||||
@ -249,6 +268,9 @@ 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() {
|
||||||
@ -273,7 +295,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(getEditor(), text);
|
Font newFont = UiHelper.selectEditorFont(getIjEditor(), text);
|
||||||
if (newFont != entry.getFont()) {
|
if (newFont != entry.getFont()) {
|
||||||
entry.setFont(newFont);
|
entry.setFont(newFont);
|
||||||
}
|
}
|
||||||
@ -392,6 +414,14 @@ 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();
|
||||||
@ -409,6 +439,10 @@ 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
|
||||||
@ -446,8 +480,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setFontForElements() {
|
private void setFontForElements() {
|
||||||
label.setFont(UiHelper.selectEditorFont(getEditor(), label.getText()));
|
label.setFont(UiHelper.selectEditorFont(getIjEditor(), label.getText()));
|
||||||
entry.setFont(UiHelper.selectEditorFont(getEditor(), getVisibleText()));
|
entry.setFont(UiHelper.selectEditorFont(getIjEditor(), getVisibleText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionPanel() {
|
private void positionPanel() {
|
||||||
@ -535,6 +569,32 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
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,25 +11,33 @@ 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.VimCommandLineService
|
import com.maddyhome.idea.vim.api.VimCommandLineCaret
|
||||||
|
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.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.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 : VimCommandLineService {
|
class ExEntryPanelService : VimCommandLineServiceBase(), VimModalInputService {
|
||||||
override fun getActiveCommandLine(): VimCommandLine? {
|
override fun getActiveCommandLine(): VimCommandLine? {
|
||||||
val instance = ExEntryPanel.instance ?: ExEntryPanel.instanceWithoutShortcuts ?: return null
|
val instance = ExEntryPanel.instance ?: return null
|
||||||
return if (instance.isActive) instance else null
|
return if (instance.isActive) instance else null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inputString(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?): String? {
|
@Deprecated("Please use readInputAndProcess")
|
||||||
|
fun inputString(vimEditor: VimEditor, context: ExecutionContext, prompt: String, finishOn: Char?): String? {
|
||||||
val editor = vimEditor.ij
|
val editor = vimEditor.ij
|
||||||
if (vimEditor.inRepeatMode) {
|
if (vimEditor.inRepeatMode) {
|
||||||
val input = Extension.consumeString()
|
val input = Extension.consumeString()
|
||||||
@ -58,7 +66,7 @@ class ExEntryPanelService : VimCommandLineService {
|
|||||||
} 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.create(vimEditor, context, prompt.ifEmpty { " " }, "")
|
val commandLine = injector.commandLine.createSearchPrompt(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() -> {
|
||||||
@ -89,7 +97,40 @@ class ExEntryPanelService : VimCommandLineService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun create(editor: VimEditor, context: ExecutionContext, label: String, initText: String): VimCommandLine {
|
override fun readInputAndProcess(
|
||||||
|
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
|
||||||
@ -104,4 +145,31 @@ class ExEntryPanelService : VimCommandLineService {
|
|||||||
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()
|
||||||
|
}
|
||||||
}
|
}
|
@ -16,6 +16,7 @@ import com.intellij.util.ui.JBUI;
|
|||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
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.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;
|
||||||
@ -211,7 +212,7 @@ public class ExTextField extends JTextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Editor getEditor() {
|
public @Nullable Editor getEditor() {
|
||||||
return ExEntryPanel.getInstance().getEditor();
|
return ExEntryPanel.getInstance().getIjEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataContext getContext() {
|
public DataContext getContext() {
|
||||||
@ -291,9 +292,9 @@ public class ExTextField extends JTextField {
|
|||||||
*/
|
*/
|
||||||
void cancel() {
|
void cancel() {
|
||||||
clearCurrentAction();
|
clearCurrentAction();
|
||||||
Editor editor = ExEntryPanel.instance.getEditor();
|
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
||||||
if (editor != null) {
|
if (commandLine != null) {
|
||||||
VimPlugin.getProcess().cancelExEntry(new IjVimEditor(editor), true, true);
|
commandLine.close(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +352,8 @@ 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,6 +31,16 @@ 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()
|
||||||
}
|
}
|
||||||
@ -83,6 +93,7 @@ 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 {
|
||||||
|
@ -39,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 = VimPlugin.getProcess().lastCommand
|
val last = 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
|
||||||
@ -76,6 +76,7 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
|
VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
|
||||||
ExOutputModel.getInstance(editor.ij).output(it)
|
ExOutputModel.getInstance(editor.ij).output(it)
|
||||||
}
|
}
|
||||||
|
lastCommand = command
|
||||||
ExecutionResult.Success
|
ExecutionResult.Success
|
||||||
} else {
|
} else {
|
||||||
// Filter
|
// Filter
|
||||||
@ -92,6 +93,7 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lastCommand = command
|
||||||
ExecutionResult.Success
|
ExecutionResult.Success
|
||||||
}
|
}
|
||||||
} catch (e: ProcessCanceledException) {
|
} catch (e: ProcessCanceledException) {
|
||||||
@ -103,5 +105,6 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
<!--
|
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
~ 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<name>IdeaVim</name>
|
<name>IdeaVim</name>
|
||||||
<id>IdeaVIM</id>
|
<id>IdeaVIM</id>
|
||||||
<description><![CDATA[
|
<description><![CDATA[
|
||||||
@ -21,7 +13,7 @@
|
|||||||
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
|
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
|
||||||
</ul>
|
</ul>
|
||||||
]]></description>
|
]]></description>
|
||||||
<version>SNAPSHOT</version>
|
<version>chylex</version>
|
||||||
<vendor>JetBrains</vendor>
|
<vendor>JetBrains</vendor>
|
||||||
|
|
||||||
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
||||||
@ -154,5 +146,6 @@
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
|
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
|
||||||
|
<action id="VimJumpToSource" class="com.intellij.diff.actions.impl.OpenInEditorAction" />
|
||||||
</actions>
|
</actions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
@ -100,8 +100,8 @@ action.not.found.0=Action not found: {0}
|
|||||||
|
|
||||||
action.CustomizeModeWidget.text=Mode Widget Settings
|
action.CustomizeModeWidget.text=Mode Widget Settings
|
||||||
|
|
||||||
action.VimFindActionIdAction.text=IdeaVim: Track Action Ids
|
action.VimFindActionIdAction.text=IdeaVim: Track Action IDs
|
||||||
action.VimFindActionIdAction.description=Starts tracking ids of executed actions
|
action.VimFindActionIdAction.description=Starts tracking IDs of executed actions
|
||||||
|
|
||||||
ex.show.all.actions.0.1=--- Actions ---{0}{1}
|
ex.show.all.actions.0.1=--- Actions ---{0}{1}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class ChangeActionTest : VimTestCase() {
|
|||||||
listOf("i", "<C-O>", "v", "<esc>"),
|
listOf("i", "<C-O>", "v", "<esc>"),
|
||||||
"12${c}345",
|
"12${c}345",
|
||||||
"12${c}345",
|
"12${c}345",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ Mode.INSERT,
|
|||||||
listOf("i", "<C-O>", "v", "d"),
|
listOf("i", "<C-O>", "v", "d"),
|
||||||
"12${c}345",
|
"12${c}345",
|
||||||
"12${c}45",
|
"12${c}45",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ Mode.INSERT,
|
|||||||
listOf("i", "<C-O>", "gh", "<esc>"),
|
listOf("i", "<C-O>", "gh", "<esc>"),
|
||||||
"12${c}345",
|
"12${c}345",
|
||||||
"123${c}45",
|
"123${c}45",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ Mode.INSERT,
|
|||||||
listOf("i", "<C-O>", "gh", "d"),
|
listOf("i", "<C-O>", "gh", "d"),
|
||||||
"12${c}345",
|
"12${c}345",
|
||||||
"12d${c}45",
|
"12d${c}45",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ Mode.INSERT,
|
|||||||
listOf("i", "def", "<C-O>", "d2h", "x"),
|
listOf("i", "def", "<C-O>", "d2h", "x"),
|
||||||
"abc$c.\n",
|
"abc$c.\n",
|
||||||
"abcdx.\n",
|
"abcdx.\n",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ Mode.INSERT,
|
|||||||
four
|
four
|
||||||
|
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +405,7 @@ Mode.INSERT,
|
|||||||
listOf("A", ", ", "<C-R>", "a", "!"),
|
listOf("A", ", ", "<C-R>", "a", "!"),
|
||||||
"${c}Hello\n",
|
"${c}Hello\n",
|
||||||
"Hello, World!\n",
|
"Hello, World!\n",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +416,7 @@ Mode.INSERT,
|
|||||||
listOf("O", "bar"),
|
listOf("O", "bar"),
|
||||||
"fo${c}o\n",
|
"fo${c}o\n",
|
||||||
"bar\nfoo\n",
|
"bar\nfoo\n",
|
||||||
Mode.INSERT,
|
Mode.INSERT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,7 +738,7 @@ class MotionActionTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun testDeleteToEndOfSearchResultInclusive() {
|
fun testDeleteToEndOfSearchResultInclusive() {
|
||||||
val before = "Lorem ${c}ipsum dolor sit amet, consectetur adipiscing elit"
|
val before = "Lorem ${c}ipsum dolor sit amet, consectetur adipiscing elit"
|
||||||
val after = "Lorem ${c} amet, consectetur adipiscing elit"
|
val after = "Lorem $c amet, consectetur adipiscing elit"
|
||||||
doTest("d/sit/e<CR>", before, after)
|
doTest("d/sit/e<CR>", before, after)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,6 +766,11 @@ class MotionActionTest : VimTestCase() {
|
|||||||
doTest(keys, before, after, Mode.NORMAL())
|
doTest(keys, before, after, Mode.NORMAL())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDeleteToLiteral() {
|
||||||
|
doTest("d/<C-V>333<CR>", "ab${c}cdōef", "abōef")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDeleteBackwardsToSearchResult() {
|
fun testDeleteBackwardsToSearchResult() {
|
||||||
val before = "Lorem ipsum dolor sit amet, ${c}consectetur adipiscing elit"
|
val before = "Lorem ipsum dolor sit amet, ${c}consectetur adipiscing elit"
|
||||||
|
@ -13,7 +13,6 @@ import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
|
|||||||
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.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
|
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@ -2173,7 +2172,7 @@ rtyfg${c}hzxc"""
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
injector.registerGroup.storeText('*', "fgh")
|
injector.registerGroup.storeText('*', "fgh")
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(IjVimEditor(editor), editor.vim.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(IjVimEditor(editor), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("\"*P"))
|
typeText(injector.parser.parseKeys("\"*P"))
|
||||||
val after = "fg${c}hqfg${c}hwe asd zxc rty fg${c}hfgh vbn"
|
val after = "fg${c}hqfg${c}hwe asd zxc rty fg${c}hfgh vbn"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
|
@ -9,8 +9,11 @@
|
|||||||
package org.jetbrains.plugins.ideavim.action.change
|
package org.jetbrains.plugins.ideavim.action.change
|
||||||
|
|
||||||
import com.intellij.idea.TestFor
|
import com.intellij.idea.TestFor
|
||||||
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
|
import org.junit.jupiter.api.Assumptions.assumeTrue
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
class UndoActionTest : VimTestCase() {
|
class UndoActionTest : VimTestCase() {
|
||||||
@ -109,6 +112,7 @@ class UndoActionTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
@TestFor(issues = ["VIM-547"])
|
@TestFor(issues = ["VIM-547"])
|
||||||
fun `test typed text requires one undo`() {
|
fun `test typed text requires one undo`() {
|
||||||
|
assumeTrue(!injector.globalIjOptions().oldundo)
|
||||||
configureByText("Lorem ipsu${c}m")
|
configureByText("Lorem ipsu${c}m")
|
||||||
typeText("a dolor sit amet,<CR>consectetur adipiscing elit<Esc>")
|
typeText("a dolor sit amet,<CR>consectetur adipiscing elit<Esc>")
|
||||||
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit")
|
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit")
|
||||||
@ -119,6 +123,7 @@ class UndoActionTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
@TestFor(issues = ["VIM-547"])
|
@TestFor(issues = ["VIM-547"])
|
||||||
fun `test breaking insert sequence`() {
|
fun `test breaking insert sequence`() {
|
||||||
|
assumeTrue(!injector.globalIjOptions().oldundo)
|
||||||
configureByText("Lorem ipsu${c}m")
|
configureByText("Lorem ipsu${c}m")
|
||||||
typeText("a dolor sit amet,<CR>consectetur <C-G>uadipiscing elit<Esc>")
|
typeText("a dolor sit amet,<CR>consectetur <C-G>uadipiscing elit<Esc>")
|
||||||
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit")
|
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit")
|
||||||
@ -129,6 +134,7 @@ class UndoActionTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
@TestFor(issues = ["VIM-547"])
|
@TestFor(issues = ["VIM-547"])
|
||||||
fun `test moving caret breaks insert sequence`() {
|
fun `test moving caret breaks insert sequence`() {
|
||||||
|
assumeTrue(!injector.globalIjOptions().oldundo)
|
||||||
configureByText("Lorem ipsu${c}m")
|
configureByText("Lorem ipsu${c}m")
|
||||||
typeText("a dolor sit amet,<CR>consectetur <Left>adipiscing elit<Esc>")
|
typeText("a dolor sit amet,<CR>consectetur <Left>adipiscing elit<Esc>")
|
||||||
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit ")
|
assertState("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit ")
|
||||||
@ -140,7 +146,17 @@ class UndoActionTest : VimTestCase() {
|
|||||||
@TestFor(issues = ["VIM-547"])
|
@TestFor(issues = ["VIM-547"])
|
||||||
fun `test change action is included in insert sequence`() {
|
fun `test change action is included in insert sequence`() {
|
||||||
configureByText("Lorem ${c}ipsum dolor sit amet")
|
configureByText("Lorem ${c}ipsum dolor sit amet")
|
||||||
typeText("celorem")
|
typeText("celorem<Esc>")
|
||||||
|
assertState("Lorem lore${c}m dolor sit amet")
|
||||||
|
typeText("u")
|
||||||
|
assertState("Lorem ${c}ipsum dolor sit amet")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestFor(issues = ["VIM-3552"])
|
||||||
|
fun `test paste is not part of undo sequence`() {
|
||||||
|
configureByText("test")
|
||||||
|
typeText("yypoxxxu")
|
||||||
configureByText("Lorem lorem${c} dolor sit amet")
|
configureByText("Lorem lorem${c} dolor sit amet")
|
||||||
typeText("u")
|
typeText("u")
|
||||||
configureByText("Lorem ${c}ipsum dolor sit amet")
|
configureByText("Lorem ${c}ipsum dolor sit amet")
|
||||||
|
@ -33,7 +33,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
|
|||||||
appReadySetup(false)
|
appReadySetup(false)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("p"))
|
typeText(injector.parser.parseKeys("p"))
|
||||||
|
|
||||||
val notification = notifications().last()
|
val notification = notifications().last()
|
||||||
@ -53,7 +53,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
|
|||||||
appReadySetup(false)
|
appReadySetup(false)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("p"))
|
typeText(injector.parser.parseKeys("p"))
|
||||||
|
|
||||||
val notifications = notifications()
|
val notifications = notifications()
|
||||||
@ -71,7 +71,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
|
|||||||
appReadySetup(true)
|
appReadySetup(true)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("p"))
|
typeText(injector.parser.parseKeys("p"))
|
||||||
|
|
||||||
val notifications = EventLog.getLogModel(fixture.project).notifications
|
val notifications = EventLog.getLogModel(fixture.project).notifications
|
||||||
|
@ -88,7 +88,7 @@ class PutTestAfterCursorActionTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
.storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("p"))
|
typeText(injector.parser.parseKeys("p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -127,7 +127,6 @@ class PutTestAfterCursorActionTest : VimTestCase() {
|
|||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
injector.registerGroup.storeText(
|
injector.registerGroup.storeText(
|
||||||
vimEditor,
|
vimEditor,
|
||||||
vimEditor.primaryCaret(),
|
|
||||||
before rangeOf "I found it in a legendary land\n",
|
before rangeOf "I found it in a legendary land\n",
|
||||||
SelectionType.LINE_WISE,
|
SelectionType.LINE_WISE,
|
||||||
false,
|
false,
|
||||||
@ -157,7 +156,7 @@ class PutTestAfterCursorActionTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("vep"))
|
typeText(injector.parser.parseKeys("vep"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -175,8 +174,8 @@ class PutTestAfterCursorActionTest : VimTestCase() {
|
|||||||
override fun collectTransferableData(
|
override fun collectTransferableData(
|
||||||
file: PsiFile,
|
file: PsiFile,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
startOffsets: IntArray?,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray?,
|
endOffsets: IntArray,
|
||||||
): List<TextBlockTransferableData> {
|
): List<TextBlockTransferableData> {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class PutTextBeforeCursorActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
injector.registerGroup.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
injector.registerGroup.storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "P"))
|
typeText(injector.parser.parseKeys("V" + "P"))
|
||||||
typeText(injector.parser.parseKeys("V" + "P"))
|
typeText(injector.parser.parseKeys("V" + "P"))
|
||||||
val after = """
|
val after = """
|
||||||
|
@ -54,7 +54,7 @@ class PutViaIdeaTest : VimTestCase() {
|
|||||||
|
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
|
|
||||||
typeText("ppp")
|
typeText("ppp")
|
||||||
val after = "Ilegendarylegendarylegendar${c}y found it in a legendary land"
|
val after = "Ilegendarylegendarylegendar${c}y found it in a legendary land"
|
||||||
@ -74,7 +74,6 @@ class PutViaIdeaTest : VimTestCase() {
|
|||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(
|
.storeText(
|
||||||
vimEditor,
|
vimEditor,
|
||||||
vimEditor.primaryCaret(),
|
|
||||||
before rangeOf "legendary$randomUUID",
|
before rangeOf "legendary$randomUUID",
|
||||||
SelectionType.CHARACTER_WISE,
|
SelectionType.CHARACTER_WISE,
|
||||||
false,
|
false,
|
||||||
@ -100,7 +99,6 @@ class PutViaIdeaTest : VimTestCase() {
|
|||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister().storeText(
|
VimPlugin.getRegister().storeText(
|
||||||
vimEditor,
|
vimEditor,
|
||||||
vimEditor.primaryCaret(),
|
|
||||||
before rangeOf "\nLorem ipsum dolor sit amet,\n",
|
before rangeOf "\nLorem ipsum dolor sit amet,\n",
|
||||||
SelectionType.CHARACTER_WISE,
|
SelectionType.CHARACTER_WISE,
|
||||||
false,
|
false,
|
||||||
|
@ -75,7 +75,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = "legendar${c}y it in a legendary land"
|
val after = "legendar${c}y it in a legendary land"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -87,7 +87,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "2p"))
|
typeText(injector.parser.parseKeys("v2e" + "2p"))
|
||||||
val after = "legendarylegendar${c}y in a legendary land"
|
val after = "legendarylegendar${c}y in a legendary land"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -99,7 +99,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v$" + "2p"))
|
typeText(injector.parser.parseKeys("v$" + "2p"))
|
||||||
val after = "legendarylegendar${c}y"
|
val after = "legendarylegendar${c}y"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -133,7 +133,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
val before = "I foun${c}d it in a legendary land"
|
val before = "I foun${c}d it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("vb" + "p"))
|
typeText(injector.parser.parseKeys("vb" + "p"))
|
||||||
val after = "I legendar${c}y it in a legendary land"
|
val after = "I legendar${c}y it in a legendary land"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -154,7 +154,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -182,7 +182,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -210,7 +210,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -238,7 +238,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v$" + "p"))
|
typeText(injector.parser.parseKeys("v$" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -455,7 +455,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -491,7 +491,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "p"))
|
typeText(injector.parser.parseKeys("ve" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -529,7 +529,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("ve" + "2p"))
|
typeText(injector.parser.parseKeys("ve" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -640,7 +640,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -666,7 +666,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "2p"))
|
typeText(injector.parser.parseKeys("V" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -703,7 +703,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -876,7 +876,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -902,7 +902,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "2p"))
|
typeText(injector.parser.parseKeys("V" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -939,7 +939,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1117,7 +1117,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1172,7 +1172,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "p"))
|
typeText(injector.parser.parseKeys("V" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1233,7 +1233,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "2p"))
|
typeText(injector.parser.parseKeys("V" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1409,7 +1409,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1435,7 +1435,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>3e2k" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>3e2k" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1461,7 +1461,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1487,7 +1487,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>3j$" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>3j$" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1526,7 +1526,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1554,7 +1554,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "P"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "P"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1593,7 +1593,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1633,7 +1633,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1672,7 +1672,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1707,7 +1707,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1743,7 +1743,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1779,7 +1779,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2ej" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2ej" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1815,7 +1815,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>elj" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>elj" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
@ -1852,7 +1852,7 @@ class PutVisualTextActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
|
typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
|
||||||
val after = """
|
val after = """
|
||||||
A Discovery
|
A Discovery
|
||||||
|
@ -18,7 +18,6 @@ import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
|||||||
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
|
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
import org.jetbrains.plugins.ideavim.annotations.TestWithoutPrimaryClipboard
|
import org.jetbrains.plugins.ideavim.annotations.TestWithoutPrimaryClipboard
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.jupiter.api.Disabled
|
import org.junit.jupiter.api.Disabled
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "2gp"))
|
typeText(injector.parser.parseKeys("v2e" + "2gp"))
|
||||||
val after = "legendarylegendary$c in a legendary land"
|
val after = "legendarylegendary$c in a legendary land"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -46,7 +45,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "gp"))
|
typeText(injector.parser.parseKeys("v2e" + "gp"))
|
||||||
val after = """
|
val after = """
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "gp"))
|
typeText(injector.parser.parseKeys("V" + "gp"))
|
||||||
val after = "legendary\n$c"
|
val after = "legendary\n$c"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -89,7 +88,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(file)
|
val editor = configureByText(file)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(2, 11), SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(2, 11), SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "gp"))
|
typeText(injector.parser.parseKeys("V" + "gp"))
|
||||||
assertState(newFile)
|
assertState(newFile)
|
||||||
}
|
}
|
||||||
@ -135,7 +134,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "gP"))
|
typeText(injector.parser.parseKeys("v2e" + "gP"))
|
||||||
val after = """
|
val after = """
|
||||||
|
|
||||||
@ -151,7 +150,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "2gP"))
|
typeText(injector.parser.parseKeys("v2e" + "2gP"))
|
||||||
val after = "legendarylegendary$c in a legendary land"
|
val after = "legendarylegendary$c in a legendary land"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -163,7 +162,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v$" + "2gP"))
|
typeText(injector.parser.parseKeys("v$" + "2gP"))
|
||||||
val after = "legendarylegendar${c}y"
|
val after = "legendarylegendar${c}y"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -175,7 +174,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
val before = "${c}I found it in a legendary land"
|
val before = "${c}I found it in a legendary land"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "gP"))
|
typeText(injector.parser.parseKeys("V" + "gP"))
|
||||||
val after = "legendary\n$c"
|
val after = "legendary\n$c"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
@ -261,9 +260,9 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
assertState(after)
|
assertState(after)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Disabled
|
||||||
@Ignore
|
@Test
|
||||||
fun `ingoretest put visual block visual line mode`() {
|
fun `test put visual block visual line mode`() {
|
||||||
val before = """
|
val before = """
|
||||||
qw${c}e
|
qw${c}e
|
||||||
asd
|
asd
|
||||||
@ -274,7 +273,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.BLOCK_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.BLOCK_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<S-v>" + "gp"))
|
typeText(injector.parser.parseKeys("<S-v>" + "gp"))
|
||||||
val after = """
|
val after = """
|
||||||
${c}fgh
|
${c}fgh
|
||||||
@ -300,7 +299,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.LINE_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.LINE_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("<C-v>" + "h" + "gp"))
|
typeText(injector.parser.parseKeys("<C-v>" + "h" + "gp"))
|
||||||
val after = """
|
val after = """
|
||||||
q
|
q
|
||||||
@ -315,15 +314,13 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
|
|||||||
assertState(after)
|
assertState(after)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
fun `test put visual text multicaret`() {
|
fun `test put visual text multicaret`() {
|
||||||
val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
|
val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("v2e" + "2gp"))
|
typeText(injector.parser.parseKeys("v2e" + "2gp"))
|
||||||
val after = "fghfgh$c fghfgh$c fghfgh$c"
|
val after = "fghfgh$c fghfgh$c fghfgh$c"
|
||||||
assertState(after)
|
assertState(after)
|
||||||
|
@ -91,7 +91,7 @@ class YankVisualActionTest : VimTestCase() {
|
|||||||
typeText(injector.parser.parseKeys("viw" + "y"))
|
typeText(injector.parser.parseKeys("viw" + "y"))
|
||||||
val editor = fixture.editor.vim
|
val editor = fixture.editor.vim
|
||||||
val lastRegister = injector.registerGroup.lastRegisterChar
|
val lastRegister = injector.registerGroup.lastRegisterChar
|
||||||
val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
|
val registers = editor.carets().map { injector.registerGroup.getRegister(lastRegister)?.rawText }
|
||||||
kotlin.test.assertEquals(listOf("found", "was"), registers)
|
kotlin.test.assertEquals(listOf("found", "was"), registers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ class YankVisualActionTest : VimTestCase() {
|
|||||||
typeText(injector.parser.parseKeys("V" + "y"))
|
typeText(injector.parser.parseKeys("V" + "y"))
|
||||||
val editor = fixture.editor.vim
|
val editor = fixture.editor.vim
|
||||||
val lastRegister = injector.registerGroup.lastRegisterChar
|
val lastRegister = injector.registerGroup.lastRegisterChar
|
||||||
val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
|
val registers = editor.carets().map { injector.registerGroup.getRegister(lastRegister)?.rawText }
|
||||||
kotlin.test.assertEquals(
|
kotlin.test.assertEquals(
|
||||||
listOf("all rocks and lavender and tufted grass,\n", "hard by the torrent of a mountain pass.\n"),
|
listOf("all rocks and lavender and tufted grass,\n", "hard by the torrent of a mountain pass.\n"),
|
||||||
registers,
|
registers,
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.jetbrains.plugins.ideavim.action.motion.updown
|
||||||
|
|
||||||
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
|
import org.junit.jupiter.api.Disabled
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class MotionUpCtrlPAction : VimTestCase() {
|
||||||
|
@Test
|
||||||
|
@Disabled("This one should be fixed")
|
||||||
|
fun `test last column empty`() {
|
||||||
|
val keys = "o<Esc><End><C-P>"
|
||||||
|
val before = """
|
||||||
|
${c}Lorem Ipsumm dolor sit amet, consectetur adipiscing elit. Morbi gravida commodo orci, egestas placerat purus rhoncus non. Donec efficitur placerat lorem, non ullamcorper nisl. Aliquam vestibulum, purus a pretium sodales, lorem libero placerat tortor, ut gravida est arcu nec purus. Suspendisse luctus euismod mi, at consectetur sapien facilisis sed. Duis eu magna id nisi lacinia vehicula in quis mauris. Donec tincidunt, erat in euismod placerat, tortor eros efficitur ligula, non finibus metus enim in ex. Nam commodo libero quis vestibulum congue. Vivamus sit amet tincidunt orci, in luctus tortor. Ut aliquam porttitor pharetra. Sed vel mi lacinia, auctor eros vel, condimentum eros. Fusce suscipit auctor venenatis. Aliquam elit risus, eleifend quis mollis eu, venenatis quis ex. Nunc varius consectetur eros sit amet efficitur. Donec a elit rutrum, tristique est in, maximus sem. Donec eleifend magna vitae suscipit viverra. Phasellus luctus aliquam tellus viverra consequat.
|
||||||
|
""".trimIndent()
|
||||||
|
val after = """
|
||||||
|
Lorem Ipsumm dolor sit amet, consectetur adipiscing elit. Morbi gravida commodo orci, egestas placerat purus rhoncus non. Donec efficitur placerat lorem, non ullamcorper nisl. Aliquam vestibulum, purus a pretium sodales, lorem libero placerat tortor, ut gravida est arcu nec purus. Suspendisse luctus euismod mi, at consectetur sapien facilisis sed. Duis eu magna id nisi lacinia vehicula in quis mauris. Donec tincidunt, erat in euismod placerat, tortor eros efficitur ligula, non finibus metus enim in ex. Nam commodo libero quis vestibulum congue. Vivamus sit amet tincidunt orci, in luctus tortor. Ut aliquam porttitor pharetra. Sed vel mi lacinia, auctor eros vel, condimentum eros. Fusce suscipit auctor venenatis. Aliquam elit risus, eleifend quis mollis eu, venenatis quis ex. Nunc varius consectetur eros sit amet efficitur. Donec a elit rutrum, tristique est in, maximus sem. Donec eleifend magna vitae suscipit viverra. Phasellus luctus aliquam tellus viverra consequat${c}.
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
doTest(keys, before, after)
|
||||||
|
}
|
||||||
|
}
|
@ -130,7 +130,7 @@ class MultipleCaretsTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(commandToKeys("pu"))
|
typeText(commandToKeys("pu"))
|
||||||
val after = """
|
val after = """
|
||||||
qwe
|
qwe
|
||||||
@ -165,7 +165,7 @@ class MultipleCaretsTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(commandToKeys("pu"))
|
typeText(commandToKeys("pu"))
|
||||||
val after = """
|
val after = """
|
||||||
qwe
|
qwe
|
||||||
@ -201,7 +201,7 @@ class MultipleCaretsTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(commandToKeys("4pu"))
|
typeText(commandToKeys("4pu"))
|
||||||
val after = """
|
val after = """
|
||||||
qwe
|
qwe
|
||||||
@ -237,7 +237,7 @@ class MultipleCaretsTest : VimTestCase() {
|
|||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(commandToKeys("4pu"))
|
typeText(commandToKeys("4pu"))
|
||||||
val after = """
|
val after = """
|
||||||
qwe
|
qwe
|
||||||
@ -258,7 +258,7 @@ class MultipleCaretsTest : VimTestCase() {
|
|||||||
val before = "${c}qwe\n" + "rty\n" + "as${c}d\n" + "fgh\n" + "zxc\n" + "vbn\n"
|
val before = "${c}qwe\n" + "rty\n" + "as${c}d\n" + "fgh\n" + "zxc\n" + "vbn\n"
|
||||||
val editor = configureByText(before)
|
val editor = configureByText(before)
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(editor.vim, editor.vim.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
.storeText(editor.vim, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
|
||||||
|
|
||||||
typeText("vj")
|
typeText("vj")
|
||||||
typeText(commandToKeys("pu"))
|
typeText(commandToKeys("pu"))
|
||||||
|
@ -298,6 +298,15 @@ class MapCommandTest : VimTestCase() {
|
|||||||
assertState("I found it in ${c}a legendary land")
|
assertState("I found it in ${c}a legendary land")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestFor(issues = ["VIM-3569"])
|
||||||
|
fun `test bar in mapping`() {
|
||||||
|
configureByText("${c}I found it in a legendary land")
|
||||||
|
typeText(commandToKeys("nmap <leader>\\| dw"))
|
||||||
|
typeText("<leader>|")
|
||||||
|
assertState("${c}found it in a legendary land")
|
||||||
|
}
|
||||||
|
|
||||||
// VIM-676 |:map|
|
// VIM-676 |:map|
|
||||||
@TestWithoutNeovim(reason = SkipNeovimReason.VIM_SCRIPT)
|
@TestWithoutNeovim(reason = SkipNeovimReason.VIM_SCRIPT)
|
||||||
@Test
|
@Test
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
package org.jetbrains.plugins.ideavim.ex.implementation.commands
|
package org.jetbrains.plugins.ideavim.ex.implementation.commands
|
||||||
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
|
||||||
import com.maddyhome.idea.vim.register.RegisterConstants
|
import com.maddyhome.idea.vim.register.RegisterConstants
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
@ -303,33 +302,4 @@ class YankLinesCommandTest : VimTestCase() {
|
|||||||
|Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
|
|Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
|
||||||
|""".trimMargin())
|
|""".trimMargin())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `test multicaret yank`() {
|
|
||||||
configureByText(
|
|
||||||
"""
|
|
||||||
|Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
||||||
|${c}Morbi nec luctus tortor, id venenatis lacus.
|
|
||||||
|${c}Nunc sit amet tellus vel purus cursus posuere et at purus.
|
|
||||||
|${c}Ut id dapibus augue.
|
|
||||||
|Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
|
|
||||||
|Pellentesque orci dolor, tristique quis rutrum non, scelerisque id dui.
|
|
||||||
""".trimMargin()
|
|
||||||
)
|
|
||||||
enterCommand("y")
|
|
||||||
val carets = fixture.editor.vim.carets()
|
|
||||||
assertEquals(3, carets.size)
|
|
||||||
assertEquals(
|
|
||||||
"Morbi nec luctus tortor, id venenatis lacus.\n",
|
|
||||||
carets[0].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
"Nunc sit amet tellus vel purus cursus posuere et at purus.\n",
|
|
||||||
carets[1].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
"Ut id dapibus augue.\n",
|
|
||||||
carets[2].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.plugins.ideavim.extension.replacewithregister
|
package org.jetbrains.plugins.ideavim.extension.replacewithregister
|
||||||
|
|
||||||
import com.intellij.testFramework.UsefulTestCase.assertContainsElements
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
@ -24,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInfo
|
import org.junit.jupiter.api.TestInfo
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class ReplaceWithRegisterTest : VimTestCase() {
|
class ReplaceWithRegisterTest : VimTestCase() {
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("griw"))
|
typeText(injector.parser.parseKeys("griw"))
|
||||||
assertState("one on${c}e three")
|
assertState("one on${c}e three")
|
||||||
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
||||||
@ -170,7 +170,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("3griw"))
|
typeText(injector.parser.parseKeys("3griw"))
|
||||||
assertState("one on${c}e four")
|
assertState("one on${c}e four")
|
||||||
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
||||||
@ -184,7 +184,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("griw"))
|
typeText(injector.parser.parseKeys("griw"))
|
||||||
assertState("one two one four")
|
assertState("one two one four")
|
||||||
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
||||||
@ -197,7 +197,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("griw" + "w" + "."))
|
typeText(injector.parser.parseKeys("griw" + "w" + "."))
|
||||||
assertState("one one on${c}e four")
|
assertState("one one on${c}e four")
|
||||||
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
|
||||||
@ -247,7 +247,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("grr"))
|
typeText(injector.parser.parseKeys("grr"))
|
||||||
assertState(
|
assertState(
|
||||||
"""
|
"""
|
||||||
@ -414,7 +414,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("viw" + "gr"))
|
typeText(injector.parser.parseKeys("viw" + "gr"))
|
||||||
assertState(
|
assertState(
|
||||||
"""
|
"""
|
||||||
@ -485,7 +485,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
configureByText(text)
|
configureByText(text)
|
||||||
val vimEditor = fixture.editor.vim
|
val vimEditor = fixture.editor.vim
|
||||||
VimPlugin.getRegister()
|
VimPlugin.getRegister()
|
||||||
.storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
.storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
|
||||||
typeText(injector.parser.parseKeys("V" + "gr"))
|
typeText(injector.parser.parseKeys("V" + "gr"))
|
||||||
assertState(
|
assertState(
|
||||||
"""
|
"""
|
||||||
@ -525,7 +525,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
|
|||||||
fun `test multiple carets`() {
|
fun `test multiple carets`() {
|
||||||
// Behaviour of pasting a full line with multiple carets is undefined in Vim and has different implementation in
|
// Behaviour of pasting a full line with multiple carets is undefined in Vim and has different implementation in
|
||||||
// IdeaVim depending on if ideaput is specified in 'clipboard' or not
|
// IdeaVim depending on if ideaput is specified in 'clipboard' or not
|
||||||
assertContainsElements(optionsNoEditor().clipboard, OptionConstants.clipboard_ideaput)
|
assertTrue(OptionConstants.clipboard_ideaput in optionsNoEditor().clipboard)
|
||||||
|
|
||||||
enableExtensions("multiple-cursors")
|
enableExtensions("multiple-cursors")
|
||||||
val text = """
|
val text = """
|
||||||
|
@ -321,8 +321,9 @@ class CaretVisualAttributesHelperTest : VimTestCase() {
|
|||||||
""".trimMargin(),
|
""".trimMargin(),
|
||||||
)
|
)
|
||||||
injector.actionExecutor.executeAction(
|
injector.actionExecutor.executeAction(
|
||||||
"EditorCloneCaretBelow",
|
fixture.editor.vim,
|
||||||
injector.executionContextManager.getEditorExecutionContext(fixture.editor.vim),
|
name = "EditorCloneCaretBelow",
|
||||||
|
context = injector.executionContextManager.getEditorExecutionContext(fixture.editor.vim),
|
||||||
)
|
)
|
||||||
kotlin.test.assertEquals(2, fixture.editor.caretModel.caretCount)
|
kotlin.test.assertEquals(2, fixture.editor.caretModel.caretCount)
|
||||||
assertCaretVisualAttributes(CaretVisualAttributes.Shape.BLOCK, 0f)
|
assertCaretVisualAttributes(CaretVisualAttributes.Shape.BLOCK, 0f)
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.plugins.ideavim.option
|
package org.jetbrains.plugins.ideavim.option
|
||||||
|
|
||||||
import com.intellij.testFramework.UsefulTestCase.assertDoesntContain
|
|
||||||
import com.maddyhome.idea.vim.helper.CharacterHelper
|
import com.maddyhome.idea.vim.helper.CharacterHelper
|
||||||
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
@ -92,14 +91,7 @@ class KeywordOptionTest : VimTestCase() {
|
|||||||
setKeyword("b-a")
|
setKeyword("b-a")
|
||||||
assertPluginError(true)
|
assertPluginError(true)
|
||||||
assertPluginErrorMessageContains("E474: Invalid argument: iskeyword=b-a")
|
assertPluginErrorMessageContains("E474: Invalid argument: iskeyword=b-a")
|
||||||
assertDoesntContain(
|
assertTrue("b-a" !in values)
|
||||||
values,
|
|
||||||
object : ArrayList<String?>() {
|
|
||||||
init {
|
|
||||||
add("b-a")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -107,14 +99,7 @@ class KeywordOptionTest : VimTestCase() {
|
|||||||
setKeyword("ab")
|
setKeyword("ab")
|
||||||
assertPluginError(true)
|
assertPluginError(true)
|
||||||
assertPluginErrorMessageContains("E474: Invalid argument: iskeyword=ab")
|
assertPluginErrorMessageContains("E474: Invalid argument: iskeyword=ab")
|
||||||
assertDoesntContain(
|
assertTrue("ab" !in values)
|
||||||
values,
|
|
||||||
object : ArrayList<String?>() {
|
|
||||||
init {
|
|
||||||
add("ab")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -27,8 +27,8 @@ import com.maddyhome.idea.vim.register.RegisterConstants.LAST_SEARCH_REGISTER
|
|||||||
import com.maddyhome.idea.vim.register.RegisterConstants.VALID_REGISTERS
|
import com.maddyhome.idea.vim.register.RegisterConstants.VALID_REGISTERS
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.state.mode.toVimNotation
|
import com.maddyhome.idea.vim.state.mode.toVimNotation
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.jupiter.api.TestInfo
|
import org.junit.jupiter.api.TestInfo
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
object NeovimTesting {
|
object NeovimTesting {
|
||||||
private lateinit var neovimApi: NeovimApi
|
private lateinit var neovimApi: NeovimApi
|
||||||
@ -103,7 +103,7 @@ object NeovimTesting {
|
|||||||
singleCaret
|
singleCaret
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isNeovimTestingEnabled(): Boolean {
|
private fun isNeovimTestingEnabled(): Boolean {
|
||||||
val property = System.getProperty("ideavim.nvim.test", "false")
|
val property = System.getProperty("ideavim.nvim.test", "false")
|
||||||
val neovimTestingEnabled = if (property.isBlank()) true else property.toBoolean()
|
val neovimTestingEnabled = if (property.isBlank()) true else property.toBoolean()
|
||||||
return neovimTestingEnabled
|
return neovimTestingEnabled
|
||||||
@ -188,7 +188,7 @@ object NeovimTesting {
|
|||||||
val neovimRegister = getRegister(register)
|
val neovimRegister = getRegister(register)
|
||||||
val vimPluginRegister = VimPlugin.getRegister().getRegister(register)
|
val vimPluginRegister = VimPlugin.getRegister().getRegister(register)
|
||||||
val ideavimRegister = vimPluginRegister?.text ?: ""
|
val ideavimRegister = vimPluginRegister?.text ?: ""
|
||||||
assertEquals("Register '$register'", neovimRegister, ideavimRegister)
|
assertEquals(neovimRegister, ideavimRegister, "Register '$register'")
|
||||||
|
|
||||||
if (neovimRegister.isNotEmpty()) {
|
if (neovimRegister.isNotEmpty()) {
|
||||||
val neovimRegisterType = neovimApi.callFunction("getregtype", listOf(register)).get().toString()
|
val neovimRegisterType = neovimApi.callFunction("getregtype", listOf(register)).get().toString()
|
||||||
@ -201,7 +201,7 @@ object NeovimTesting {
|
|||||||
|
|
||||||
// We take only the first char because neovim returns width for block selection
|
// We take only the first char because neovim returns width for block selection
|
||||||
val neovimChar = neovimRegisterType.getOrNull(0)?.toString() ?: ""
|
val neovimChar = neovimRegisterType.getOrNull(0)?.toString() ?: ""
|
||||||
assertEquals("Register '$register'", expectedType, neovimChar)
|
assertEquals(expectedType, neovimChar, "Register '$register'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user