mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-18 19:24:55 +02:00
Compare commits
19 Commits
customized
...
customized
Author | SHA1 | Date | |
---|---|---|---|
3da1cc300f
|
|||
4d535c4148
|
|||
5768209a33
|
|||
fe0f4fde9d
|
|||
25e4eb9078
|
|||
9b507e6033
|
|||
4d0a54221a
|
|||
17d49bc35d
|
|||
ba9966d996
|
|||
ae1cb45854
|
|||
27c8d9e610
|
|||
5a247843e4
|
|||
4438c654d0
|
|||
705530fdfd
|
|||
a1c0cfda52
|
|||
9261d17491
|
|||
c89099bb0c
|
|||
00f73f52bd
|
|||
b0474cec7d
|
3
.github/workflows/closeYoutrackOnCommit.yml
vendored
3
.github/workflows/closeYoutrackOnCommit.yml
vendored
@@ -8,9 +8,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
|
5
.github/workflows/codeql-analysis.yml
vendored
5
.github/workflows/codeql-analysis.yml
vendored
@@ -20,11 +20,6 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: '44 12 * * 4'
|
- cron: '44 12 * * 4'
|
||||||
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze
|
name: Analyze
|
||||||
|
14
.github/workflows/syncDoc.yml
vendored
14
.github/workflows/syncDoc.yml
vendored
@@ -10,9 +10,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
@@ -37,17 +34,6 @@ jobs:
|
|||||||
id: update_authors
|
id: update_authors
|
||||||
run: cp -a origin/doc/. docs
|
run: cp -a origin/doc/. docs
|
||||||
|
|
||||||
# The Wiki for github should have no `.md` in references
|
|
||||||
# Otherwise, such links will lead to the raw text.
|
|
||||||
# However, the `.md` should exist to have a navigation in GitHub code.
|
|
||||||
- name: Replace `.md)` with `)`
|
|
||||||
run: |
|
|
||||||
# Define the directory you want to process
|
|
||||||
DIRECTORY="docs"
|
|
||||||
|
|
||||||
# Find all files in the directory and perform the replacement
|
|
||||||
find $DIRECTORY -type f -exec sed -i 's/\.md)/)/g' {} +
|
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
with:
|
with:
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,6 +27,9 @@
|
|||||||
# Generated by gradle task "generateGrammarSource"
|
# Generated by gradle task "generateGrammarSource"
|
||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
|
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
|
||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
|
||||||
|
# Generated JSONs for lazy classloading
|
||||||
|
/vim-engine/src/main/resources/ksp-generated
|
||||||
|
/src/main/resources/ksp-generated
|
||||||
|
|
||||||
# Created by github automation
|
# Created by github automation
|
||||||
settings.xml
|
settings.xml
|
||||||
|
15
.teamcity/_Self/Constants.kt
vendored
15
.teamcity/_Self/Constants.kt
vendored
@@ -5,12 +5,13 @@ object Constants {
|
|||||||
const val EAP_CHANNEL = "eap"
|
const val EAP_CHANNEL = "eap"
|
||||||
const val DEV_CHANNEL = "Dev"
|
const val DEV_CHANNEL = "Dev"
|
||||||
|
|
||||||
const val NVIM_TESTS = "2024.2.1"
|
const val GITHUB_TESTS = "2024.1.1"
|
||||||
const val PROPERTY_TESTS = "2024.2.1"
|
const val NVIM_TESTS = "2024.1.1"
|
||||||
const val LONG_RUNNING_TESTS = "2024.2.1"
|
const val PROPERTY_TESTS = "2024.1.1"
|
||||||
const val QODANA_TESTS = "2024.2.1"
|
const val LONG_RUNNING_TESTS = "2024.1.1"
|
||||||
const val RELEASE = "2024.2.1"
|
const val QODANA_TESTS = "2024.1.1"
|
||||||
|
const val RELEASE = "2024.1.1"
|
||||||
|
|
||||||
const val RELEASE_DEV = "2024.2.1"
|
const val RELEASE_DEV = "2024.1.1"
|
||||||
const val RELEASE_EAP = "2024.2.1"
|
const val RELEASE_EAP = "2024.1.1"
|
||||||
}
|
}
|
||||||
|
10
.teamcity/_Self/Project.kt
vendored
10
.teamcity/_Self/Project.kt
vendored
@@ -8,6 +8,7 @@ import _Self.buildTypes.PropertyBased
|
|||||||
import _Self.buildTypes.Qodana
|
import _Self.buildTypes.Qodana
|
||||||
import _Self.buildTypes.TestingBuildType
|
import _Self.buildTypes.TestingBuildType
|
||||||
import _Self.subprojects.GitHub
|
import _Self.subprojects.GitHub
|
||||||
|
import _Self.subprojects.OldTests
|
||||||
import _Self.subprojects.Releases
|
import _Self.subprojects.Releases
|
||||||
import _Self.vcsRoots.GitHubPullRequest
|
import _Self.vcsRoots.GitHubPullRequest
|
||||||
import _Self.vcsRoots.ReleasesVcsRoot
|
import _Self.vcsRoots.ReleasesVcsRoot
|
||||||
@@ -17,7 +18,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.Project
|
|||||||
object Project : Project({
|
object Project : Project({
|
||||||
description = "Vim engine for JetBrains IDEs"
|
description = "Vim engine for JetBrains IDEs"
|
||||||
|
|
||||||
subProjects(Releases, GitHub)
|
subProjects(Releases, OldTests, GitHub)
|
||||||
|
|
||||||
// VCS roots
|
// VCS roots
|
||||||
vcsRoot(GitHubPullRequest)
|
vcsRoot(GitHubPullRequest)
|
||||||
@@ -25,7 +26,7 @@ object Project : Project({
|
|||||||
|
|
||||||
// Active tests
|
// Active tests
|
||||||
buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
|
buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
|
||||||
buildType(TestingBuildType("2024.2.1", "<default>"))
|
buildType(TestingBuildType("2024.1.1", "<default>"))
|
||||||
buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
|
buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
|
||||||
|
|
||||||
buildType(PropertyBased)
|
buildType(PropertyBased)
|
||||||
@@ -42,9 +43,6 @@ object Project : Project({
|
|||||||
abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
|
abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
|
||||||
artifactRules = """
|
artifactRules = """
|
||||||
+:build/reports => build/reports
|
+:build/reports => build/reports
|
||||||
+:tests/java-tests/build/reports => java-tests/build/reports
|
|
||||||
+:tests/long-running-tests/build/reports => long-running-tests/build/reports
|
|
||||||
+:tests/property-tests/build/reports => property-tests/build/reports
|
|
||||||
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
|
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
@@ -54,7 +52,7 @@ abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
|
|||||||
// These requirements define Linux-Medium configuration.
|
// These requirements define Linux-Medium configuration.
|
||||||
// Unfortunately, requirement by name (teamcity.agent.name) doesn't work
|
// Unfortunately, requirement by name (teamcity.agent.name) doesn't work
|
||||||
// IDK the reason for it, but on our agents this property is empty
|
// IDK the reason for it, but on our agents this property is empty
|
||||||
equals("teamcity.agent.hardware.cpuCount", "16")
|
equals("teamcity.agent.hardware.cpuCount", "4")
|
||||||
equals("teamcity.agent.os.family", "Linux")
|
equals("teamcity.agent.os.family", "Linux")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
3
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
@@ -40,9 +40,6 @@ object Compatibility : IdeaVimBuildType({
|
|||||||
# 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
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.peekaboo' [latest-IU] -team-city
|
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.switch' [latest-IU] -team-city
|
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.functiontextobj' [latest-IU] -team-city
|
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ object ReleaseEapFromBranch : IdeaVimBuildType({
|
|||||||
vcs {
|
vcs {
|
||||||
root(ReleasesVcsRoot)
|
root(ReleasesVcsRoot)
|
||||||
branchFilter = """
|
branchFilter = """
|
||||||
+:heads/releases/*
|
+:heads/(releases/*)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
checkoutMode = CheckoutMode.AUTO
|
checkoutMode = CheckoutMode.AUTO
|
||||||
|
@@ -39,11 +39,9 @@ open class TestingBuildType(
|
|||||||
|
|
||||||
steps {
|
steps {
|
||||||
gradle {
|
gradle {
|
||||||
clearConditions()
|
|
||||||
tasks = "clean test"
|
tasks = "clean test"
|
||||||
buildFile = ""
|
buildFile = ""
|
||||||
enableStacktrace = true
|
enableStacktrace = true
|
||||||
jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
.teamcity/_Self/subprojects/GitHub.kt
vendored
2
.teamcity/_Self/subprojects/GitHub.kt
vendored
@@ -1,5 +1,6 @@
|
|||||||
package _Self.subprojects
|
package _Self.subprojects
|
||||||
|
|
||||||
|
import _Self.Constants
|
||||||
import _Self.IdeaVimBuildType
|
import _Self.IdeaVimBuildType
|
||||||
import _Self.vcsRoots.GitHubPullRequest
|
import _Self.vcsRoots.GitHubPullRequest
|
||||||
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
|
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
|
||||||
@@ -24,6 +25,7 @@ class GithubBuildType(command: String, desc: String) : IdeaVimBuildType({
|
|||||||
|
|
||||||
params {
|
params {
|
||||||
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
|
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
|
||||||
|
param("env.ORG_GRADLE_PROJECT_ideaVersion", Constants.GITHUB_TESTS)
|
||||||
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
|
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
.teamcity/_Self/subprojects/OldTests.kt
vendored
Normal file
25
.teamcity/_Self/subprojects/OldTests.kt
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package _Self.subprojects
|
||||||
|
|
||||||
|
import _Self.buildTypes.TestingBuildType
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
|
||||||
|
|
||||||
|
object OldTests : Project({
|
||||||
|
name = "Old IdeaVim tests"
|
||||||
|
description = "Tests for older versions of IJ"
|
||||||
|
|
||||||
|
buildType(TestingBuildType("IC-2018.1", "181-182", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2018.2", "181-182", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2018.3", "183", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2019.1", "191-193", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2019.2", "191-193", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2019.3", "191-193", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2020.1", "201", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2020.2", "202", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2020.3", "203-212", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2021.1", "203-212", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2021.2.2", "203-212", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2021.3.2", "213-221", javaVersion = "1.8", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2022.2.3", branch = "222", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2023.1", "231-232", javaPlugin = false))
|
||||||
|
buildType(TestingBuildType("IC-2023.2", "231-232", javaPlugin = false))
|
||||||
|
})
|
39
.teamcity/patches/buildTypes/IdeaVimTests_Latest_EAP.kts
vendored
Normal file
39
.teamcity/patches/buildTypes/IdeaVimTests_Latest_EAP.kts
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package patches.buildTypes
|
||||||
|
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.GradleBuildStep
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
|
||||||
|
|
||||||
|
/*
|
||||||
|
This patch script was generated by TeamCity on settings change in UI.
|
||||||
|
To apply the patch, change the buildType with id = 'IdeaVimTests_Latest_EAP'
|
||||||
|
accordingly, and delete the patch script.
|
||||||
|
*/
|
||||||
|
changeBuildType(RelativeId("IdeaVimTests_Latest_EAP")) {
|
||||||
|
check(artifactRules == """
|
||||||
|
+:build/reports => build/reports
|
||||||
|
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
|
||||||
|
""".trimIndent()) {
|
||||||
|
"Unexpected option value: artifactRules = $artifactRules"
|
||||||
|
}
|
||||||
|
artifactRules = """
|
||||||
|
+:build/reports => build/reports
|
||||||
|
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
|
||||||
|
+:tests/java-tests/build/reports => tests/java-tests/build/reports
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
expectSteps {
|
||||||
|
gradle {
|
||||||
|
tasks = "clean test"
|
||||||
|
buildFile = ""
|
||||||
|
enableStacktrace = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
update<GradleBuildStep>(0) {
|
||||||
|
clearConditions()
|
||||||
|
jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
.teamcity/patches/buildTypes/ReleaseEapFromBranch.kts
vendored
Normal file
19
.teamcity/patches/buildTypes/ReleaseEapFromBranch.kts
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package patches.buildTypes
|
||||||
|
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
|
||||||
|
|
||||||
|
/*
|
||||||
|
This patch script was generated by TeamCity on settings change in UI.
|
||||||
|
To apply the patch, change the buildType with id = 'ReleaseEapFromBranch'
|
||||||
|
accordingly, and delete the patch script.
|
||||||
|
*/
|
||||||
|
changeBuildType(RelativeId("ReleaseEapFromBranch")) {
|
||||||
|
vcs {
|
||||||
|
|
||||||
|
check(branchFilter == "+:heads/(releases/*)") {
|
||||||
|
"Unexpected option value: branchFilter = $branchFilter"
|
||||||
|
}
|
||||||
|
branchFilter = "heads/releases/*"
|
||||||
|
}
|
||||||
|
}
|
44
AUTHORS.md
44
AUTHORS.md
@@ -523,46 +523,6 @@ Contributors:
|
|||||||
[![icon][github]](https://github.com/LazyScaper)
|
[![icon][github]](https://github.com/LazyScaper)
|
||||||
|
|
||||||
Jake
|
Jake
|
||||||
* [![icon][mail]](mailto:the1xdeveloper@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/The1xDeveloper)
|
|
||||||
|
|
||||||
The1xDeveloper
|
|
||||||
* [![icon][mail]](mailto:shaunewilliams@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/shaunlebron)
|
|
||||||
|
|
||||||
shaun
|
|
||||||
* [![icon][mail]](mailto:i.i.babko@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/igorbabko)
|
|
||||||
|
|
||||||
Igor Babko
|
|
||||||
* [![icon][mail]](mailto:533601+felixwiemuth@users.noreply.github.com)
|
|
||||||
[![icon][github]](https://github.com/felixwiemuth)
|
|
||||||
|
|
||||||
Felix Wiemuth
|
|
||||||
* [![icon][mail]](mailto:kirill.karnaukhov@jetbrains.com)
|
|
||||||
[![icon][github]](https://github.com/kkarnauk)
|
|
||||||
|
|
||||||
Kirill Karnaukhov,
|
|
||||||
* [![icon][mail]](mailto:sander.hestvik@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/SanderHestvik)
|
|
||||||
|
|
||||||
SanderHestvik
|
|
||||||
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
|
|
||||||
[![icon][github]](https://github.com/gregsh)
|
|
||||||
|
|
||||||
Greg Shrago
|
|
||||||
* [![icon][mail]](mailto:jphalip@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/jphalip)
|
|
||||||
|
|
||||||
Julien Phalip
|
|
||||||
* [![icon][mail]](mailto:j.trimailovas@gmail.com)
|
|
||||||
[![icon][github]](https://github.com/trimailov)
|
|
||||||
|
|
||||||
Justas Trimailovas,
|
|
||||||
* [![icon][mail]](mailto:justast@wix.com)
|
|
||||||
[![icon][github]](https://github.com/justast-wix)
|
|
||||||
|
|
||||||
Justas Trimailovas
|
|
||||||
|
|
||||||
Previous contributors:
|
Previous contributors:
|
||||||
|
|
||||||
@@ -574,10 +534,6 @@ Previous contributors:
|
|||||||
[![icon][github]](https://github.com/kevin70)
|
[![icon][github]](https://github.com/kevin70)
|
||||||
|
|
||||||
kk
|
kk
|
||||||
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
|
|
||||||
[![icon][github]](https://github.com/gregsh)
|
|
||||||
|
|
||||||
Greg Shrago
|
|
||||||
|
|
||||||
|
|
||||||
If you are a contributor and your name is not listed here, feel free to
|
If you are a contributor and your name is not listed here, feel free to
|
||||||
|
@@ -27,8 +27,8 @@ usual beta standards.
|
|||||||
|
|
||||||
Since version 2.9.0, the changelog can be found on YouTrack
|
Since version 2.9.0, the changelog can be found on YouTrack
|
||||||
|
|
||||||
* [To Be Released](https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20)
|
To Be Released: https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20
|
||||||
* [Version Fixes](https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20%7BFix%20versions%7D%20asc)
|
Latest Fixes: https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20updated%20
|
||||||
|
|
||||||
## 2.9.0, 2024-02-20
|
## 2.9.0, 2024-02-20
|
||||||
|
|
||||||
|
@@ -62,16 +62,12 @@ for a few days or send it to a friend for testing.
|
|||||||
If you are looking for:
|
If you are looking for:
|
||||||
|
|
||||||
- Vim commands (`w`, `<C-O>`, `p`, etc.):
|
- Vim commands (`w`, `<C-O>`, `p`, etc.):
|
||||||
- Any particular command:
|
- Any particular command: `package-info.java`.
|
||||||
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_commands.json)
|
|
||||||
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_commands.json)
|
|
||||||
- How commands are executed in common: `EditorActionHandlerBase`.
|
- How commands are executed in common: `EditorActionHandlerBase`.
|
||||||
- Key mapping: `KeyHandler.handleKey()`.
|
- Key mapping: `KeyHandler.handleKey()`.
|
||||||
|
|
||||||
- Ex commands (`:set`, `:s`, `:nohlsearch`):
|
- Ex commands (`:set`, `:s`, `:nohlsearch`):
|
||||||
- Any particular command:
|
- Any particular ex command: package `com.maddyhome.idea.vim.ex.handler`.
|
||||||
- [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_ex_commands.json)
|
|
||||||
- [IdeaVim only commands](src/main/resources/ksp-generated/intellij_ex_commands.json)
|
|
||||||
- Vim script grammar: `Vimscript.g4`.
|
- Vim script grammar: `Vimscript.g4`.
|
||||||
- Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
|
- Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
|
||||||
- Vim script executor: `Executor`.
|
- Vim script executor: `Executor`.
|
||||||
|
@@ -109,6 +109,7 @@ etc
|
|||||||
|
|
||||||
See also:
|
See also:
|
||||||
|
|
||||||
|
* [The list of all supported commands](src/main/java/com/maddyhome/idea/vim/package-info.java)
|
||||||
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
|
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
|
||||||
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
|
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
|
||||||
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
|
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
|
||||||
|
@@ -21,7 +21,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("com.google.devtools.ksp:symbol-processing-api:2.1.0-1.0.29")
|
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")
|
||||||
|
@@ -37,8 +37,7 @@ class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironme
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
|
||||||
val sortedCommands = commands.sortedWith(compareBy({ it.keys }, { it.`class` }))
|
val fileContent = json.encodeToString(commands)
|
||||||
val fileContent = json.encodeToString(sortedCommands)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
@@ -37,8 +37,7 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
|
||||||
val sortedCommandToClass = commandToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
|
val fileContent = json.encodeToString(commandToClass)
|
||||||
val fileContent = json.encodeToString(sortedCommandToClass)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
@@ -37,8 +37,7 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
|
|||||||
Files.createDirectories(generatedDirPath)
|
Files.createDirectories(generatedDirPath)
|
||||||
|
|
||||||
val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
|
val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
|
||||||
val sortedNameToClass = nameToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
|
val fileContent = json.encodeToString(nameToClass)
|
||||||
val fileContent = json.encodeToString(sortedNameToClass)
|
|
||||||
filePath.writeText(fileContent)
|
filePath.writeText(fileContent)
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
@@ -50,14 +50,14 @@ buildscript {
|
|||||||
classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
||||||
|
|
||||||
// This is needed for jgit to connect to ssh
|
// This is needed for jgit to connect to ssh
|
||||||
classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r")
|
classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
|
||||||
classpath("org.kohsuke:github-api:1.305")
|
classpath("org.kohsuke:github-api:1.305")
|
||||||
|
|
||||||
classpath("io.ktor:ktor-client-core:3.0.2")
|
classpath("io.ktor:ktor-client-core:2.3.12")
|
||||||
classpath("io.ktor:ktor-client-cio:3.0.2")
|
classpath("io.ktor:ktor-client-cio:2.3.10")
|
||||||
classpath("io.ktor:ktor-client-auth:3.0.2")
|
classpath("io.ktor:ktor-client-auth:2.3.12")
|
||||||
classpath("io.ktor:ktor-client-content-negotiation:3.0.2")
|
classpath("io.ktor:ktor-client-content-negotiation:2.3.10")
|
||||||
classpath("io.ktor:ktor-serialization-kotlinx-json:3.0.2")
|
classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
|
||||||
|
|
||||||
// This comes from the changelog plugin
|
// This comes from the changelog plugin
|
||||||
// classpath("org.jetbrains:markdown:0.3.1")
|
// classpath("org.jetbrains:markdown:0.3.1")
|
||||||
@@ -69,7 +69,7 @@ plugins {
|
|||||||
kotlin("jvm") version "2.0.0"
|
kotlin("jvm") version "2.0.0"
|
||||||
application
|
application
|
||||||
id("java-test-fixtures")
|
id("java-test-fixtures")
|
||||||
id("org.jetbrains.intellij.platform") version "2.2.0"
|
id("org.jetbrains.intellij.platform") version "2.0.0-rc2"
|
||||||
id("org.jetbrains.changelog") version "2.2.1"
|
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"
|
||||||
@@ -85,6 +85,7 @@ val ideaVersion: String by project
|
|||||||
val ideaType: String by project
|
val ideaType: String by project
|
||||||
val instrumentPluginCode: String by project
|
val instrumentPluginCode: String by project
|
||||||
val remoteRobotVersion: String by project
|
val remoteRobotVersion: String by project
|
||||||
|
val splitModeVersion: String by project
|
||||||
|
|
||||||
val publishChannels: String by project
|
val publishChannels: String by project
|
||||||
val publishToken: String by project
|
val publishToken: String by project
|
||||||
@@ -107,17 +108,13 @@ dependencies {
|
|||||||
compileOnly(project(":annotation-processors"))
|
compileOnly(project(":annotation-processors"))
|
||||||
|
|
||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
compileOnly("org.jetbrains:annotations:26.0.1")
|
compileOnly("org.jetbrains:annotations:24.1.0")
|
||||||
|
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
// Snapshots don't use installers
|
|
||||||
// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html#target-versions-installers
|
|
||||||
val useInstaller = "EAP-SNAPSHOT" !in ideaVersion
|
|
||||||
|
|
||||||
// Note that it is also possible to use local("...") to compile against a locally installed IDE
|
// Note that it is also possible to use local("...") to compile against a locally installed IDE
|
||||||
// E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
|
// E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
|
||||||
// Or something like: intellijIdeaUltimate(ideaVersion)
|
// Or something like: intellijIdeaUltimate(ideaVersion)
|
||||||
create(ideaType, ideaVersion, useInstaller)
|
create(ideaType, ideaVersion)
|
||||||
|
|
||||||
pluginVerifier()
|
pluginVerifier()
|
||||||
zipSigner()
|
zipSigner()
|
||||||
@@ -128,7 +125,6 @@ dependencies {
|
|||||||
|
|
||||||
// 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.19")
|
plugin("AceJump", "3.8.19")
|
||||||
plugin("com.intellij.classic.ui", "242.20224.159")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
|
moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
|
||||||
@@ -150,17 +146,17 @@ dependencies {
|
|||||||
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
||||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
|
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5")
|
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5")
|
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5")
|
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
|
||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5")
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5")
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
|
||||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5")
|
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
|
// 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
|
// Can be removed when IJPL-159134 is fixed
|
||||||
// testRuntimeOnly("junit:junit:4.13.2")
|
// testRuntimeOnly("junit:junit:4.13.2")
|
||||||
testImplementation("org.junit.vintage:junit-vintage-engine:5.10.5")
|
testImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
|
||||||
// testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
|
// testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,8 +210,6 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileTestKotlin {
|
compileTestKotlin {
|
||||||
enabled = false
|
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = javaVersion
|
jvmTarget = javaVersion
|
||||||
apiVersion = "1.9"
|
apiVersion = "1.9"
|
||||||
@@ -235,7 +229,6 @@ tasks {
|
|||||||
|
|
||||||
// Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
|
// Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
|
||||||
// Note that the version must be greater than the plugin's target version, for obvious reasons
|
// Note that the version must be greater than the plugin's target version, for obvious reasons
|
||||||
// You can also set splitMode and splitModeTarget here to test split mode in a custom IDE
|
|
||||||
// val runIdeCustom by intellijPlatformTesting.runIde.registering {
|
// val runIdeCustom by intellijPlatformTesting.runIde.registering {
|
||||||
// type = IntelliJPlatformType.Rider
|
// type = IntelliJPlatformType.Rider
|
||||||
// version = "2024.1.2"
|
// version = "2024.1.2"
|
||||||
@@ -268,6 +261,10 @@ tasks {
|
|||||||
val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
|
val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
|
||||||
splitMode = true
|
splitMode = true
|
||||||
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
|
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
|
||||||
|
|
||||||
|
// Frontend split mode support requires 242+
|
||||||
|
// TODO: Remove this once IdeaVim targets 242, as the task will naturally use the target version to run
|
||||||
|
version.set(splitModeVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add plugin open API sources to the plugin ZIP
|
// Add plugin open API sources to the plugin ZIP
|
||||||
|
@@ -322,9 +322,6 @@ If you want to optimize highlight duration, assign a time in milliseconds:
|
|||||||
If you want to change background color of highlight you can provide the rgba of the color you want e.g.
|
If you want to change background color of highlight you can provide the rgba of the color you want e.g.
|
||||||
`let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"`
|
`let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"`
|
||||||
|
|
||||||
If you want to change text color of highlight you can provide the rgba of the color you want e.g.
|
|
||||||
`let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"`
|
|
||||||
|
|
||||||
https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt
|
https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
@@ -438,50 +435,3 @@ Original plugin: [vim-which-key](https://github.com/liuchengxu/vim-which-key).
|
|||||||
https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation
|
https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
|
||||||
<summary><h2>Vim Peekaboo</h2></summary>
|
|
||||||
|
|
||||||
By Julien Phalip
|
|
||||||
Original plugin: [vim-peekaboo](https://github.com/junegunn/vim-peekaboo).
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
Add `set peekaboo` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
|
|
||||||
or restart the IDE.
|
|
||||||
|
|
||||||
### Instructions
|
|
||||||
|
|
||||||
https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h2>FunctionTextObj</h2></summary>
|
|
||||||
|
|
||||||
By Julien Phalip
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
Add `set functiontextobj` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
|
|
||||||
or restart the IDE.
|
|
||||||
|
|
||||||
### Instructions
|
|
||||||
|
|
||||||
https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h2>Switch</h2></summary>
|
|
||||||
|
|
||||||
By Julien Phalip
|
|
||||||
Original plugin: [switch.vim](https://github.com/AndrewRadev/switch.vim).
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
Add `set switch` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
|
|
||||||
or restart the IDE.
|
|
||||||
|
|
||||||
### Instructions
|
|
||||||
|
|
||||||
https://plugins.jetbrains.com/plugin/25899-vim-switch
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
@@ -8,7 +8,7 @@ Every effort is made to make these options compatible with Vim behaviour.
|
|||||||
However, some differences are inevitable.
|
However, some differences are inevitable.
|
||||||
|
|
||||||
```
|
```
|
||||||
'clipboard' 'cb' Defines clipboard behavior
|
'clipboard' 'cb' Defines clipboard behavioue
|
||||||
A comma-separated list of words to control clipboard behaviour:
|
A comma-separated list of words to control clipboard behaviour:
|
||||||
unnamed The clipboard register '*' is used instead of the
|
unnamed The clipboard register '*' is used instead of the
|
||||||
unnamed register
|
unnamed register
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
# Support Guide
|
# Support Guide
|
||||||
|
|
||||||
This document is created to help our support team.
|
This document is created to help our support team.
|
||||||
It's not intended to be read by the users as it brings no value to them.
|
It's not intended to be read by the users as it brings to value to them.
|
||||||
|
|
||||||
## Support channels
|
## Support channels
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ It's not intended to be read by the users as it brings no value to them.
|
|||||||
IdeaVim has multiple YouTrack statuses, main are:
|
IdeaVim has multiple YouTrack statuses, main are:
|
||||||
|
|
||||||
- Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets.
|
- Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets.
|
||||||
- Open: issues is processed by our team, what means that the issues is reproduced and accepted
|
- Open: issues is processed by out team, what means that the issues is reproduced and accepted
|
||||||
- Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the
|
- Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the
|
||||||
user doesn't reply in 30 days.
|
user doesn't reply in 30 days.
|
||||||
- Ready To Release: Bug is fixed, but not yet released
|
- Ready To Release: Bug is fixed, but not yet released
|
||||||
|
@@ -20,11 +20,17 @@ 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=chylex-42
|
version=chylex-38
|
||||||
javaVersion=17
|
javaVersion=17
|
||||||
remoteRobotVersion=0.11.23
|
remoteRobotVersion=0.11.23
|
||||||
antlrVersion=4.10.1
|
antlrVersion=4.10.1
|
||||||
|
|
||||||
|
# [VERSION UPDATE] 2024.2 - remove when IdeaVim targets 2024.2
|
||||||
|
# Running IdeaVim in split mode requires 242. Update this version once 242 has been released, and remove it completely
|
||||||
|
# when IdeaVim targets 242, at which point runIdeSplitMode will run correctly with the target version.
|
||||||
|
# See also runIdeSplitMode
|
||||||
|
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
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
22
gradlew
vendored
22
gradlew
vendored
@@ -15,8 +15,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -57,7 +55,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -85,9 +83,7 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -148,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@@ -156,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -205,11 +201,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command;
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
# and any embedded shellness will be escaped.
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -13,8 +13,6 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -45,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -59,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ 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/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
|
- 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
|
||||||
|
@@ -20,17 +20,17 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.25")
|
||||||
|
|
||||||
implementation("io.ktor:ktor-client-core:3.0.2")
|
implementation("io.ktor:ktor-client-core:2.3.12")
|
||||||
implementation("io.ktor:ktor-client-cio:3.0.2")
|
implementation("io.ktor:ktor-client-cio:2.3.10")
|
||||||
implementation("io.ktor:ktor-client-content-negotiation:3.0.2")
|
implementation("io.ktor:ktor-client-content-negotiation:2.3.10")
|
||||||
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.2")
|
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
|
||||||
implementation("io.ktor:ktor-client-auth:3.0.2")
|
implementation("io.ktor:ktor-client-auth:2.3.12")
|
||||||
implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
|
||||||
|
|
||||||
// This is needed for jgit to connect to ssh
|
// This is needed for jgit to connect to ssh
|
||||||
implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r")
|
implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
|
||||||
implementation("com.vdurmont:semver4j:3.1.0")
|
implementation("com.vdurmont:semver4j:3.1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,9 +40,6 @@ val knownPlugins = setOf(
|
|||||||
"com.protoseo.input-source-auto-converter",
|
"com.protoseo.input-source-auto-converter",
|
||||||
|
|
||||||
// "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
|
// "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
|
||||||
"com.julienphalip.ideavim.peekaboo", // https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
|
|
||||||
"com.julienphalip.ideavim.switch", // https://plugins.jetbrains.com/plugin/25899-vim-switch
|
|
||||||
"com.julienphalip.ideavim.functiontextobj", // https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
|
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun main() {
|
suspend fun main() {
|
||||||
|
@@ -8,10 +8,6 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim
|
package com.maddyhome.idea.vim
|
||||||
|
|
||||||
import com.intellij.ide.BrowserUtil
|
|
||||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
|
||||||
import com.intellij.ide.plugins.PluginStateListener
|
|
||||||
import com.intellij.ide.plugins.PluginStateManager
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
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
|
||||||
@@ -33,9 +29,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
|
|||||||
|
|
||||||
private var firstInitializationOccurred = false
|
private var firstInitializationOccurred = false
|
||||||
|
|
||||||
// TODO
|
|
||||||
// We should migrate to some solution from https://plugins.jetbrains.com/docs/intellij/plugin-components.html#application-startup
|
|
||||||
// If you'd like to add a new code here, please consider using one of the things described there.
|
|
||||||
override suspend fun execute(project: Project) {
|
override suspend fun execute(project: Project) {
|
||||||
if (firstInitializationOccurred) return
|
if (firstInitializationOccurred) return
|
||||||
firstInitializationOccurred = true
|
firstInitializationOccurred = true
|
||||||
@@ -47,18 +40,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
|
|||||||
|
|
||||||
// This code should be executed once
|
// This code should be executed once
|
||||||
VimPlugin.getInstance().initialize()
|
VimPlugin.getInstance().initialize()
|
||||||
|
|
||||||
// Uninstall survey. Should be registered once for all projects
|
|
||||||
PluginStateManager.addStateListener(object : PluginStateListener {
|
|
||||||
override fun install(p0: IdeaPluginDescriptor) {/*Nothing*/
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun uninstall(descriptor: IdeaPluginDescriptor) {
|
|
||||||
if (descriptor.pluginId == VimPlugin.getPluginId()) {
|
|
||||||
BrowserUtil.open("https://surveys.jetbrains.com/s3/ideavim-uninstall-feedback")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,6 @@ package com.maddyhome.idea.vim;
|
|||||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||||
import com.intellij.ide.plugins.PluginManagerCore;
|
import com.intellij.ide.plugins.PluginManagerCore;
|
||||||
import com.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
import com.intellij.openapi.application.AccessToken;
|
|
||||||
import com.intellij.openapi.application.Application;
|
import com.intellij.openapi.application.Application;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.components.PersistentStateComponent;
|
import com.intellij.openapi.components.PersistentStateComponent;
|
||||||
@@ -25,8 +24,10 @@ import com.intellij.openapi.project.Project;
|
|||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
import com.intellij.openapi.util.Disposer;
|
import com.intellij.openapi.util.Disposer;
|
||||||
import com.intellij.openapi.util.SystemInfo;
|
import com.intellij.openapi.util.SystemInfo;
|
||||||
import com.intellij.util.SlowOperations;
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
import com.maddyhome.idea.vim.api.*;
|
import com.maddyhome.idea.vim.api.VimInjectorKt;
|
||||||
|
import com.maddyhome.idea.vim.api.VimKeyGroup;
|
||||||
|
import com.maddyhome.idea.vim.api.VimOptionGroup;
|
||||||
import com.maddyhome.idea.vim.config.VimState;
|
import com.maddyhome.idea.vim.config.VimState;
|
||||||
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
|
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
|
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
|
||||||
@@ -35,6 +36,7 @@ import com.maddyhome.idea.vim.group.copy.PutGroup;
|
|||||||
import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
|
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.IjVimInjectorKt;
|
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;
|
||||||
@@ -139,8 +141,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
|
|||||||
return (MacroGroup)VimInjectorKt.getInjector().getMacro();
|
return (MacroGroup)VimInjectorKt.getInjector().getMacro();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull VimDigraphGroup getDigraph() {
|
public static @NotNull DigraphGroup getDigraph() {
|
||||||
return VimInjectorKt.getInjector().getDigraphGroup();
|
return (DigraphGroup)VimInjectorKt.getInjector().getDigraphGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull HistoryGroup getHistory() {
|
public static @NotNull HistoryGroup getHistory() {
|
||||||
@@ -337,9 +339,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
|
|||||||
|
|
||||||
// 4) ~/.ideavimrc execution
|
// 4) ~/.ideavimrc execution
|
||||||
// Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
|
// Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
|
||||||
try (AccessToken ignore = SlowOperations.knownIssue("VIM-3661")) {
|
|
||||||
registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
|
registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
|
||||||
}
|
|
||||||
|
|
||||||
// Turing on should be performed after all commands registration
|
// Turing on should be performed after all commands registration
|
||||||
getSearch().turnOn();
|
getSearch().turnOn();
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
package com.maddyhome.idea.vim.action
|
|
||||||
|
|
||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
|
||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
|
|
||||||
import com.intellij.openapi.command.WriteCommandAction
|
|
||||||
import com.intellij.openapi.fileEditor.TextEditor
|
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
|
||||||
import com.intellij.openapi.project.DumbAwareAction
|
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
|
|
||||||
class VimRunLastMacroInOpenFiles : DumbAwareAction() {
|
|
||||||
override fun update(e: AnActionEvent) {
|
|
||||||
val lastRegister = injector.macro.lastRegister
|
|
||||||
val isEnabled = lastRegister != 0.toChar()
|
|
||||||
|
|
||||||
e.presentation.isEnabled = isEnabled
|
|
||||||
e.presentation.text = if (isEnabled) "Run Macro '${lastRegister}' in Open Files" else "Run Last Macro in Open Files"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
|
||||||
return ActionUpdateThread.EDT
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun actionPerformed(e: AnActionEvent) {
|
|
||||||
val project = e.project ?: return
|
|
||||||
val fileEditorManager = FileEditorManagerEx.getInstanceExIfCreated(project) ?: return
|
|
||||||
val editors = fileEditorManager.allEditors.filterIsInstance<TextEditor>()
|
|
||||||
|
|
||||||
WriteCommandAction.writeCommandAction(project)
|
|
||||||
.withName(e.presentation.text)
|
|
||||||
.withGlobalUndo()
|
|
||||||
.withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION)
|
|
||||||
.run<RuntimeException> {
|
|
||||||
val reg = injector.macro.lastRegister
|
|
||||||
|
|
||||||
for (editor in editors) {
|
|
||||||
fileEditorManager.openFile(editor.file, true)
|
|
||||||
|
|
||||||
val vimEditor = editor.editor.vim
|
|
||||||
vimEditor.mode = Mode.NORMAL()
|
|
||||||
KeyHandler.getInstance().reset(vimEditor)
|
|
||||||
|
|
||||||
injector.macro.playbackRegister(vimEditor, IjEditorExecutionContext(e.dataContext), reg, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -298,10 +298,26 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
|
|||||||
.addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK))
|
.addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK))
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0))
|
.addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0))
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK))
|
.addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK))
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_UP, 0))
|
.addAll(getKeyStrokes(KeyEvent.VK_UP, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0))
|
.addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_LEFT, 0))
|
.addAll(
|
||||||
.addAll(getKeyStrokes(KeyEvent.VK_RIGHT, 0))
|
getKeyStrokes(
|
||||||
|
KeyEvent.VK_LEFT,
|
||||||
|
0,
|
||||||
|
InputEvent.CTRL_DOWN_MASK,
|
||||||
|
InputEvent.SHIFT_DOWN_MASK,
|
||||||
|
InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.addAll(
|
||||||
|
getKeyStrokes(
|
||||||
|
KeyEvent.VK_RIGHT,
|
||||||
|
0,
|
||||||
|
InputEvent.CTRL_DOWN_MASK,
|
||||||
|
InputEvent.SHIFT_DOWN_MASK,
|
||||||
|
InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
|
||||||
|
),
|
||||||
|
)
|
||||||
.addAll(
|
.addAll(
|
||||||
getKeyStrokes(
|
getKeyStrokes(
|
||||||
KeyEvent.VK_HOME,
|
KeyEvent.VK_HOME,
|
||||||
|
@@ -37,7 +37,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
|
|||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
|
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
|
||||||
|
|
||||||
// todo make it multicaret
|
// todo make it multicaret
|
||||||
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, motionType: SelectionType): Boolean {
|
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
|
||||||
val func = injector.globalOptions().operatorfunc
|
val func = injector.globalOptions().operatorfunc
|
||||||
if (func.isEmpty()) {
|
if (func.isEmpty()) {
|
||||||
VimPlugin.showMessage(MessageHelper.message("E774"))
|
VimPlugin.showMessage(MessageHelper.message("E774"))
|
||||||
@@ -57,9 +57,9 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
|
|||||||
if (value is VimFuncref) {
|
if (value is VimFuncref) {
|
||||||
handler = value.handler
|
handler = value.handler
|
||||||
}
|
}
|
||||||
} catch (_: ExException) {
|
} catch (ex: ExException) {
|
||||||
// Get the argument for function('...') or funcref('...') for the error message
|
// Get the argument for function('...') or funcref('...') for the error message
|
||||||
val functionName = if (expression is FunctionCallExpression && expression.arguments.isNotEmpty()) {
|
val functionName = if (expression is FunctionCallExpression && expression.arguments.size > 0) {
|
||||||
expression.arguments[0].evaluate(editor, context, scriptContext).toString()
|
expression.arguments[0].evaluate(editor, context, scriptContext).toString()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -77,7 +77,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val arg = when (motionType) {
|
val arg = when (selectionType) {
|
||||||
SelectionType.LINE_WISE -> "line"
|
SelectionType.LINE_WISE -> "line"
|
||||||
SelectionType.CHARACTER_WISE -> "char"
|
SelectionType.CHARACTER_WISE -> "char"
|
||||||
SelectionType.BLOCK_WISE -> "block"
|
SelectionType.BLOCK_WISE -> "block"
|
||||||
@@ -101,13 +101,19 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
|
|||||||
override val argumentType: Argument.Type = Argument.Type.MOTION
|
override val argumentType: Argument.Type = Argument.Type.MOTION
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
val argument = cmd.argument as? Argument.Motion ?: return false
|
val argument = cmd.argument ?: return false
|
||||||
if (!editor.inRepeatMode) {
|
if (!editor.inRepeatMode) {
|
||||||
argumentCaptured = argument
|
argumentCaptured = argument
|
||||||
}
|
}
|
||||||
val range = getMotionRange(editor, context, argument, operatorArguments)
|
val range = getMotionRange(editor, context, argument, operatorArguments)
|
||||||
|
|
||||||
if (range != null) {
|
if (range != null) {
|
||||||
return doOperatorAction(editor, context, range, argument.getMotionType())
|
val selectionType = if (argument.motion.isLinewiseMotion()) {
|
||||||
|
SelectionType.LINE_WISE
|
||||||
|
} else {
|
||||||
|
SelectionType.CHARACTER_WISE
|
||||||
|
}
|
||||||
|
return doOperatorAction(editor, context, range, selectionType)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -115,7 +121,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
|
|||||||
private fun getMotionRange(
|
private fun getMotionRange(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
argument: Argument.Motion,
|
argument: Argument,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): TextRange? {
|
): TextRange? {
|
||||||
// Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
|
// Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
|
||||||
@@ -130,7 +136,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
|
|||||||
operatorArguments,
|
operatorArguments,
|
||||||
)?.normalize()?.let {
|
)?.normalize()?.let {
|
||||||
// If we're linewise, make sure the end offset isn't just the EOL char
|
// If we're linewise, make sure the end offset isn't just the EOL char
|
||||||
if (argument.getMotionType() == SelectionType.LINE_WISE && it.endOffset < editor.fileSize()) {
|
if (argument.motion.isLinewiseMotion() && it.endOffset < editor.fileSize()) {
|
||||||
TextRange(it.startOffset, it.endOffset + 1)
|
TextRange(it.startOffset, it.endOffset + 1)
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
|
@@ -25,7 +25,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
|
|||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
val state = injector.vimState
|
val state = injector.vimState
|
||||||
var lastCommand = VimRepeater.lastChangeCommand
|
val lastCommand = VimRepeater.lastChangeCommand
|
||||||
|
|
||||||
if (lastCommand == null && Extension.lastExtensionHandler == null) return false
|
if (lastCommand == null && Extension.lastExtensionHandler == null) return false
|
||||||
|
|
||||||
@@ -57,7 +57,12 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
|
|||||||
)
|
)
|
||||||
} else if (!repeatHandler && lastCommand != null) {
|
} else if (!repeatHandler && lastCommand != null) {
|
||||||
if (cmd.rawCount > 0) {
|
if (cmd.rawCount > 0) {
|
||||||
lastCommand = lastCommand.copy(rawCount = cmd.rawCount)
|
lastCommand.rawCount = cmd.count
|
||||||
|
val arg = lastCommand.argument
|
||||||
|
if (arg != null) {
|
||||||
|
val mot = arg.motion
|
||||||
|
mot.rawCount = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state.executingCommand = lastCommand
|
state.executingCommand = lastCommand
|
||||||
|
|
||||||
|
@@ -40,7 +40,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecuti
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
injector.editorGroup.notifyIdeaJoin(editor)
|
injector.editorGroup.notifyIdeaJoin(editor)
|
||||||
|
|
||||||
return injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, false)
|
return injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(
|
override fun execute(
|
||||||
|
@@ -35,7 +35,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
|
|||||||
injector.editorGroup.notifyIdeaJoin(editor)
|
injector.editorGroup.notifyIdeaJoin(editor)
|
||||||
var res = true
|
var res = true
|
||||||
editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
|
editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
|
||||||
if (!injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, true)) {
|
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) {
|
||||||
res = false
|
res = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution(
|
|||||||
val range = caretsAndSelections[caret] ?: return@forEach
|
val range = caretsAndSelections[caret] ?: return@forEach
|
||||||
if (!injector.changeGroup.deleteJoinRange(
|
if (!injector.changeGroup.deleteJoinRange(
|
||||||
editor,
|
editor,
|
||||||
context,
|
|
||||||
caret,
|
caret,
|
||||||
range.toVimTextRange(true).normalize(),
|
range.toVimTextRange(true).normalize(),
|
||||||
false,
|
false,
|
||||||
|
@@ -44,7 +44,6 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec
|
|||||||
val range = caretsAndSelections[caret] ?: return@forEach
|
val range = caretsAndSelections[caret] ?: return@forEach
|
||||||
if (!injector.changeGroup.deleteJoinRange(
|
if (!injector.changeGroup.deleteJoinRange(
|
||||||
editor,
|
editor,
|
||||||
context,
|
|
||||||
caret,
|
caret,
|
||||||
range.toVimTextRange(true).normalize(),
|
range.toVimTextRange(true).normalize(),
|
||||||
true,
|
true,
|
||||||
|
@@ -20,10 +20,13 @@ import com.maddyhome.idea.vim.command.OperatorArguments
|
|||||||
import com.maddyhome.idea.vim.handler.IdeActionHandler
|
import com.maddyhome.idea.vim.handler.IdeActionHandler
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
import com.maddyhome.idea.vim.helper.enumSetOf
|
import com.maddyhome.idea.vim.helper.enumSetOf
|
||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
|
|
||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@CommandOrMotion(keys = ["<C-H>", "<BS>"], modes = [Mode.INSERT])
|
||||||
|
internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE) {
|
||||||
|
override val type: Command.Type = Command.Type.DELETE
|
||||||
|
}
|
||||||
|
|
||||||
@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
|
@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
|
||||||
internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE) {
|
internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE) {
|
||||||
override val type: Command.Type = Command.Type.DELETE
|
override val type: Command.Type = Command.Type.DELETE
|
||||||
@@ -41,13 +44,8 @@ internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CA
|
|||||||
operatorArguments: OperatorArguments
|
operatorArguments: OperatorArguments
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val undo = injector.undo
|
val undo = injector.undo
|
||||||
when (undo) {
|
|
||||||
is VimKeyBasedUndoService -> undo.setMergeUndoKey()
|
|
||||||
is VimTimestampBasedUndoService -> {
|
|
||||||
val nanoTime = System.nanoTime()
|
val nanoTime = System.nanoTime()
|
||||||
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.execute(editor, context, cmd, operatorArguments)
|
return super.execute(editor, context, cmd, operatorArguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,13 +68,8 @@ internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARE
|
|||||||
operatorArguments: OperatorArguments
|
operatorArguments: OperatorArguments
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val undo = injector.undo
|
val undo = injector.undo
|
||||||
when (undo) {
|
|
||||||
is VimKeyBasedUndoService -> undo.setMergeUndoKey()
|
|
||||||
is VimTimestampBasedUndoService -> {
|
|
||||||
val nanoTime = System.nanoTime()
|
val nanoTime = System.nanoTime()
|
||||||
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.execute(editor, context, cmd, operatorArguments)
|
return super.execute(editor, context, cmd, operatorArguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,30 +27,6 @@ public interface VimExtension {
|
|||||||
return MappingOwner.Plugin.Companion.get(getName());
|
return MappingOwner.Plugin.Companion.get(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is always called AFTER the full execution of the `.ideavimrc` file.
|
|
||||||
* <p>
|
|
||||||
* During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
|
|
||||||
* This practically means that the .vimrc file is initialized first; then the plugins are loaded.
|
|
||||||
* See `:h initialization`
|
|
||||||
* <p>
|
|
||||||
* Why does this matter? Because this affects the order of commands are executed. For example,
|
|
||||||
* ```
|
|
||||||
* plug 'tommcdo/vim-exchange'
|
|
||||||
* let g:exchange_no_mappings=1
|
|
||||||
* ```
|
|
||||||
* Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
|
|
||||||
* immediately, this variable won't be initialized at the moment of plugin initialization.
|
|
||||||
* <p>
|
|
||||||
* There is also a tricky case for mappings override:
|
|
||||||
* ```
|
|
||||||
* plug 'tommcdo/vim-exchange'
|
|
||||||
* map X <Plug>(ExchangeLine)
|
|
||||||
* ```
|
|
||||||
* For this case, a plugin with a good implementation detects that there is already a defined mapping for
|
|
||||||
* `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
|
|
||||||
* to be defined before the plugin initialization.
|
|
||||||
*/
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
default void dispose() {
|
default void dispose() {
|
||||||
|
@@ -69,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"
|
||||||
@@ -188,22 +189,14 @@ object VimExtensionFacade {
|
|||||||
|
|
||||||
/** Get the current contents of the given register similar to 'getreg()'. */
|
/** Get the current contents of the given register similar to 'getreg()'. */
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Please use com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister(com.maddyhome.idea.vim.api.VimEditor, char)")
|
|
||||||
fun getRegister(register: Char): List<KeyStroke>? {
|
fun getRegister(register: Char): List<KeyStroke>? {
|
||||||
val reg = VimPlugin.getRegister().getRegister(register) ?: return null
|
val reg = VimPlugin.getRegister().getRegister(register) ?: return null
|
||||||
return reg.keys
|
return reg.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the current contents of the given register similar to 'getreg()'. */
|
|
||||||
@JvmStatic
|
|
||||||
fun getRegister(editor: VimEditor, register: Char): List<KeyStroke>? {
|
|
||||||
val reg = VimPlugin.getRegister().getRegister(editor, injector.executionContextManager.getEditorExecutionContext(editor), register) ?: return null
|
|
||||||
return reg.keys
|
|
||||||
}
|
|
||||||
|
|
||||||
@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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,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 */
|
||||||
|
@@ -88,10 +88,29 @@ internal object VimExtensionRegistrar : VimExtensionRegistrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the docs for [VimExtension.init]
|
* During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
|
||||||
|
* This practically means that the .vimrc file is initialized first, then the plugins are loaded.
|
||||||
|
* See `:h initialization`
|
||||||
*
|
*
|
||||||
* In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
|
* In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
|
||||||
* the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
|
* the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
|
||||||
|
*
|
||||||
|
* Why this matters? Because this affects the order of commands are executed. For example:
|
||||||
|
* ```
|
||||||
|
* plug 'tommcdo/vim-exchange'
|
||||||
|
* let g:exchange_no_mappings=1
|
||||||
|
* ```
|
||||||
|
* Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
|
||||||
|
* immediately, this variable won't be initialized at the moment of plugin initialization.
|
||||||
|
*
|
||||||
|
* There is also a tricky case for mappings override:
|
||||||
|
* ```
|
||||||
|
* plug 'tommcdo/vim-exchange'
|
||||||
|
* map X <Plug>(ExchangeLine)
|
||||||
|
* ```
|
||||||
|
* For this case, a plugin with a good implementation detects that there is already a defined mapping for
|
||||||
|
* `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
|
||||||
|
* to be defined before the plugin initialization.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun enableDelayedExtensions() {
|
fun enableDelayedExtensions() {
|
||||||
|
@@ -33,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
|
||||||
@@ -63,8 +64,8 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
*/
|
*/
|
||||||
private static class BracketPairs {
|
private static class BracketPairs {
|
||||||
// NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
|
// NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
|
||||||
private final @NotNull String openBrackets;
|
@NotNull private final String openBrackets;
|
||||||
private final @NotNull String closeBrackets;
|
@NotNull private final String closeBrackets;
|
||||||
|
|
||||||
static class ParseException extends Exception {
|
static class ParseException extends Exception {
|
||||||
public ParseException(@NotNull String message) {
|
public ParseException(@NotNull String message) {
|
||||||
@@ -86,7 +87,8 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
* @param bracketPairs comma-separated list of colon-separated bracket pairs.
|
* @param bracketPairs comma-separated list of colon-separated bracket pairs.
|
||||||
* @throws ParseException if a syntax error is detected.
|
* @throws ParseException if a syntax error is detected.
|
||||||
*/
|
*/
|
||||||
static @NotNull BracketPairs fromBracketPairList(final @NotNull String bracketPairs) throws ParseException {
|
@NotNull
|
||||||
|
static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseException {
|
||||||
StringBuilder openBrackets = new StringBuilder();
|
StringBuilder openBrackets = new StringBuilder();
|
||||||
StringBuilder closeBrackets = new StringBuilder();
|
StringBuilder closeBrackets = new StringBuilder();
|
||||||
ParseState state = ParseState.OPEN;
|
ParseState state = ParseState.OPEN;
|
||||||
@@ -126,7 +128,7 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
|
return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
BracketPairs(final @NotNull String openBrackets, final @NotNull String closeBrackets) {
|
BracketPairs(@NotNull final String openBrackets, @NotNull final String closeBrackets) {
|
||||||
assert openBrackets.length() == closeBrackets.length();
|
assert openBrackets.length() == closeBrackets.length();
|
||||||
this.openBrackets = openBrackets;
|
this.openBrackets = openBrackets;
|
||||||
this.closeBrackets = closeBrackets;
|
this.closeBrackets = closeBrackets;
|
||||||
@@ -156,9 +158,10 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
|
public static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
|
||||||
|
|
||||||
private static @Nullable String bracketPairsVariable() {
|
@Nullable
|
||||||
|
private static String bracketPairsVariable() {
|
||||||
final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
|
final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
|
||||||
if (value instanceof VimString vimValue) {
|
if (value instanceof VimString vimValue) {
|
||||||
return vimValue.getValue();
|
return vimValue.getValue();
|
||||||
@@ -189,8 +192,9 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
this.isInner = isInner;
|
this.isInner = isInner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable TextRange getRange(@NotNull VimEditor editor,
|
public TextRange getRange(@NotNull VimEditor editor,
|
||||||
@NotNull ImmutableVimCaret caret,
|
@NotNull ImmutableVimCaret caret,
|
||||||
@NotNull ExecutionContext context,
|
@NotNull ExecutionContext context,
|
||||||
int count,
|
int count,
|
||||||
@@ -232,22 +236,24 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
return new TextRange(finder.getLeftBound(), finder.getRightBound());
|
return new TextRange(finder.getLeftBound(), finder.getRightBound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull TextObjectVisualType getVisualType() {
|
public TextObjectVisualType getVisualType() {
|
||||||
return TextObjectVisualType.CHARACTER_WISE;
|
return TextObjectVisualType.CHARACTER_WISE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
||||||
|
@NotNull KeyHandler keyHandler = KeyHandler.getInstance();
|
||||||
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
||||||
|
int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
|
||||||
|
|
||||||
final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
|
final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
|
||||||
//noinspection DuplicatedCode
|
//noinspection DuplicatedCode
|
||||||
if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
|
if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
|
||||||
int count0 = operatorArguments.getCount0();
|
|
||||||
editor.nativeCarets().forEach((VimCaret caret) -> {
|
editor.nativeCarets().forEach((VimCaret caret) -> {
|
||||||
final TextRange range = textObjectHandler.getRange(editor, caret, context, Math.max(1, count0), count0);
|
final TextRange range = textObjectHandler.getRange(editor, caret, context, count, 0);
|
||||||
if (range != null) {
|
if (range != null) {
|
||||||
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
||||||
if (editor.getMode() instanceof Mode.VISUAL) {
|
if (editor.getMode() instanceof Mode.VISUAL) {
|
||||||
@@ -259,7 +265,8 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
|
keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
|
||||||
|
textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,9 +276,9 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
* position
|
* position
|
||||||
*/
|
*/
|
||||||
private static class ArgBoundsFinder {
|
private static class ArgBoundsFinder {
|
||||||
private final @NotNull CharSequence text;
|
@NotNull private final CharSequence text;
|
||||||
private final @NotNull Document document;
|
@NotNull private final Document document;
|
||||||
private final @NotNull BracketPairs brackets;
|
@NotNull private final BracketPairs brackets;
|
||||||
private int leftBound = Integer.MAX_VALUE;
|
private int leftBound = Integer.MAX_VALUE;
|
||||||
private int rightBound = Integer.MIN_VALUE;
|
private int rightBound = Integer.MIN_VALUE;
|
||||||
private int leftBracket;
|
private int leftBracket;
|
||||||
@@ -298,7 +305,7 @@ public class VimArgTextObjExtension implements VimExtension {
|
|||||||
* @param position starting position.
|
* @param position starting position.
|
||||||
*/
|
*/
|
||||||
boolean findBoundsAt(int position) throws IllegalStateException {
|
boolean findBoundsAt(int position) throws IllegalStateException {
|
||||||
if (text.isEmpty()) {
|
if (text.length() == 0) {
|
||||||
error = "empty document";
|
error = "empty document";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,9 @@ 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.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.command.Argument
|
||||||
|
import com.maddyhome.idea.vim.command.Command
|
||||||
|
import com.maddyhome.idea.vim.command.CommandFlags
|
||||||
import com.maddyhome.idea.vim.command.MappingMode
|
import com.maddyhome.idea.vim.command.MappingMode
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.command.TextObjectVisualType
|
import com.maddyhome.idea.vim.command.TextObjectVisualType
|
||||||
@@ -49,6 +52,7 @@ 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.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
internal class CommentaryExtension : VimExtension {
|
internal class CommentaryExtension : VimExtension {
|
||||||
|
|
||||||
@@ -180,8 +184,10 @@ internal class CommentaryExtension : VimExtension {
|
|||||||
override val isRepeatable = true
|
override val isRepeatable = true
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
|
val command = Command(operatorArguments.count1, CommentaryTextObjectMotionHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags::class.java))
|
||||||
|
|
||||||
val keyState = KeyHandler.getInstance().keyHandlerState
|
val keyState = KeyHandler.getInstance().keyHandlerState
|
||||||
keyState.commandBuilder.addAction(CommentaryTextObjectMotionHandler)
|
keyState.commandBuilder.completeCommandPart(Argument(command))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -222,10 +222,10 @@ internal class VimExchangeExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val zRegText = getRegister(editor.vim, 'z')
|
val zRegText = getRegister('z')
|
||||||
val unnRegText = getRegister(editor.vim, '"')
|
val unnRegText = getRegister('"')
|
||||||
val startRegText = getRegister(editor.vim, '*')
|
val startRegText = getRegister('*')
|
||||||
val plusRegText = getRegister(editor.vim, '+')
|
val plusRegText = getRegister('+')
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
// TODO handle:
|
// TODO handle:
|
||||||
// " Compare using =~ because "'==' != 0" returns 0
|
// " Compare using =~ because "'==' != 0" returns 0
|
||||||
@@ -299,7 +299,7 @@ internal class VimExchangeExtension : VimExtension {
|
|||||||
|
|
||||||
private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange {
|
private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange {
|
||||||
// TODO: improve KeyStroke list to sting conversion
|
// TODO: improve KeyStroke list to sting conversion
|
||||||
fun getRegisterText(reg: Char): String = getRegister(editor.vim, reg)?.map { it.keyChar }?.joinToString("") ?: ""
|
fun getRegisterText(reg: Char): String = getRegister(reg)?.map { it.keyChar }?.joinToString("") ?: ""
|
||||||
fun getMarks(isVisual: Boolean): Pair<Mark, Mark> {
|
fun getMarks(isVisual: Boolean): Pair<Mark, Mark> {
|
||||||
val (startMark, endMark) =
|
val (startMark, endMark) =
|
||||||
if (isVisual) {
|
if (isVisual) {
|
||||||
@@ -313,9 +313,9 @@ internal class VimExchangeExtension : VimExtension {
|
|||||||
return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!)
|
return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
val unnRegText = getRegister(editor.vim, '"')
|
val unnRegText = getRegister('"')
|
||||||
val starRegText = getRegister(editor.vim, '*')
|
val starRegText = getRegister('*')
|
||||||
val plusRegText = getRegister(editor.vim, '+')
|
val plusRegText = getRegister('+')
|
||||||
|
|
||||||
val (selectionStart, selectionEnd) = getMarks(isVisual)
|
val (selectionStart, selectionEnd) = getMarks(isVisual)
|
||||||
if (isVisual) {
|
if (isVisual) {
|
||||||
|
@@ -45,10 +45,6 @@ private val HIGHLIGHT_DURATION_VARIABLE_NAME = "highlightedyank_highlight_durati
|
|||||||
|
|
||||||
@NonNls
|
@NonNls
|
||||||
private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color"
|
private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color"
|
||||||
|
|
||||||
@NonNls
|
|
||||||
private val HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME = "highlightedyank_highlight_foreground_color"
|
|
||||||
|
|
||||||
private var defaultHighlightTextColor: Color? = null
|
private var defaultHighlightTextColor: Color? = null
|
||||||
|
|
||||||
private fun getDefaultHighlightTextColor(): Color {
|
private fun getDefaultHighlightTextColor(): Color {
|
||||||
@@ -79,9 +75,6 @@ internal class HighlightColorResetter : LafManagerListener {
|
|||||||
* if you want to change background color of highlight you can provide the rgba of the color you want e.g.
|
* if you want to change background color of highlight you can provide the rgba of the color you want e.g.
|
||||||
* let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"
|
* let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"
|
||||||
*
|
*
|
||||||
* if you want to change text color of highlight you can provide the rgba of the color you want e.g.
|
|
||||||
* let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"
|
|
||||||
*
|
|
||||||
* When a new text is yanked or user starts editing, the old highlighting would be deleted.
|
* When a new text is yanked or user starts editing, the old highlighting would be deleted.
|
||||||
*/
|
*/
|
||||||
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
|
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
|
||||||
@@ -188,15 +181,13 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
|||||||
highlighters.clear()
|
highlighters.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHighlightTextAttributes(editor: Editor): TextAttributes {
|
private fun getHighlightTextAttributes(editor: Editor) = TextAttributes(
|
||||||
return TextAttributes(
|
null,
|
||||||
extractUserHighlightForegroundColor(),
|
|
||||||
extractUsersHighlightColor(),
|
extractUsersHighlightColor(),
|
||||||
editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
|
editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
|
||||||
EffectType.SEARCH_MATCH,
|
EffectType.SEARCH_MATCH,
|
||||||
Font.PLAIN,
|
Font.PLAIN,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractUsersHighlightDuration(): Int {
|
private fun extractUsersHighlightDuration(): Int {
|
||||||
return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) {
|
return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) {
|
||||||
@@ -209,52 +200,15 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun extractUsersHighlightColor(): Color {
|
private fun extractUsersHighlightColor(): Color {
|
||||||
val value = VimPlugin.getVariableService().getGlobalVariableValue(HIGHLIGHT_COLOR_VARIABLE_NAME)
|
return extractVariable(HIGHLIGHT_COLOR_VARIABLE_NAME, getDefaultHighlightTextColor()) { value ->
|
||||||
if (value != null) {
|
val rgba = value.asString()
|
||||||
return try {
|
|
||||||
parseRgbaColor(value.asString())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
@VimNlsSafe val message = MessageHelper.message(
|
|
||||||
"highlightedyank.invalid.value.of.0.1",
|
|
||||||
"g:$HIGHLIGHT_COLOR_VARIABLE_NAME",
|
|
||||||
e.message ?: "",
|
|
||||||
)
|
|
||||||
VimPlugin.showMessage(message)
|
|
||||||
getDefaultHighlightTextColor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getDefaultHighlightTextColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractUserHighlightForegroundColor(): Color? {
|
|
||||||
val value = VimPlugin.getVariableService().getGlobalVariableValue(HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME)
|
|
||||||
?: return null
|
|
||||||
|
|
||||||
return try {
|
|
||||||
parseRgbaColor(value.asString())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
@VimNlsSafe val message = MessageHelper.message(
|
|
||||||
"highlightedyank.invalid.value.of.0.1",
|
|
||||||
"g:$HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME",
|
|
||||||
e.message ?: "",
|
|
||||||
)
|
|
||||||
VimPlugin.showMessage(message)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseRgbaColor(colorString: String): Color {
|
|
||||||
val rgba = colorString
|
|
||||||
.substring(4)
|
.substring(4)
|
||||||
.filter { it != '(' && it != ')' && !it.isWhitespace() }
|
.filter { it != '(' && it != ')' && !it.isWhitespace() }
|
||||||
.split(',')
|
.split(',')
|
||||||
.map { it.toInt() }
|
.map { it.toInt() }
|
||||||
|
|
||||||
if (rgba.size != 4 || rgba.any { it < 0 || it > 255 }) {
|
Color(rgba[0], rgba[1], rgba[2], rgba[3])
|
||||||
throw IllegalArgumentException("Invalid RGBA values. Each component must be between 0 and 255")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Color(rgba[0], rgba[1], rgba[2], rgba[3])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T {
|
private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T {
|
||||||
|
@@ -44,7 +44,6 @@ import com.maddyhome.idea.vim.helper.enumSetOf
|
|||||||
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.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
@@ -94,29 +93,34 @@ internal class Matchit : VimExtension {
|
|||||||
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
val keyHandler = KeyHandler.getInstance()
|
val keyHandler = KeyHandler.getInstance()
|
||||||
val keyState = keyHandler.keyHandlerState
|
val keyState = keyHandler.keyHandlerState
|
||||||
|
val count = keyState.commandBuilder.count
|
||||||
|
|
||||||
// Reset the command count so it doesn't transfer onto subsequent commands.
|
// Reset the command count so it doesn't transfer onto subsequent commands.
|
||||||
keyState.commandBuilder.resetCount()
|
keyState.commandBuilder.resetCount()
|
||||||
|
|
||||||
// Normally we want to jump to the start of the matching pair. But when moving forward in operator
|
// Normally we want to jump to the start of the matching pair. But when moving forward in operator
|
||||||
// pending mode, we want to include the entire match. isInOpPending makes that distinction.
|
// pending mode, we want to include the entire match. isInOpPending makes that distinction.
|
||||||
if (editor.mode is Mode.OP_PENDING) {
|
val isInOpPending = keyHandler.isOperatorPending(editor.mode, keyState)
|
||||||
|
|
||||||
|
if (isInOpPending) {
|
||||||
val matchitAction = MatchitAction()
|
val matchitAction = MatchitAction()
|
||||||
matchitAction.reverse = reverse
|
matchitAction.reverse = reverse
|
||||||
matchitAction.isInOpPending = true
|
matchitAction.isInOpPending = true
|
||||||
|
|
||||||
keyState.commandBuilder.addAction(matchitAction)
|
keyState.commandBuilder.completeCommandPart(
|
||||||
|
Argument(
|
||||||
|
Command(
|
||||||
|
count,
|
||||||
|
matchitAction,
|
||||||
|
Command.Type.MOTION,
|
||||||
|
EnumSet.noneOf(CommandFlags::class.java),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
editor.sortedCarets().forEach { caret ->
|
editor.sortedCarets().forEach { caret ->
|
||||||
injector.jumpService.saveJumpLocation(editor)
|
injector.jumpService.saveJumpLocation(editor)
|
||||||
caret.moveToOffset(
|
caret.moveToOffset(getMatchitOffset(editor.ij, caret.ij, count, isInOpPending, reverse))
|
||||||
getMatchitOffset(
|
|
||||||
editor.ij,
|
|
||||||
caret.ij,
|
|
||||||
operatorArguments.count0,
|
|
||||||
isInOpPending = false,
|
|
||||||
reverse
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,7 +354,7 @@ private object FileTypePatterns {
|
|||||||
|
|
||||||
private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')
|
private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')
|
||||||
|
|
||||||
private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPending: Boolean, reverse: Boolean): Int {
|
private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPending: Boolean, reverse: Boolean): Int {
|
||||||
val virtualFile = EditorHelper.getVirtualFile(editor)
|
val virtualFile = EditorHelper.getVirtualFile(editor)
|
||||||
var caretOffset = caret.offset
|
var caretOffset = caret.offset
|
||||||
|
|
||||||
@@ -363,9 +367,9 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPe
|
|||||||
val currentChar = editor.document.charsSequence[caretOffset]
|
val currentChar = editor.document.charsSequence[caretOffset]
|
||||||
var motionOffset: Int? = null
|
var motionOffset: Int? = null
|
||||||
|
|
||||||
if (count0 > 0) {
|
if (count > 0) {
|
||||||
// Matchit doesn't affect the percent motion, so we fall back to the default behavior.
|
// Matchit doesn't affect the percent motion, so we fall back to the default behavior.
|
||||||
motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count0)
|
motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count)
|
||||||
} else {
|
} else {
|
||||||
// Check the simplest case first.
|
// Check the simplest case first.
|
||||||
if (DEFAULT_PAIRS.contains(currentChar)) {
|
if (DEFAULT_PAIRS.contains(currentChar)) {
|
||||||
@@ -396,7 +400,8 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPe
|
|||||||
|
|
||||||
private fun getMotionOffset(motion: Motion): Int? {
|
private fun getMotionOffset(motion: Motion): Int? {
|
||||||
return when (motion) {
|
return when (motion) {
|
||||||
is Motion.AdjustedOffset, is Motion.AbsoluteOffset -> motion.offset
|
is Motion.AbsoluteOffset -> motion.offset
|
||||||
|
is Motion.AdjustedOffset -> motion.offset
|
||||||
is Motion.Error, is Motion.NoMotion -> null
|
is Motion.Error, is Motion.NoMotion -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,10 +42,13 @@ import com.maddyhome.idea.vim.extension.VimExtension
|
|||||||
import com.maddyhome.idea.vim.group.KeyGroup
|
import com.maddyhome.idea.vim.group.KeyGroup
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper
|
import com.maddyhome.idea.vim.helper.MessageHelper
|
||||||
import com.maddyhome.idea.vim.helper.runAfterGotFocus
|
import com.maddyhome.idea.vim.helper.runAfterGotFocus
|
||||||
import com.maddyhome.idea.vim.key.KeyStrokeTrie
|
import com.maddyhome.idea.vim.key.CommandNode
|
||||||
|
import com.maddyhome.idea.vim.key.CommandPartNode
|
||||||
import com.maddyhome.idea.vim.key.MappingOwner
|
import com.maddyhome.idea.vim.key.MappingOwner
|
||||||
|
import com.maddyhome.idea.vim.key.Node
|
||||||
import com.maddyhome.idea.vim.key.RequiredShortcut
|
import com.maddyhome.idea.vim.key.RequiredShortcut
|
||||||
import com.maddyhome.idea.vim.key.add
|
import com.maddyhome.idea.vim.key.RootNode
|
||||||
|
import com.maddyhome.idea.vim.key.addLeafs
|
||||||
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.vimscript.model.datatypes.VimString
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
|
||||||
@@ -195,8 +198,6 @@ internal class NerdTree : VimExtension {
|
|||||||
internal var waitForSearch = false
|
internal var waitForSearch = false
|
||||||
internal var speedSearchListenerInstalled = false
|
internal var speedSearchListenerInstalled = false
|
||||||
|
|
||||||
private val keys = mutableListOf<KeyStroke>()
|
|
||||||
|
|
||||||
override fun actionPerformed(e: AnActionEvent) {
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
var keyStroke = getKeyStroke(e) ?: return
|
var keyStroke = getKeyStroke(e) ?: return
|
||||||
val keyChar = keyStroke.keyChar
|
val keyChar = keyStroke.keyChar
|
||||||
@@ -204,14 +205,20 @@ internal class NerdTree : VimExtension {
|
|||||||
keyStroke = KeyStroke.getKeyStroke(keyChar)
|
keyStroke = KeyStroke.getKeyStroke(keyChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
keys.add(keyStroke)
|
val nextNode = currentNode[keyStroke]
|
||||||
actionsRoot.getData(keys)?.let { action ->
|
|
||||||
|
when (nextNode) {
|
||||||
|
null -> currentNode = actionsRoot
|
||||||
|
is CommandNode<NerdAction> -> {
|
||||||
|
currentNode = actionsRoot
|
||||||
|
|
||||||
|
val action = nextNode.actionHolder
|
||||||
when (action) {
|
when (action) {
|
||||||
is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim)
|
is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim)
|
||||||
is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) }
|
is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
keys.clear()
|
is CommandPartNode<NerdAction> -> currentNode = nextNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,29 +540,37 @@ private fun addCommand(alias: String, handler: CommandAliasHandler) {
|
|||||||
VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler))
|
VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommand(variable: String, defaultMapping: String, action: NerdAction) {
|
private fun registerCommand(variable: String, default: String, action: NerdAction) {
|
||||||
val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable)
|
val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable)
|
||||||
val mapping = if (variableValue is VimString) {
|
val mappings = if (variableValue is VimString) {
|
||||||
variableValue.value
|
variableValue.value
|
||||||
} else {
|
} else {
|
||||||
defaultMapping
|
default
|
||||||
}
|
}
|
||||||
registerCommand(mapping, action)
|
actionsRoot.addLeafs(mappings, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommand(mapping: String, action: NerdAction) {
|
private fun registerCommand(default: String, action: NerdAction) {
|
||||||
actionsRoot.add(mapping, action)
|
actionsRoot.addLeafs(default, action)
|
||||||
injector.parser.parseKeys(mapping).forEach {
|
|
||||||
distinctShortcuts.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val actionsRoot: KeyStrokeTrie<NerdAction> = KeyStrokeTrie<NerdAction>("NERDTree")
|
|
||||||
private val distinctShortcuts = mutableSetOf<KeyStroke>()
|
private val actionsRoot: RootNode<NerdAction> = RootNode()
|
||||||
|
private var currentNode: CommandPartNode<NerdAction> = actionsRoot
|
||||||
|
private fun collectShortcuts(node: Node<NerdAction>): Set<KeyStroke> {
|
||||||
|
return if (node is CommandPartNode<NerdAction>) {
|
||||||
|
val res = node.keys.toMutableSet()
|
||||||
|
res += node.values.map { collectShortcuts(it) }.flatten()
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun installDispatcher(project: Project) {
|
private fun installDispatcher(project: Project) {
|
||||||
val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
|
val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
|
||||||
val shortcuts = distinctShortcuts.map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
|
val shortcuts =
|
||||||
|
collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
|
||||||
dispatcher.registerCustomShortcutSet(
|
dispatcher.registerCustomShortcutSet(
|
||||||
KeyGroup.toShortcutSet(shortcuts),
|
KeyGroup.toShortcutSet(shortcuts),
|
||||||
(ProjectView.getInstance(project) as ProjectViewImpl).component,
|
(ProjectView.getInstance(project) as ProjectViewImpl).component,
|
||||||
|
@@ -62,7 +62,7 @@ internal class ParagraphMotion : VimExtension {
|
|||||||
toKeys: List<KeyStroke>,
|
toKeys: List<KeyStroke>,
|
||||||
recursive: Boolean,
|
recursive: Boolean,
|
||||||
) {
|
) {
|
||||||
val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().getKeyMapping(it).getLayer(fromKeys) != null }
|
val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().hasmapfrom(it, fromKeys) }
|
||||||
putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive)
|
putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ package com.maddyhome.idea.vim.extension.replacewithregister
|
|||||||
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
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.ImmutableVimCaret
|
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||||
@@ -143,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
|
||||||
@@ -165,11 +166,17 @@ private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimC
|
|||||||
putToLine = -1,
|
putToLine = -1,
|
||||||
)
|
)
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
|
val keyHandler = KeyHandler.getInstance()
|
||||||
ClipboardOptionHelper.IdeaputDisabler().use {
|
ClipboardOptionHelper.IdeaputDisabler().use {
|
||||||
VimPlugin.getPut().putText(
|
VimPlugin.getPut().putText(
|
||||||
vimEditor,
|
vimEditor,
|
||||||
context.vim,
|
context.vim,
|
||||||
putData,
|
putData,
|
||||||
|
operatorArguments = OperatorArguments(
|
||||||
|
keyHandler.isOperatorPending(vimEditor.mode, keyHandler.keyHandlerState),
|
||||||
|
0,
|
||||||
|
editor.vim.mode,
|
||||||
|
),
|
||||||
saveToRegister = false
|
saveToRegister = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
|
|||||||
import com.maddyhome.idea.vim.extension.VimExtensionHandler
|
import com.maddyhome.idea.vim.extension.VimExtensionHandler
|
||||||
import com.maddyhome.idea.vim.helper.StrictMode
|
import com.maddyhome.idea.vim.helper.StrictMode
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import org.jetbrains.annotations.TestOnly
|
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -46,26 +45,15 @@ private const val DEFAULT_HIGHLIGHT_DURATION_SNEAK = 300
|
|||||||
// By [Mikhail Levchenko](https://github.com/Mishkun)
|
// By [Mikhail Levchenko](https://github.com/Mishkun)
|
||||||
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
|
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
|
||||||
internal class IdeaVimSneakExtension : VimExtension {
|
internal class IdeaVimSneakExtension : VimExtension {
|
||||||
@Suppress("CompanionObjectInExtension")
|
|
||||||
companion object {
|
|
||||||
private var highlightHandler: HighlightHandler? = null
|
|
||||||
|
|
||||||
@TestOnly
|
|
||||||
internal fun stopTimer() {
|
|
||||||
highlightHandler?.stopExistingTimer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getName(): String = "sneak"
|
override fun getName(): String = "sneak"
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
val _highlightHandler = HighlightHandler()
|
val highlightHandler = HighlightHandler()
|
||||||
highlightHandler = _highlightHandler
|
mapToFunctionAndProvideKeys("s", SneakHandler(highlightHandler, Direction.FORWARD), MappingMode.NXO)
|
||||||
mapToFunctionAndProvideKeys("s", SneakHandler(_highlightHandler, Direction.FORWARD), MappingMode.NXO)
|
|
||||||
|
|
||||||
// vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330
|
// vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330
|
||||||
mapToFunctionAndProvideKeys("S", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.NO)
|
mapToFunctionAndProvideKeys("S", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.NO)
|
||||||
mapToFunctionAndProvideKeys("Z", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.X)
|
mapToFunctionAndProvideKeys("Z", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.X)
|
||||||
|
|
||||||
// workaround to support ; and , commands
|
// workaround to support ; and , commands
|
||||||
mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO)
|
mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO)
|
||||||
@@ -73,8 +61,8 @@ internal class IdeaVimSneakExtension : VimExtension {
|
|||||||
mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO)
|
mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO)
|
||||||
mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO)
|
mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO)
|
||||||
|
|
||||||
mapToFunctionAndProvideKeys(";", SneakRepeatHandler(_highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO)
|
mapToFunctionAndProvideKeys(";", SneakRepeatHandler(highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO)
|
||||||
mapToFunctionAndProvideKeys(",", SneakRepeatHandler(_highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO)
|
mapToFunctionAndProvideKeys(",", SneakRepeatHandler(highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SneakHandler(
|
private class SneakHandler(
|
||||||
@@ -221,7 +209,6 @@ internal class IdeaVimSneakExtension : VimExtension {
|
|||||||
private class HighlightHandler {
|
private class HighlightHandler {
|
||||||
private var editor: Editor? = null
|
private var editor: Editor? = null
|
||||||
private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf()
|
private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf()
|
||||||
private var timer: Timer? = null
|
|
||||||
|
|
||||||
fun highlightSneakRange(editor: Editor, range: TextRange) {
|
fun highlightSneakRange(editor: Editor, range: TextRange) {
|
||||||
clearAllSneakHighlighters()
|
clearAllSneakHighlighters()
|
||||||
@@ -267,19 +254,13 @@ internal class IdeaVimSneakExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
|
private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
|
||||||
stopExistingTimer()
|
val timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
|
||||||
timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
|
|
||||||
if (editor?.isDisposed != true) {
|
if (editor?.isDisposed != true) {
|
||||||
editor?.markupModel?.removeHighlighter(highlighter)
|
editor?.markupModel?.removeHighlighter(highlighter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer?.isRepeats = false
|
timer.isRepeats = false
|
||||||
timer?.start()
|
timer.start()
|
||||||
}
|
|
||||||
|
|
||||||
fun stopExistingTimer() {
|
|
||||||
timer?.stop()
|
|
||||||
timer?.actionListeners?.forEach { it.actionPerformed(null) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHighlightTextAttributes() = TextAttributes(
|
private fun getHighlightTextAttributes() = TextAttributes(
|
||||||
@@ -326,7 +307,7 @@ private fun VimExtension.mapToFunctionAndProvideKeys(
|
|||||||
VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
|
VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
|
||||||
}
|
}
|
||||||
val filteredFromModes = mappingModes.filterNotTo(HashSet()) {
|
val filteredFromModes = mappingModes.filterNotTo(HashSet()) {
|
||||||
injector.keyGroup.getKeyMapping(it).getLayer(fromKeys) != null
|
injector.keyGroup.hasmapfrom(it, fromKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
val doubleFiltered = mappingModes
|
val doubleFiltered = mappingModes
|
||||||
|
@@ -47,11 +47,11 @@ import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
|
|||||||
import com.maddyhome.idea.vim.put.PutData
|
import com.maddyhome.idea.vim.put.PutData
|
||||||
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.returnTo
|
|
||||||
import com.maddyhome.idea.vim.state.mode.selectionType
|
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.
|
||||||
@@ -161,17 +161,17 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) {
|
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
||||||
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
|
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) {
|
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 {
|
||||||
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
|
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
|
||||||
setRegisterForCaret(REGISTER, it, null)
|
setRegisterForCaret(REGISTER, it, null)
|
||||||
SurroundingInfo(it, null, oldValue, false)
|
SurroundingInfo(it, null, oldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete surrounding's content
|
// Delete surrounding's content
|
||||||
@@ -187,25 +187,21 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val registerValue = getRegisterForCaret(REGISTER, it.caret)
|
val registerValue = getRegisterForCaret(REGISTER, it.caret)
|
||||||
val innerValue = if (registerValue.isNullOrEmpty()) emptyList() else registerValue
|
val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue
|
||||||
it.innerText = innerValue
|
it.innerText = innerValue
|
||||||
|
}
|
||||||
|
|
||||||
// Valid surroundings are only those that:
|
surroundings.forEach {
|
||||||
// - are validly wrapping with surround characters (i.e. parenthesis, brackets, tags, quotes, etc.);
|
if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
|
||||||
// - or have non-empty inner text (e.g. when we are surrounding words: `csw"`)
|
it.innerText = emptyList()
|
||||||
if (currentSurrounding != null || innerValue.isNotEmpty()) {
|
|
||||||
it.isValidSurrounding = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
surroundings
|
surroundings
|
||||||
.filter { it.isValidSurrounding } // we do nothing with carets that are not inside the surrounding
|
.filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
|
||||||
.map { surrounding ->
|
.map { surrounding ->
|
||||||
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
|
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
|
||||||
val text = newSurround?.let {
|
val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
|
||||||
val trimmedValue = if (newSurround.shouldTrim) innerValue.trim() else innerValue
|
|
||||||
it.first + trimmedValue + it.second
|
|
||||||
} ?: innerValue
|
|
||||||
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
|
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
|
||||||
val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
|
val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
|
||||||
|
|
||||||
@@ -258,7 +254,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var isValidSurrounding: Boolean) {
|
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?) {
|
||||||
fun restoreRegister() {
|
fun restoreRegister() {
|
||||||
setRegisterForCaret(REGISTER, caret, oldRegisterContent)
|
setRegisterForCaret(REGISTER, caret, oldRegisterContent)
|
||||||
}
|
}
|
||||||
@@ -301,7 +297,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: SurroundPair, count: Int) {
|
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
|
||||||
// XXX: Will it work with line-wise or block-wise selections?
|
// XXX: Will it work with line-wise or block-wise selections?
|
||||||
val primaryCaret = editor.caretModel.primaryCaret
|
val primaryCaret = editor.caretModel.primaryCaret
|
||||||
val range = getSurroundRange(primaryCaret.vim)
|
val range = getSurroundRange(primaryCaret.vim)
|
||||||
@@ -335,33 +331,31 @@ private const val OPERATOR_FUNC = "SurroundOperatorFunc"
|
|||||||
|
|
||||||
private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern()
|
private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern()
|
||||||
|
|
||||||
private data class SurroundPair(val first: String, val second: String, val shouldTrim: Boolean)
|
|
||||||
|
|
||||||
private val SURROUND_PAIRS = mapOf(
|
private val SURROUND_PAIRS = mapOf(
|
||||||
'b' to SurroundPair("(", ")", false),
|
'b' to ("(" to ")"),
|
||||||
'(' to SurroundPair("( ", " )", false),
|
'(' to ("( " to " )"),
|
||||||
')' to SurroundPair("(", ")", true),
|
')' to ("(" to ")"),
|
||||||
'B' to SurroundPair("{", "}", false),
|
'B' to ("{" to "}"),
|
||||||
'{' to SurroundPair("{ ", " }", false),
|
'{' to ("{ " to " }"),
|
||||||
'}' to SurroundPair("{", "}", true),
|
'}' to ("{" to "}"),
|
||||||
'r' to SurroundPair("[", "]", false),
|
'r' to ("[" to "]"),
|
||||||
'[' to SurroundPair("[ ", " ]", false),
|
'[' to ("[ " to " ]"),
|
||||||
']' to SurroundPair("[", "]", true),
|
']' to ("[" to "]"),
|
||||||
'a' to SurroundPair("<", ">", false),
|
'a' to ("<" to ">"),
|
||||||
'>' to SurroundPair("<", ">", false),
|
'>' to ("<" to ">"),
|
||||||
's' to SurroundPair(" ", "", false),
|
's' to (" " to ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getSurroundPair(c: Char): SurroundPair? = if (c in SURROUND_PAIRS) {
|
private fun getSurroundPair(c: Char): Pair<String, String>? = if (c in SURROUND_PAIRS) {
|
||||||
SURROUND_PAIRS[c]
|
SURROUND_PAIRS[c]
|
||||||
} else if (!c.isLetter()) {
|
} else if (!c.isLetter()) {
|
||||||
val s = c.toString()
|
val s = c.toString()
|
||||||
SurroundPair(s, s, false)
|
s to s
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inputTagPair(editor: Editor, context: DataContext): SurroundPair? {
|
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) {
|
if (editor.vim.mode is Mode.CMD_LINE) {
|
||||||
editor.vim.mode = editor.vim.mode.returnTo()
|
editor.vim.mode = editor.vim.mode.returnTo()
|
||||||
@@ -370,7 +364,7 @@ private fun inputTagPair(editor: Editor, context: DataContext): SurroundPair? {
|
|||||||
return if (matcher.find()) {
|
return if (matcher.find()) {
|
||||||
val tagName = matcher.group(1)
|
val tagName = matcher.group(1)
|
||||||
val tagAttributes = matcher.group(2)
|
val tagAttributes = matcher.group(2)
|
||||||
SurroundPair("<$tagName$tagAttributes>", "</$tagName>", false)
|
"<$tagName$tagAttributes>" to "</$tagName>"
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -380,20 +374,16 @@ private fun inputFunctionName(
|
|||||||
editor: Editor,
|
editor: Editor,
|
||||||
context: DataContext,
|
context: DataContext,
|
||||||
withInternalSpaces: Boolean,
|
withInternalSpaces: Boolean,
|
||||||
): SurroundPair? {
|
): 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) {
|
if (editor.vim.mode is Mode.CMD_LINE) {
|
||||||
editor.vim.mode = editor.vim.mode.returnTo()
|
editor.vim.mode = editor.vim.mode.returnTo()
|
||||||
}
|
}
|
||||||
if (functionNameInput.isEmpty()) return null
|
if (functionNameInput.isEmpty()) return null
|
||||||
return if (withInternalSpaces) {
|
return if (withInternalSpaces) "$functionNameInput( " to " )" else "$functionNameInput(" to ")"
|
||||||
SurroundPair("$functionNameInput( ", " )", false)
|
|
||||||
} else {
|
|
||||||
SurroundPair("$functionNameInput(", ")", false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrInputPair(c: Char, editor: Editor, context: DataContext): SurroundPair? = when (c) {
|
private fun getOrInputPair(c: Char, editor: Editor, context: DataContext): Pair<String, String>? = when (c) {
|
||||||
'<', 't' -> inputTagPair(editor, context)
|
'<', 't' -> inputTagPair(editor, context)
|
||||||
'f' -> inputFunctionName(editor, context, false)
|
'f' -> inputFunctionName(editor, context, false)
|
||||||
'F' -> inputFunctionName(editor, context, true)
|
'F' -> inputFunctionName(editor, context, true)
|
||||||
@@ -412,7 +402,7 @@ private fun getChar(editor: Editor): Char {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performSurround(pair: SurroundPair, range: TextRange, caret: VimCaret, count: Int, 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()
|
||||||
|
@@ -29,12 +29,14 @@ import com.maddyhome.idea.vim.state.mode.Mode;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Port of vim-entire:
|
* Port of vim-entire:
|
||||||
* <a href="https://github.com/kana/vim-textobj-entire">vim-textobj-entire</a>
|
* https://github.com/kana/vim-textobj-entire
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* vim-textobj-entire provides two text objects:
|
* vim-textobj-entire provides two text objects:
|
||||||
@@ -49,7 +51,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingI
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* See also the reference manual for more details at:
|
* See also the reference manual for more details at:
|
||||||
* <a href="https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt">text-obj-entire.txt</a>
|
* https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt
|
||||||
*
|
*
|
||||||
* @author Alexandre Grison (@agrison)
|
* @author Alexandre Grison (@agrison)
|
||||||
*/
|
*/
|
||||||
@@ -92,8 +94,9 @@ public class VimTextObjEntireExtension implements VimExtension {
|
|||||||
this.ignoreLeadingAndTrailing = ignoreLeadingAndTrailing;
|
this.ignoreLeadingAndTrailing = ignoreLeadingAndTrailing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable TextRange getRange(@NotNull VimEditor editor,
|
public TextRange getRange(@NotNull VimEditor editor,
|
||||||
@NotNull ImmutableVimCaret caret,
|
@NotNull ImmutableVimCaret caret,
|
||||||
@NotNull ExecutionContext context,
|
@NotNull ExecutionContext context,
|
||||||
int count,
|
int count,
|
||||||
@@ -122,22 +125,24 @@ public class VimTextObjEntireExtension implements VimExtension {
|
|||||||
return new TextRange(start, end);
|
return new TextRange(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull TextObjectVisualType getVisualType() {
|
public TextObjectVisualType getVisualType() {
|
||||||
return TextObjectVisualType.CHARACTER_WISE;
|
return TextObjectVisualType.CHARACTER_WISE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
||||||
|
@NotNull KeyHandler keyHandler = KeyHandler.getInstance();
|
||||||
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
||||||
|
int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
|
||||||
|
|
||||||
final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
|
final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
|
||||||
//noinspection DuplicatedCode
|
//noinspection DuplicatedCode
|
||||||
if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
|
if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
|
||||||
int count0 = operatorArguments.getCount0();
|
|
||||||
((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
|
((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
|
||||||
final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
|
final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, count, 0);
|
||||||
if (range != null) {
|
if (range != null) {
|
||||||
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
||||||
if (editor.getMode() instanceof Mode.VISUAL) {
|
if (editor.getMode() instanceof Mode.VISUAL) {
|
||||||
@@ -150,7 +155,9 @@ public class VimTextObjEntireExtension implements VimExtension {
|
|||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
|
keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
|
||||||
|
textObjectHandler, Command.Type.MOTION,
|
||||||
|
EnumSet.noneOf(CommandFlags.class))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,12 +30,14 @@ import com.maddyhome.idea.vim.state.mode.Mode;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
|
||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
|
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Port of vim-indent-object:
|
* Port of vim-indent-object:
|
||||||
* <a href="https://github.com/michaeljsmith/vim-indent-object">vim-indent-object</a>
|
* https://github.com/michaeljsmith/vim-indent-object
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* vim-indent-object provides these text objects based on the cursor line's indentation:
|
* vim-indent-object provides these text objects based on the cursor line's indentation:
|
||||||
@@ -47,7 +49,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* See also the reference manual for more details at:
|
* See also the reference manual for more details at:
|
||||||
* <a href="https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt">indent-object.txt</a>
|
* https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt
|
||||||
*
|
*
|
||||||
* @author Shrikant Kandula (@sharat87)
|
* @author Shrikant Kandula (@sharat87)
|
||||||
*/
|
*/
|
||||||
@@ -96,8 +98,9 @@ public class VimIndentObject implements VimExtension {
|
|||||||
this.includeBelow = includeBelow;
|
this.includeBelow = includeBelow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable TextRange getRange(@NotNull VimEditor editor,
|
public TextRange getRange(@NotNull VimEditor editor,
|
||||||
@NotNull ImmutableVimCaret caret,
|
@NotNull ImmutableVimCaret caret,
|
||||||
@NotNull ExecutionContext context,
|
@NotNull ExecutionContext context,
|
||||||
int count,
|
int count,
|
||||||
@@ -246,8 +249,9 @@ public class VimIndentObject implements VimExtension {
|
|||||||
return new TextRange(upperBoundaryOffset, lowerBoundaryOffset);
|
return new TextRange(upperBoundaryOffset, lowerBoundaryOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull TextObjectVisualType getVisualType() {
|
public TextObjectVisualType getVisualType() {
|
||||||
return TextObjectVisualType.LINE_WISE;
|
return TextObjectVisualType.LINE_WISE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,14 +264,15 @@ public class VimIndentObject implements VimExtension {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
|
||||||
IjVimEditor vimEditor = (IjVimEditor)editor;
|
IjVimEditor vimEditor = (IjVimEditor)editor;
|
||||||
|
@NotNull KeyHandler keyHandler = KeyHandler.getInstance();
|
||||||
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
|
||||||
|
int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
|
||||||
|
|
||||||
final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
|
final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
|
||||||
|
|
||||||
if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
|
if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
|
||||||
int count0 = operatorArguments.getCount0();
|
|
||||||
((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
|
((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
|
||||||
final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
|
final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, count, 0);
|
||||||
if (range != null) {
|
if (range != null) {
|
||||||
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
|
||||||
if (editor.getMode() instanceof Mode.VISUAL) {
|
if (editor.getMode() instanceof Mode.VISUAL) {
|
||||||
@@ -280,7 +285,9 @@ public class VimIndentObject implements VimExtension {
|
|||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
|
keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
|
||||||
|
textObjectHandler, Command.Type.MOTION,
|
||||||
|
EnumSet.noneOf(CommandFlags.class))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,12 +36,9 @@ import com.maddyhome.idea.vim.helper.inInsertMode
|
|||||||
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.IjVimCaret
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCopiedText
|
|
||||||
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.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
|
|
||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides all the insert/replace related functionality
|
* Provides all the insert/replace related functionality
|
||||||
@@ -64,15 +61,9 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
val editor = (vimEditor as IjVimEditor).editor
|
val editor = (vimEditor as IjVimEditor).editor
|
||||||
val ijContext = context.ij
|
val ijContext = context.ij
|
||||||
val doc = vimEditor.editor.document
|
val doc = vimEditor.editor.document
|
||||||
|
|
||||||
val undo = injector.undo
|
val undo = injector.undo
|
||||||
when (undo) {
|
|
||||||
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
|
|
||||||
is VimTimestampBasedUndoService -> {
|
|
||||||
val nanoTime = System.nanoTime()
|
val nanoTime = System.nanoTime()
|
||||||
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
||||||
}
|
|
||||||
}
|
|
||||||
CommandProcessor.getInstance().executeCommand(
|
CommandProcessor.getInstance().executeCommand(
|
||||||
editor.project, {
|
editor.project, {
|
||||||
ApplicationManager.getApplication()
|
ApplicationManager.getApplication()
|
||||||
@@ -112,11 +103,6 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processBackspace(editor: VimEditor, context: ExecutionContext) {
|
|
||||||
injector.actionExecutor.executeAction(editor, name = IdeActions.ACTION_EDITOR_BACKSPACE, context = context)
|
|
||||||
injector.scroll.scrollCaretIntoView(editor)
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
||||||
@@ -145,10 +131,10 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
|
|
||||||
// FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux
|
// FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux
|
||||||
// FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method
|
// FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method
|
||||||
var copiedText: IjVimCopiedText? = null
|
var primaryTextAndTransferableData: Pair<String, List<Any>?>? = null
|
||||||
try {
|
try {
|
||||||
if (injector.registerGroup.isPrimaryRegisterSupported()) {
|
if (injector.registerGroup.isPrimaryRegisterSupported()) {
|
||||||
copiedText = injector.clipboardManager.getPrimaryContent(editor, context) as IjVimCopiedText
|
primaryTextAndTransferableData = injector.clipboardManager.getPrimaryTextAndTransferableData()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
|
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
|
||||||
@@ -174,8 +160,12 @@ class ChangeGroup : VimChangeGroupBase() {
|
|||||||
afterAction.invoke()
|
afterAction.invoke()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (copiedText != null) {
|
if (primaryTextAndTransferableData != null) {
|
||||||
injector.clipboardManager.setPrimaryContent(editor, context, copiedText)
|
injector.clipboardManager.setPrimaryText(
|
||||||
|
primaryTextAndTransferableData.first,
|
||||||
|
primaryTextAndTransferableData.first,
|
||||||
|
primaryTextAndTransferableData.second ?: emptyList()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
|
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
|
||||||
|
78
src/main/java/com/maddyhome/idea/vim/group/DigraphGroup.java
Normal file
78
src/main/java/com/maddyhome/idea/vim/group/DigraphGroup.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.group;
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
|
import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
|
||||||
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
|
import com.maddyhome.idea.vim.helper.EditorHelper;
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class DigraphGroup extends VimDigraphGroupBase {
|
||||||
|
|
||||||
|
public void showDigraphs(@NotNull VimEditor editor) {
|
||||||
|
int width = EditorHelper.getApproximateScreenWidth(((IjVimEditor) editor).getEditor());
|
||||||
|
if (width < 10) {
|
||||||
|
width = 80;
|
||||||
|
}
|
||||||
|
int colCount = width / 12;
|
||||||
|
int height = (int)Math.ceil((double) getDigraphs().size() / (double)colCount);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("width=" + width);
|
||||||
|
logger.debug("colCount=" + colCount);
|
||||||
|
logger.debug("height=" + height);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
int cnt = 0;
|
||||||
|
for (Character code : getKeys().keySet()) {
|
||||||
|
String key = getKeys().get(code);
|
||||||
|
|
||||||
|
res.append(key);
|
||||||
|
res.append(' ');
|
||||||
|
if (code < 32) {
|
||||||
|
res.append('^');
|
||||||
|
res.append((char)(code + '@'));
|
||||||
|
}
|
||||||
|
else if (code >= 128 && code <= 159) {
|
||||||
|
res.append('~');
|
||||||
|
res.append((char)(code - 128 + '@'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.append(code);
|
||||||
|
res.append(' ');
|
||||||
|
}
|
||||||
|
res.append(' ');
|
||||||
|
if (code < 0x1000) {
|
||||||
|
res.append('0');
|
||||||
|
}
|
||||||
|
if (code < 0x100) {
|
||||||
|
res.append('0');
|
||||||
|
}
|
||||||
|
if (code < 0x10) {
|
||||||
|
res.append('0');
|
||||||
|
}
|
||||||
|
res.append(Integer.toHexString(code));
|
||||||
|
res.append(" ");
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
if (cnt == colCount) {
|
||||||
|
res.append('\n');
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExOutputModel.getInstance(((IjVimEditor) editor).getEditor()).output(res.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
|
||||||
|
}
|
@@ -374,9 +374,9 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
|
|||||||
if (activeCommandLine != null) {
|
if (activeCommandLine != null) {
|
||||||
activeCommandLine.close(true, false);
|
activeCommandLine.close(true, false);
|
||||||
}
|
}
|
||||||
VimOutputPanel outputPanel = injector.getOutputPanel().getCurrentOutputPanel();
|
ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
|
||||||
if (outputPanel != null) {
|
if (exOutputModel != null) {
|
||||||
outputPanel.close();
|
exOutputModel.close();
|
||||||
}
|
}
|
||||||
VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
|
VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
|
||||||
if (modalInput != null) {
|
if (modalInput != null) {
|
||||||
|
@@ -42,6 +42,7 @@ import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
|||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.execute
|
import com.maddyhome.idea.vim.newapi.execute
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine.Companion.getInstance
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
|
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@@ -14,7 +14,9 @@ import com.intellij.openapi.components.State;
|
|||||||
import com.intellij.openapi.components.Storage;
|
import com.intellij.openapi.components.Storage;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.history.*;
|
import com.maddyhome.idea.vim.history.HistoryBlock;
|
||||||
|
import com.maddyhome.idea.vim.history.HistoryEntry;
|
||||||
|
import com.maddyhome.idea.vim.history.VimHistoryBase;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -33,20 +35,21 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
logger.debug("saveData");
|
logger.debug("saveData");
|
||||||
Element hist = new Element("history");
|
Element hist = new Element("history");
|
||||||
|
|
||||||
for (Type type : getHistories().keySet()) {
|
saveData(hist, SEARCH);
|
||||||
saveData(hist, type);
|
saveData(hist, COMMAND);
|
||||||
}
|
saveData(hist, EXPRESSION);
|
||||||
|
saveData(hist, INPUT);
|
||||||
|
|
||||||
element.addContent(hist);
|
element.addContent(hist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveData(@NotNull Element element, VimHistory.Type type) {
|
private void saveData(@NotNull Element element, String key) {
|
||||||
final HistoryBlock block = getHistories().get(type);
|
final HistoryBlock block = getHistories().get(key);
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Element root = new Element("history-" + typeToKey(type));
|
final Element root = new Element("history-" + key);
|
||||||
|
|
||||||
for (HistoryEntry entry : block.getEntries()) {
|
for (HistoryEntry entry : block.getEntries()) {
|
||||||
final Element entryElement = new Element("entry");
|
final Element entryElement = new Element("entry");
|
||||||
@@ -64,10 +67,10 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Element child : hist.getChildren()) {
|
readData(hist, SEARCH);
|
||||||
String key = child.getName().replace("history-", "");
|
readData(hist, COMMAND);
|
||||||
readData(hist, key);
|
readData(hist, EXPRESSION);
|
||||||
}
|
readData(hist, INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readData(@NotNull Element element, String key) {
|
private void readData(@NotNull Element element, String key) {
|
||||||
@@ -77,7 +80,7 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
}
|
}
|
||||||
|
|
||||||
block = new HistoryBlock();
|
block = new HistoryBlock();
|
||||||
getHistories().put(getTypeForString(key), block);
|
getHistories().put(key, block);
|
||||||
|
|
||||||
final Element root = element.getChild("history-" + key);
|
final Element root = element.getChild("history-" + key);
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
@@ -91,25 +94,6 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String typeToKey(VimHistory.Type type) {
|
|
||||||
if (type instanceof VimHistory.Type.Search) {
|
|
||||||
return SEARCH;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Command) {
|
|
||||||
return COMMAND;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Expression) {
|
|
||||||
return EXPRESSION;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Input) {
|
|
||||||
return INPUT;
|
|
||||||
}
|
|
||||||
if (type instanceof VimHistory.Type.Custom) {
|
|
||||||
return ((Type.Custom) type).getId();
|
|
||||||
}
|
|
||||||
return "unreachable";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Element getState() {
|
public Element getState() {
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.group;
|
package com.maddyhome.idea.vim.group;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||||
import com.intellij.openapi.actionSystem.*;
|
import com.intellij.openapi.actionSystem.*;
|
||||||
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
||||||
@@ -16,16 +17,21 @@ import com.intellij.openapi.application.ApplicationManager;
|
|||||||
import com.intellij.openapi.components.PersistentStateComponent;
|
import com.intellij.openapi.components.PersistentStateComponent;
|
||||||
import com.intellij.openapi.components.State;
|
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.editor.Editor;
|
||||||
import com.intellij.openapi.keymap.Keymap;
|
import com.intellij.openapi.keymap.Keymap;
|
||||||
import com.intellij.openapi.keymap.KeymapManager;
|
import com.intellij.openapi.keymap.KeymapManager;
|
||||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
||||||
import com.intellij.util.containers.MultiMap;
|
|
||||||
import com.maddyhome.idea.vim.EventFacade;
|
import com.maddyhome.idea.vim.EventFacade;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
|
||||||
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
|
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
|
||||||
import com.maddyhome.idea.vim.api.*;
|
import com.maddyhome.idea.vim.api.NativeAction;
|
||||||
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
|
import com.maddyhome.idea.vim.api.VimInjectorKt;
|
||||||
|
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
|
||||||
import com.maddyhome.idea.vim.command.MappingMode;
|
import com.maddyhome.idea.vim.command.MappingMode;
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel;
|
||||||
import com.maddyhome.idea.vim.key.*;
|
import com.maddyhome.idea.vim.key.*;
|
||||||
import com.maddyhome.idea.vim.newapi.IjNativeAction;
|
import com.maddyhome.idea.vim.newapi.IjNativeAction;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
@@ -55,6 +61,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
private static final @NonNls String OWNER_ATTRIBUTE = "owner";
|
private static final @NonNls String OWNER_ATTRIBUTE = "owner";
|
||||||
private static final String TEXT_ELEMENT = "text";
|
private static final String TEXT_ELEMENT = "text";
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getInstance(KeyGroup.class);
|
||||||
|
|
||||||
public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
|
public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
|
||||||
EventFacade.getInstance()
|
EventFacade.getInstance()
|
||||||
.registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
|
.registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
|
||||||
@@ -72,6 +80,25 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
((IjVimEditor)editor).getEditor().getComponent());
|
((IjVimEditor)editor).getEditor().getComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull Editor editor) {
|
||||||
|
List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
|
||||||
|
MappingInfo mappingInfo = row.getSecond();
|
||||||
|
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(mappingInfo.isRecursive() ? " " : "*");
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(mappingInfo.getPresentableString());
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
ExOutputModel.getInstance(editor).output(builder.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateShortcutKeysRegistration() {
|
public void updateShortcutKeysRegistration() {
|
||||||
for (VimEditor editor : injector.getEditorGroup().getEditors()) {
|
for (VimEditor editor : injector.getEditorGroup().getEditors()) {
|
||||||
@@ -194,7 +221,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
|
registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
|
||||||
|
|
||||||
for (MappingMode mappingMode : command.getModes()) {
|
for (MappingMode mappingMode : command.getModes()) {
|
||||||
getBuiltinCommandsTrie(mappingMode).add(keyStrokes, command);
|
Node<LazyVimCommand> node = getKeyRoot(mappingMode);
|
||||||
|
NodesKt.addLeafs(node, keyStrokes, command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,79 +247,53 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0]));
|
return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NotNull List<Pair<Set<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes,
|
private static @NotNull List<Pair<EnumSet<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes) {
|
||||||
@NotNull List<? extends KeyStroke> prefix) {
|
final Map<ImmutableList<KeyStroke>, EnumSet<MappingMode>> actualModes = new HashMap<>();
|
||||||
// Some map commands set a mapping for more than one mode (e.g. `map` sets for Normal, Visual, Select and
|
|
||||||
// Op-pending). Vim treats this as a single mapping, and when listing all maps only lists it once, with the
|
|
||||||
// appropriate mode indicator(s) in the first column (NVO is a space char). If the lhs mapping is changed or cleared
|
|
||||||
// for one of the modes, the original mapping is still a single map for the remaining modes, and the indicator
|
|
||||||
// changes. E.g. `map foo bar` followed by `sunmap foo` would result in `nox foo bar` in the output to `map`.
|
|
||||||
// Vim doesn't do automatic grouping - `nmap foo bar` followed by `omap foo bar` and `vmap foo bar` would result in
|
|
||||||
// 3 lines in the output to `map` - one for `n`, one for `o` and one for `v`.
|
|
||||||
// We store mappings separately per mode (to simplify lookup, especially when matching prefixes), but want to have
|
|
||||||
// the same behaviour as Vim in map output. So we store the original modes with the mapping and check they're still
|
|
||||||
// valid as we collect output
|
|
||||||
final List<Pair<Set<MappingMode>, MappingInfo>> rows = new ArrayList<>();
|
|
||||||
final MultiMap<List<? extends KeyStroke>, Set<MappingMode>> multiModeMappings = MultiMap.create();
|
|
||||||
final List<KeyStroke> fromKeys = new ArrayList<>();
|
|
||||||
|
|
||||||
for (MappingMode mode : modes) {
|
for (MappingMode mode : modes) {
|
||||||
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
|
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
|
||||||
|
for (List<? extends KeyStroke> fromKeys : mapping) {
|
||||||
final Iterator<KeyMappingEntry> iterator = mapping.getAll(prefix).iterator();
|
final ImmutableList<KeyStroke> key = ImmutableList.copyOf(fromKeys);
|
||||||
while (iterator.hasNext()) {
|
final EnumSet<MappingMode> value = actualModes.get(key);
|
||||||
final KeyMappingEntry entry = iterator.next();
|
final EnumSet<MappingMode> newValue;
|
||||||
final MappingInfo mappingInfo = entry.getMappingInfo();
|
if (value != null) {
|
||||||
|
newValue = value.clone();
|
||||||
final Set<@NotNull MappingMode> originalModes = mappingInfo.getOriginalModes();
|
newValue.add(mode);
|
||||||
if (originalModes.size() == 1) {
|
|
||||||
rows.add(new Pair<>(originalModes, mappingInfo));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entry.collectPath(fromKeys);
|
newValue = EnumSet.of(mode);
|
||||||
if (!multiModeMappings.get(fromKeys).contains(originalModes)) {
|
}
|
||||||
multiModeMappings.putValue(new ArrayList<>(fromKeys), originalModes);
|
actualModes.put(key, newValue);
|
||||||
rows.add(new Pair<>(getModesForMapping(fromKeys, originalModes), mappingInfo));
|
}
|
||||||
|
}
|
||||||
|
final List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = new ArrayList<>();
|
||||||
|
for (Map.Entry<ImmutableList<KeyStroke>, EnumSet<MappingMode>> entry : actualModes.entrySet()) {
|
||||||
|
final ArrayList<KeyStroke> fromKeys = new ArrayList<>(entry.getKey());
|
||||||
|
final EnumSet<MappingMode> mappingModes = entry.getValue();
|
||||||
|
if (!mappingModes.isEmpty()) {
|
||||||
|
final MappingMode mode = mappingModes.iterator().next();
|
||||||
|
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
|
||||||
|
final MappingInfo mappingInfo = mapping.get(fromKeys);
|
||||||
|
if (mappingInfo != null) {
|
||||||
|
rows.add(new Pair<>(mappingModes, mappingInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
rows.sort(Comparator.comparing(Pair<EnumSet<MappingMode>, MappingInfo>::getSecond));
|
||||||
rows.sort(Comparator.comparing(Pair<Set<MappingMode>, MappingInfo>::getSecond));
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NotNull Set<MappingMode> getModesForMapping(@NotNull List<? extends KeyStroke> keyStrokes,
|
|
||||||
@NotNull Set<MappingMode> originalMappingModes) {
|
|
||||||
final Set<MappingMode> actualModes = EnumSet.noneOf(MappingMode.class);
|
|
||||||
for (MappingMode mode : originalMappingModes) {
|
|
||||||
final MappingInfo mappingInfo = VimPlugin.getKey().getKeyMapping(mode).get(keyStrokes);
|
|
||||||
if (mappingInfo != null && mappingInfo.getOriginalModes() == originalMappingModes) {
|
|
||||||
actualModes.add(mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return actualModes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
|
private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
|
||||||
if (modes.equals(MappingMode.IC)) return "!";
|
if (modes.equals(MappingMode.NVO)) {
|
||||||
if (modes.equals(MappingMode.NVO)) return " ";
|
return "";
|
||||||
if (modes.equals(MappingMode.C)) return "c";
|
|
||||||
if (modes.equals(MappingMode.I)) return "i";
|
|
||||||
//if (modes.equals(MappingMode.L)) return "l";
|
|
||||||
|
|
||||||
// The following modes are concatenated
|
|
||||||
String mode = "";
|
|
||||||
if (modes.containsAll(MappingMode.N)) mode += "n";
|
|
||||||
if (modes.containsAll(MappingMode.O)) mode += "o";
|
|
||||||
|
|
||||||
if (modes.containsAll(MappingMode.V)) {
|
|
||||||
mode += "v";
|
|
||||||
}
|
}
|
||||||
else {
|
else if (modes.contains(MappingMode.INSERT)) {
|
||||||
if (modes.containsAll(MappingMode.X)) mode += "x";
|
return "i";
|
||||||
if (modes.containsAll(MappingMode.S)) mode += "s";
|
|
||||||
}
|
}
|
||||||
return mode;
|
else if (modes.contains(MappingMode.NORMAL)) {
|
||||||
|
return "n";
|
||||||
|
}
|
||||||
|
// TODO: Add more codes
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
|
private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
|
||||||
@@ -355,23 +357,7 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull List<? extends KeyStroke> prefix, @NotNull VimEditor editor) {
|
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
|
||||||
List<Pair<Set<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes, prefix);
|
return showKeyMappings(modes, ((IjVimEditor) editor).getEditor());
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
for (Pair<Set<MappingMode>, MappingInfo> row : rows) {
|
|
||||||
MappingInfo mappingInfo = row.getSecond();
|
|
||||||
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 3, ' '));
|
|
||||||
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()) + " ", 12, ' '));
|
|
||||||
builder.append(mappingInfo.isRecursive() ? " " : "*"); // Or `&` if script-local mappings being recursive
|
|
||||||
builder.append(" "); // Should be `@` if it's a buffer-local mapping
|
|
||||||
builder.append(mappingInfo.getPresentableString());
|
|
||||||
builder.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
|
|
||||||
outputPanel.addText(builder.toString(), true);
|
|
||||||
outputPanel.show();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ import com.maddyhome.idea.vim.command.Argument
|
|||||||
import com.maddyhome.idea.vim.command.MotionType
|
import com.maddyhome.idea.vim.command.MotionType
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.handler.ExternalActionHandler
|
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||||
import com.maddyhome.idea.vim.handler.Motion
|
import com.maddyhome.idea.vim.handler.Motion
|
||||||
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
|
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
|
||||||
import com.maddyhome.idea.vim.handler.MotionActionHandler
|
import com.maddyhome.idea.vim.handler.MotionActionHandler
|
||||||
@@ -193,16 +193,21 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
argument: Argument,
|
argument: Argument,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): TextRange? {
|
): TextRange? {
|
||||||
if (argument !is Argument.Motion) {
|
|
||||||
throw RuntimeException("Unexpected argument passed to getMotionRange2: $argument")
|
|
||||||
}
|
|
||||||
|
|
||||||
var start: Int
|
var start: Int
|
||||||
var end: Int
|
var end: Int
|
||||||
|
if (argument.type === Argument.Type.OFFSETS) {
|
||||||
|
val offsets = argument.offsets[caret.vim] ?: return null
|
||||||
|
val (first, second) = offsets.getNativeStartAndEnd()
|
||||||
|
start = first
|
||||||
|
end = second
|
||||||
|
} else {
|
||||||
|
val cmd = argument.motion
|
||||||
|
// Normalize the counts between the command and the motion argument
|
||||||
|
val cnt = cmd.count * operatorArguments.count1
|
||||||
|
val raw = if (operatorArguments.count0 == 0 && cmd.rawCount == 0) 0 else cnt
|
||||||
|
if (cmd.action is MotionActionHandler) {
|
||||||
|
val action = cmd.action as MotionActionHandler
|
||||||
|
|
||||||
val action = argument.motion
|
|
||||||
when (action) {
|
|
||||||
is MotionActionHandler -> {
|
|
||||||
// This is where we are now
|
// This is where we are now
|
||||||
start = caret.offset
|
start = caret.offset
|
||||||
|
|
||||||
@@ -211,8 +216,8 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
editor.vim,
|
editor.vim,
|
||||||
caret.vim,
|
caret.vim,
|
||||||
IjEditorExecutionContext(context!!),
|
IjEditorExecutionContext(context!!),
|
||||||
argument.argument,
|
cmd.argument,
|
||||||
operatorArguments
|
operatorArguments.withCount0(raw),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Invalid motion
|
// Invalid motion
|
||||||
@@ -228,32 +233,22 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (cmd.action is TextObjectActionHandler) {
|
||||||
|
val action = cmd.action as TextObjectActionHandler
|
||||||
is TextObjectActionHandler -> {
|
val range =
|
||||||
val range = action.getRange(
|
action.getRange(editor.vim, caret.vim, IjEditorExecutionContext(context!!), cnt, raw) ?: return null
|
||||||
editor.vim,
|
|
||||||
caret.vim,
|
|
||||||
IjEditorExecutionContext(context!!),
|
|
||||||
operatorArguments.count1,
|
|
||||||
operatorArguments.count0
|
|
||||||
) ?: return null
|
|
||||||
start = range.startOffset
|
start = range.startOffset
|
||||||
end = range.endOffset
|
end = range.endOffset
|
||||||
if (argument.isLinewiseMotion()) end--
|
if (cmd.isLinewiseMotion()) end--
|
||||||
|
} else {
|
||||||
|
throw RuntimeException(
|
||||||
|
"Commands doesn't take " + cmd.action.javaClass.simpleName + " as an operator",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ExternalActionHandler -> {
|
|
||||||
val range = action.getRange(caret.vim) ?: return null
|
|
||||||
start = range.startOffset
|
|
||||||
end = range.endOffset
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> throw RuntimeException("Commands doesn't take " + action.javaClass.simpleName + " as an operator")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
|
// This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
|
||||||
val id = argument.motion.id
|
val id = argument.motion.action.id
|
||||||
if (id == VimChangeGroupBase.VIM_MOTION_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_BIG_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_CAMEL_RIGHT) {
|
if (id == VimChangeGroupBase.VIM_MOTION_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_BIG_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_CAMEL_RIGHT) {
|
||||||
val text = editor.document.charsSequence.subSequence(start, end).toString()
|
val text = editor.document.charsSequence.subSequence(start, end).toString()
|
||||||
val lastNewLine = text.lastIndexOf('\n')
|
val lastNewLine = text.lastIndexOf('\n')
|
||||||
@@ -263,7 +258,6 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextRange(start, end)
|
return TextRange(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +317,7 @@ internal class MotionGroup : VimMotionGroupBase() {
|
|||||||
is Mode.CMD_LINE -> {
|
is Mode.CMD_LINE -> {
|
||||||
val commandLine = injector.commandLine.getActiveCommandLine() ?: return
|
val commandLine = injector.commandLine.getActiveCommandLine() ?: return
|
||||||
commandLine.close(refocusOwningEditor = false, resetCaret = false)
|
commandLine.close(refocusOwningEditor = false, resetCaret = false)
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
ExOutputModel.tryGetInstance(editor)?.close()
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,6 @@ import com.intellij.application.options.CodeStyle
|
|||||||
import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction
|
import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Editor
|
|
||||||
import com.intellij.openapi.editor.EditorKind
|
import com.intellij.openapi.editor.EditorKind
|
||||||
import com.intellij.openapi.editor.EditorSettings.LineNumerationType
|
import com.intellij.openapi.editor.EditorSettings.LineNumerationType
|
||||||
import com.intellij.openapi.editor.ScrollPositionCalculator
|
import com.intellij.openapi.editor.ScrollPositionCalculator
|
||||||
@@ -20,6 +19,8 @@ import com.intellij.openapi.editor.ex.EditorEx
|
|||||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
|
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
|
||||||
import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces
|
import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||||
|
import com.intellij.openapi.fileEditor.TextEditor
|
||||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil
|
import com.intellij.openapi.fileEditor.impl.LoadTextUtil
|
||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl
|
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
@@ -157,24 +158,25 @@ internal class OptionGroup : VimOptionGroupBase(), IjVimOptionGroup, InternalOpt
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun editorReleased(editor: Editor) {
|
fun fileEditorManagerSelectionChangedCallback(event: FileEditorManagerEvent) {
|
||||||
// Vim always has at least one window; it's not possible to close it. Editing a new file will open a new buffer in
|
// Vim only has one window, and it's not possible to close it. This means that editing a new file will always
|
||||||
// the current window, or it's possible to split the current buffer into a new window, or open a new buffer in a
|
// reuse an existing window (opening a new window will always open from an existing window). More importantly,
|
||||||
// new window. This is important for us because when Vim opens a new window, the new window's local options are
|
// this means that any newly edited file will always get up-to-date local-to-window options. A new window is based
|
||||||
// copied from the current window.
|
// on the opening window (treated as split then edit, so copy local + per-window "global" window values, then
|
||||||
// In detail: splitting the current window gets a complete copy of local and per-window global option values.
|
// apply the per-window "global" values) and an edit reapplies the per-window "global" values.
|
||||||
// Editing a new file will split the current window and then edit the new buffer in-place.
|
// If we close all windows, and open a new one, we can only use the per-window "global" values from the fallback
|
||||||
// IntelliJ does not always have an open window. It would be weird to close the last editor tab, and then open
|
// window, but this is only initialised when we first read `~/.ideavimrc` during startup. Vim would use the values
|
||||||
// the next tab with different options - the user would expect the editor to look like the last one did.
|
// from the current window, so to simulate this, we should update the fallback window with the values from the
|
||||||
// Therefore, we have a dummy "fallback" window that captures the options of the last closed editor. When opening
|
// window that was selected at the time that the last window was closed.
|
||||||
// an editor and there are no currently open editors, we use the fallback window to initialise the new window.
|
// Unfortunately, we can't reliably know if a closing editor is the selected editor. Instead, we rely on selection
|
||||||
// This callback tracks when editors are closed, and if the last editor in a project is being closed, updates the
|
// change events. If an editor is losing selection and there is no new selection, we can assume this means that
|
||||||
// fallback window's options.
|
// the last editor has been closed, and use the closed editor to update the fallback window
|
||||||
val project = editor.project ?: return
|
//
|
||||||
if (!injector.editorGroup.getEditorsRaw()
|
// XXX: event.oldEditor will must probably return a disposed editor. So, it should be treated with care
|
||||||
.any { it.ij != editor && it.ij.project === project && it.ij.editorKind == EditorKind.MAIN_EDITOR }
|
if (event.newEditor == null) {
|
||||||
) {
|
(event.oldEditor as? TextEditor)?.editor?.let {
|
||||||
(VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, editor.vim)
|
(VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, it.vim)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ 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.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;
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.maddyhome.idea.vim.group
|
package com.maddyhome.idea.vim.group
|
||||||
|
|
||||||
|
import com.intellij.codeWithMe.ClientId
|
||||||
import com.intellij.ide.bookmark.Bookmark
|
import com.intellij.ide.bookmark.Bookmark
|
||||||
import com.intellij.ide.bookmark.BookmarkGroup
|
import com.intellij.ide.bookmark.BookmarkGroup
|
||||||
import com.intellij.ide.bookmark.BookmarksListener
|
import com.intellij.ide.bookmark.BookmarksListener
|
||||||
|
@@ -51,8 +51,6 @@ 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
|
||||||
import com.maddyhome.idea.vim.state.mode.isLine
|
import com.maddyhome.idea.vim.state.mode.isLine
|
||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
|
|
||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
|
|
||||||
import java.awt.datatransfer.DataFlavor
|
import java.awt.datatransfer.DataFlavor
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -87,16 +85,10 @@ internal class PutGroup : VimPutBase() {
|
|||||||
val context = vimContext.context as DataContext
|
val context = vimContext.context as DataContext
|
||||||
val carets: MutableMap<Caret, RangeMarker> = mutableMapOf()
|
val carets: MutableMap<Caret, RangeMarker> = mutableMapOf()
|
||||||
if (injector.vimState.mode is Mode.INSERT) {
|
if (injector.vimState.mode is Mode.INSERT) {
|
||||||
val nanoTime = System.nanoTime()
|
|
||||||
|
|
||||||
val undo = injector.undo
|
val undo = injector.undo
|
||||||
when (undo) {
|
val nanoTime = System.nanoTime()
|
||||||
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
|
|
||||||
is VimTimestampBasedUndoService -> {
|
|
||||||
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
EditorHelper.getOrderedCaretsList(editor).forEach { caret ->
|
EditorHelper.getOrderedCaretsList(editor).forEach { caret ->
|
||||||
val startOffset =
|
val startOffset =
|
||||||
prepareDocumentAndGetStartOffsets(
|
prepareDocumentAndGetStartOffsets(
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.group.visual
|
package com.maddyhome.idea.vim.group.visual
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.diagnostic.trace
|
import com.intellij.openapi.diagnostic.trace
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
@@ -16,8 +15,6 @@ import com.maddyhome.idea.vim.KeyHandler
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.api.options
|
import com.maddyhome.idea.vim.api.options
|
||||||
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.controlNonVimSelectionChange
|
|
||||||
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.predictMode
|
|
||||||
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.hasVisualSelection
|
import com.maddyhome.idea.vim.helper.hasVisualSelection
|
||||||
@@ -66,15 +63,12 @@ internal object IdeaSelectionControl {
|
|||||||
// - There was no selection and now it is
|
// - There was no selection and now it is
|
||||||
// - There was a selection and now it doesn't exist
|
// - There was a selection and now it doesn't exist
|
||||||
// - There was a selection and now it exists as well (transforming char selection to line selection, for example)
|
// - There was a selection and now it exists as well (transforming char selection to line selection, for example)
|
||||||
val hasSelection = ApplicationManager.getApplication().runReadAction<Boolean> {
|
if (initialMode?.hasVisualSelection == false && !editor.selectionModel.hasSelection(true)) {
|
||||||
editor.selectionModel.hasSelection(true)
|
|
||||||
}
|
|
||||||
if (initialMode?.hasVisualSelection == false && !hasSelection) {
|
|
||||||
logger.trace { "Exiting without selection adjusting" }
|
logger.trace { "Exiting without selection adjusting" }
|
||||||
return@singleTask
|
return@singleTask
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSelection) {
|
if (editor.selectionModel.hasSelection(true)) {
|
||||||
if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) {
|
if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) {
|
||||||
logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" }
|
logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" }
|
||||||
return@singleTask
|
return@singleTask
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
package com.maddyhome.idea.vim.group.visual
|
package com.maddyhome.idea.vim.group.visual
|
||||||
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.mode
|
||||||
|
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.singleTask
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
|
@@ -183,7 +183,6 @@ internal abstract class OctopusHandler(private val nextHandler: EditorActionHand
|
|||||||
* - App code - set handler after
|
* - App code - set handler after
|
||||||
* - Template - doesn't intersect with enter anymore
|
* - Template - doesn't intersect with enter anymore
|
||||||
* - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
|
* - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
|
||||||
* - inline.completion.enter - set handler before. Otherwise, AI completion is not invoked on enter.
|
|
||||||
*
|
*
|
||||||
* This rule is disabled due to VIM-3124
|
* This rule is disabled due to VIM-3124
|
||||||
* - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122
|
* - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122
|
||||||
@@ -219,17 +218,13 @@ internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandle
|
|||||||
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
|
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
|
||||||
override val key: String = "<Esc>"
|
override val key: String = "<Esc>"
|
||||||
|
|
||||||
private val ideaVimSupportDialog
|
|
||||||
get() = injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
|
|
||||||
|
|
||||||
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
|
override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
|
||||||
return editor.isPrimaryEditor() ||
|
val ideaVimSupportDialog =
|
||||||
EditorHelper.isFileEditor(editor) && vimStateNeedsToHandleEscape(editor) ||
|
injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
|
||||||
ideaVimSupportDialog && vimStateNeedsToHandleEscape(editor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun vimStateNeedsToHandleEscape(editor: Editor): Boolean {
|
return editor.isPrimaryEditor() ||
|
||||||
return !editor.vim.mode.inNormalMode || KeyHandler.getInstance().keyHandlerState.mappingState.hasKeys
|
EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode ||
|
||||||
|
ideaVimSupportDialog && !editor.vim.mode.inNormalMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -157,19 +157,6 @@ public class EditorHelper {
|
|||||||
return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
|
return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of characters that can be fit inside the output panel for an editor.
|
|
||||||
* <p>
|
|
||||||
* This will be greater than the approximate screen width as it also includes any gutter components in the editor.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param editor The editor
|
|
||||||
* @return The approximate number of columns that can fit in the output panel
|
|
||||||
*/
|
|
||||||
public static int getApproximateOutputPanelWidth(final @NotNull Editor editor) {
|
|
||||||
return (int)(editor.getComponent().getWidth() / getPlainSpaceWidthFloat(editor));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the width of the space character in the editor's plain font as a float.
|
* Gets the width of the space character in the editor's plain font as a float.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -286,7 +273,7 @@ public class EditorHelper {
|
|||||||
|
|
||||||
// Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current
|
// Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current
|
||||||
// virtual space at the bottom of the screen
|
// virtual space at the bottom of the screen
|
||||||
final @NotNull 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) - 1;
|
||||||
final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y);
|
final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y);
|
||||||
scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset));
|
scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset));
|
||||||
@@ -338,7 +325,7 @@ public class EditorHelper {
|
|||||||
final int lineHeight = editor.getLineHeight();
|
final int lineHeight = editor.getLineHeight();
|
||||||
|
|
||||||
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
||||||
final @NotNull VimEditor editor1 = new IjVimEditor(editor);
|
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
||||||
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
|
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
|
||||||
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
||||||
|
|
||||||
@@ -392,7 +379,7 @@ public class EditorHelper {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getHorizontalScrollbarHeight(final @NotNull Editor editor) {
|
private static int getHorizontalScrollbarHeight(@NotNull final Editor editor) {
|
||||||
// Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured
|
// Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured
|
||||||
// text, or always visible, opaque and outside the content area, so we don't need to adjust for them
|
// text, or always visible, opaque and outside the content area, so we don't need to adjust for them
|
||||||
// Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That
|
// Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That
|
||||||
@@ -475,7 +462,7 @@ public class EditorHelper {
|
|||||||
*/
|
*/
|
||||||
public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) {
|
public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) {
|
||||||
final Rectangle visibleArea = getVisibleArea(editor);
|
final Rectangle visibleArea = getVisibleArea(editor);
|
||||||
final @NotNull VimEditor editor2 = new IjVimEditor(editor);
|
@NotNull final VimEditor editor2 = new IjVimEditor(editor);
|
||||||
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1;
|
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1;
|
||||||
|
|
||||||
int y = visibleArea.y + visibleArea.height;
|
int y = visibleArea.y + visibleArea.height;
|
||||||
@@ -493,7 +480,7 @@ public class EditorHelper {
|
|||||||
caretVisualLine = lastVisualLine;
|
caretVisualLine = lastVisualLine;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final @NotNull VimEditor editor1 = new IjVimEditor(editor);
|
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
||||||
caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
|
caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
|
||||||
completed = false;
|
completed = false;
|
||||||
}
|
}
|
||||||
@@ -528,7 +515,7 @@ public class EditorHelper {
|
|||||||
public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) {
|
public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) {
|
||||||
final Rectangle visibleArea = getVisibleArea(editor);
|
final Rectangle visibleArea = getVisibleArea(editor);
|
||||||
final int lineHeight = editor.getLineHeight();
|
final int lineHeight = editor.getLineHeight();
|
||||||
final @NotNull 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) - 1;
|
||||||
|
|
||||||
int y = visibleArea.y;
|
int y = visibleArea.y;
|
||||||
|
@@ -61,9 +61,6 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
get() = IdeActions.ACTION_EXPAND_REGION
|
get() = IdeActions.ACTION_EXPAND_REGION
|
||||||
override val ACTION_EXPAND_REGION_RECURSIVELY: String
|
override val ACTION_EXPAND_REGION_RECURSIVELY: String
|
||||||
get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
|
get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
|
||||||
override val ACTION_EXPAND_COLLAPSE_TOGGLE: String
|
|
||||||
// [VERSION UPDATE] 2024.3+ Replace raw "ExpandCollapseToggleAction" with IdeActions.ACTION_EXPAND_COLLAPSE_TOGGLE_REGION from the platform.
|
|
||||||
get() = "ExpandCollapseToggleAction"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute an action
|
* Execute an action
|
||||||
@@ -75,7 +72,7 @@ internal class IjActionExecutor : VimActionExecutor {
|
|||||||
val applicationEx = ApplicationManagerEx.getApplicationEx()
|
val applicationEx = ApplicationManagerEx.getApplicationEx()
|
||||||
if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
|
if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
|
||||||
// This is needed for VIM-3376 and it should turn into error at soeme moment
|
// This is needed for VIM-3376 and it should turn into error at soeme moment
|
||||||
thisLogger().warn("Actions cannot be updated when write-action is running or pending")
|
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
|
||||||
|
@@ -13,6 +13,7 @@ import com.intellij.openapi.editor.ReadOnlyFragmentModificationException
|
|||||||
import com.intellij.openapi.editor.VisualPosition
|
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.EngineEditorHelperBase
|
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
|
||||||
@@ -41,10 +42,6 @@ internal class IjEditorHelper : EngineEditorHelperBase() {
|
|||||||
return EditorHelper.getApproximateScreenWidth(editor.ij)
|
return EditorHelper.getApproximateScreenWidth(editor.ij)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getApproximateOutputPanelWidth(editor: VimEditor): Int {
|
|
||||||
return EditorHelper.getApproximateOutputPanelWidth(editor.ij)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) {
|
override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) {
|
||||||
return EditorActionManager.getInstance()
|
return EditorActionManager.getInstance()
|
||||||
.getReadonlyFragmentModificationHandler(editor.ij.document)
|
.getReadonlyFragmentModificationHandler(editor.ij.document)
|
||||||
|
@@ -16,6 +16,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.getLineEndForOffset
|
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
||||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
||||||
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
|
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
|
||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
@@ -93,6 +94,6 @@ internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Editor.exitInsertMode(context: DataContext) {
|
internal fun Editor.exitInsertMode(context: DataContext, operatorArguments: OperatorArguments) {
|
||||||
VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context))
|
VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context), operatorArguments)
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
|
|||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
|
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
|
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
@@ -102,8 +102,7 @@ private fun updateSearchHighlights(
|
|||||||
// Update highlights in all visible editors. We update non-visible editors when they get focus.
|
// Update highlights in all visible editors. We update non-visible editors when they get focus.
|
||||||
// Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles
|
// Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles
|
||||||
val editors = injector.editorGroup.getEditors().filter {
|
val editors = injector.editorGroup.getEditors().filter {
|
||||||
(injector.application.isUnitTest() || it.ij.component.isShowing)
|
injector.application.isUnitTest() || it.ij.component.isShowing
|
||||||
&& (currentEditor == null || it.projectId == currentEditor.projectId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
editors.forEach {
|
editors.forEach {
|
||||||
|
@@ -14,9 +14,7 @@ import com.intellij.openapi.command.CommandProcessor
|
|||||||
import com.intellij.openapi.command.undo.UndoManager
|
import com.intellij.openapi.command.undo.UndoManager
|
||||||
import com.intellij.openapi.components.Service
|
import com.intellij.openapi.components.Service
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.editor.Editor
|
|
||||||
import com.intellij.openapi.fileEditor.TextEditor
|
import com.intellij.openapi.fileEditor.TextEditor
|
||||||
import com.intellij.openapi.fileEditor.TextEditorWithPreview
|
|
||||||
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.project.Project
|
||||||
import com.intellij.openapi.util.registry.Registry
|
import com.intellij.openapi.util.registry.Registry
|
||||||
@@ -32,13 +30,13 @@ import com.maddyhome.idea.vim.newapi.globalIjOptions
|
|||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
|
import com.maddyhome.idea.vim.undo.UndoRedoBase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author oleg
|
* @author oleg
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
internal class UndoRedoHelper : VimTimestampBasedUndoService {
|
internal class UndoRedoHelper : UndoRedoBase() {
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = logger<UndoRedoHelper>()
|
private val logger = logger<UndoRedoHelper>()
|
||||||
}
|
}
|
||||||
@@ -46,13 +44,13 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
|
|||||||
override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
|
override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
|
||||||
val ijContext = context.context as DataContext
|
val ijContext = context.context as DataContext
|
||||||
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
|
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
|
||||||
val textEditor = getTextEditor(editor.ij)
|
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
|
||||||
val undoManager = UndoManager.getInstance(project)
|
val undoManager = UndoManager.getInstance(project)
|
||||||
if (undoManager.isUndoAvailable(textEditor)) {
|
if (undoManager.isUndoAvailable(fileEditor)) {
|
||||||
val scrollingModel = editor.getScrollingModel()
|
val scrollingModel = editor.getScrollingModel()
|
||||||
scrollingModel.accumulateViewportChanges()
|
scrollingModel.accumulateViewportChanges()
|
||||||
|
|
||||||
performUndo(editor, undoManager, textEditor)
|
performUndo(editor, undoManager, fileEditor)
|
||||||
|
|
||||||
scrollingModel.flushViewportChanges()
|
scrollingModel.flushViewportChanges()
|
||||||
|
|
||||||
@@ -61,15 +59,6 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTextEditor(editor: Editor): TextEditor {
|
|
||||||
// If the Editor is hosted in a TextEditor with a preview, then TextEditorProvider will return a TextEditor for the
|
|
||||||
// hosted instance, not for the main editor that also contains the preview. If we pass the inner TextEditor to the
|
|
||||||
// UndoManager, it doesn't correctly restore state. Specifically, the change is undone/redone, but the caret is not
|
|
||||||
// moved. See VIM-3671.
|
|
||||||
val currentTextEditor = TextEditorProvider.getInstance().getTextEditor(editor)
|
|
||||||
return TextEditorWithPreview.getParentSplitEditor(currentTextEditor) as? TextEditor ?: currentTextEditor
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun performUndo(
|
private fun performUndo(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
undoManager: UndoManager,
|
undoManager: UndoManager,
|
||||||
@@ -117,10 +106,10 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
|
|||||||
override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
|
override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
|
||||||
val ijContext = context.context as DataContext
|
val ijContext = context.context as DataContext
|
||||||
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
|
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
|
||||||
val textEditor = getTextEditor(editor.ij)
|
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
|
||||||
val undoManager = UndoManager.getInstance(project)
|
val undoManager = UndoManager.getInstance(project)
|
||||||
if (undoManager.isRedoAvailable(textEditor)) {
|
if (undoManager.isRedoAvailable(fileEditor)) {
|
||||||
performRedo(undoManager, textEditor, editor)
|
performRedo(undoManager, fileEditor, editor)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@@ -21,11 +21,11 @@ import com.intellij.openapi.util.UserDataHolder
|
|||||||
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.common.InsertSequence
|
||||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
|
|
||||||
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.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
import com.maddyhome.idea.vim.ui.ExOutputPanel
|
||||||
@@ -124,7 +124,6 @@ internal var Editor.vimExOutput: ExOutputModel? by userData()
|
|||||||
internal var Editor.vimTestInputModel: TestInputModel? by userData()
|
internal var Editor.vimTestInputModel: TestInputModel? by userData()
|
||||||
|
|
||||||
internal var Editor.vimChangeActionSwitchMode: Mode? by userData()
|
internal var Editor.vimChangeActionSwitchMode: Mode? by userData()
|
||||||
internal var Editor.replaceMask: VimEditorReplaceMask? by userData()
|
|
||||||
|
|
||||||
internal var Caret.currentInsert: InsertSequence? by userData()
|
internal var Caret.currentInsert: InsertSequence? by userData()
|
||||||
internal val Caret.insertHistory: MutableList<InsertSequence> by userDataOr { mutableListOf() }
|
internal val Caret.insertHistory: MutableList<InsertSequence> by userDataOr { mutableListOf() }
|
||||||
|
15
src/main/java/com/maddyhome/idea/vim/key/NodesHelper.kt
Normal file
15
src/main/java/com/maddyhome/idea/vim/key/NodesHelper.kt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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.key
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
|
||||||
|
internal fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
|
||||||
|
addLeafs(injector.parser.parseKeys(keys), actionHolder)
|
||||||
|
}
|
@@ -15,6 +15,7 @@ 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.inInsertMode
|
import com.maddyhome.idea.vim.helper.inInsertMode
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
@@ -64,7 +65,7 @@ class IJEditorFocusListener : EditorListener {
|
|||||||
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||||
val mode = injector.vimState.mode
|
val mode = injector.vimState.mode
|
||||||
when (mode) {
|
when (mode) {
|
||||||
is Mode.INSERT -> editor.exitInsertMode(context)
|
is Mode.INSERT -> editor.exitInsertMode(context, OperatorArguments(false, 0, mode))
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,4 +79,3 @@ class IJEditorFocusListener : EditorListener {
|
|||||||
KeyHandler.getInstance().reset(editor)
|
KeyHandler.getInstance().reset(editor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,9 +16,7 @@ import com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction
|
|||||||
import com.intellij.codeInsight.template.Template
|
import com.intellij.codeInsight.template.Template
|
||||||
import com.intellij.codeInsight.template.TemplateEditingAdapter
|
import com.intellij.codeInsight.template.TemplateEditingAdapter
|
||||||
import com.intellij.codeInsight.template.TemplateManagerListener
|
import com.intellij.codeInsight.template.TemplateManagerListener
|
||||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
|
||||||
import com.intellij.codeInsight.template.impl.TemplateState
|
import com.intellij.codeInsight.template.impl.TemplateState
|
||||||
import com.intellij.codeInsight.template.impl.actions.NextVariableAction
|
|
||||||
import com.intellij.find.FindModelListener
|
import com.intellij.find.FindModelListener
|
||||||
import com.intellij.openapi.actionSystem.ActionManager
|
import com.intellij.openapi.actionSystem.ActionManager
|
||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||||
@@ -154,10 +152,6 @@ internal object IdeaSpecifics {
|
|||||||
KeyHandler.getInstance().reset(it.vim)
|
KeyHandler.getInstance().reset(it.vim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (action is NextVariableAction && TemplateManagerImpl.getTemplateState(editor) == null) {
|
|
||||||
editor.vim.exitInsertMode(event.dataContext.vim)
|
|
||||||
KeyHandler.getInstance().reset(editor.vim)
|
|
||||||
}
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
|
if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
|
||||||
|
@@ -16,6 +16,7 @@ import com.intellij.openapi.diagnostic.Logger
|
|||||||
import com.intellij.openapi.diagnostic.trace
|
import com.intellij.openapi.diagnostic.trace
|
||||||
import com.intellij.openapi.editor.Caret
|
import com.intellij.openapi.editor.Caret
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
import com.intellij.openapi.editor.EditorKind
|
import com.intellij.openapi.editor.EditorKind
|
||||||
import com.intellij.openapi.editor.actionSystem.TypedAction
|
import com.intellij.openapi.editor.actionSystem.TypedAction
|
||||||
import com.intellij.openapi.editor.event.CaretEvent
|
import com.intellij.openapi.editor.event.CaretEvent
|
||||||
@@ -31,10 +32,10 @@ import com.intellij.openapi.editor.event.EditorMouseMotionListener
|
|||||||
import com.intellij.openapi.editor.event.SelectionEvent
|
import com.intellij.openapi.editor.event.SelectionEvent
|
||||||
import com.intellij.openapi.editor.event.SelectionListener
|
import com.intellij.openapi.editor.event.SelectionListener
|
||||||
import com.intellij.openapi.editor.ex.DocumentEx
|
import com.intellij.openapi.editor.ex.DocumentEx
|
||||||
import com.intellij.openapi.editor.ex.EditorEx
|
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.fileEditor.FileEditor
|
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
|
||||||
@@ -44,15 +45,15 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
|||||||
import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
|
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.observable.util.addKeyListener
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
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.intellij.util.SlowOperations
|
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
|
||||||
@@ -65,6 +66,7 @@ import com.maddyhome.idea.vim.api.coerceOffset
|
|||||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
||||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||||
import com.maddyhome.idea.vim.group.EditorGroup
|
import com.maddyhome.idea.vim.group.EditorGroup
|
||||||
import com.maddyhome.idea.vim.group.FileGroup
|
import com.maddyhome.idea.vim.group.FileGroup
|
||||||
import com.maddyhome.idea.vim.group.IjOptions
|
import com.maddyhome.idea.vim.group.IjOptions
|
||||||
@@ -105,11 +107,8 @@ 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 org.jetbrains.annotations.TestOnly
|
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import java.util.*
|
|
||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,15 +130,23 @@ import javax.swing.SwingUtilities
|
|||||||
* Make sure the selected editor isn't the new editor, which can happen if there are no other editors open.
|
* Make sure the selected editor isn't the new editor, which can happen if there are no other editors open.
|
||||||
*/
|
*/
|
||||||
private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project ->
|
private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project ->
|
||||||
// We can't rely on FileEditorManager.selectedTextEditor because we're trying to retrieve the selected text editor
|
// Some TextEditor implementations create a dummy Editor instance on demand, e.g., while downloading a file to edit
|
||||||
// while creating a text editor that is about to become the selected text editor.
|
// (see BaseRemoteFileEditor). This can cause recursion if the newly opened/created TextEditor is also the currently
|
||||||
// This worked fine for 2024.2, but internal changes for 2024.3 broke things. It appears that the currently selected
|
// selected TextEditor, because we will be notified of the new dummy Editor before it has finished initialisation, and
|
||||||
// text editor is reset to null while the soon-to-be-selected text editor is being created. We therefore track the
|
// try to get its opening editor, causing a new dummy Editor to be created and notifications sent, and so on.
|
||||||
// last selected editor manually.
|
// This was reported for 232 and 233 (see VIM-3066), but I can't recreate in 241. The callstack looks different, now
|
||||||
// Note that if we ever switch back to FileEditorManager.selectedTextEditor, be careful of recursion, because the
|
// using coroutines, so it's possible the deadlock has been broken. However, it's sensible to leave the recursion
|
||||||
// actual editor might be created on-demand, which would notify our initialisation method, which would call us...
|
// guard in.
|
||||||
VimListenerManager.VimLastSelectedEditorTracker.getLastSelectedEditor(project)?.takeUnless { it == newEditor }
|
if (openingEditorRecursionGuard) return null
|
||||||
|
openingEditorRecursionGuard = true
|
||||||
|
try {
|
||||||
|
FileEditorManager.getInstance(project).selectedTextEditor?.takeUnless { it == newEditor }
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
openingEditorRecursionGuard = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var openingEditorRecursionGuard = false
|
||||||
|
|
||||||
internal object VimListenerManager {
|
internal object VimListenerManager {
|
||||||
|
|
||||||
@@ -149,9 +156,7 @@ internal object VimListenerManager {
|
|||||||
|
|
||||||
fun turnOn() {
|
fun turnOn() {
|
||||||
GlobalListeners.enable()
|
GlobalListeners.enable()
|
||||||
SlowOperations.knownIssue("VIM-3648, VIM-3649").use {
|
|
||||||
EditorListeners.addAll()
|
EditorListeners.addAll()
|
||||||
}
|
|
||||||
check(correctorRequester.tryEmit(Unit))
|
check(correctorRequester.tryEmit(Unit))
|
||||||
check(keyCheckRequests.tryEmit(Unit))
|
check(keyCheckRequests.tryEmit(Unit))
|
||||||
|
|
||||||
@@ -212,6 +217,16 @@ internal object VimListenerManager {
|
|||||||
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
|
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
|
||||||
val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable)
|
val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable)
|
||||||
busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener)
|
busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener)
|
||||||
|
|
||||||
|
// Listen for focus change to update various features such as mode widget
|
||||||
|
val eventMulticaster = EditorFactory.getInstance().eventMulticaster
|
||||||
|
(eventMulticaster as? EditorEventMulticasterEx)?.addFocusChangeListener(
|
||||||
|
VimFocusListener,
|
||||||
|
VimPlugin.getInstance().onOffDisposable
|
||||||
|
)
|
||||||
|
|
||||||
|
// Listen for document changes to update document state such as marks
|
||||||
|
eventMulticaster.addDocumentListener(VimDocumentListener, VimPlugin.getInstance().onOffDisposable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disable() {
|
fun disable() {
|
||||||
@@ -273,52 +288,45 @@ 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
|
||||||
|
|
||||||
|
val pluginLifetime = VimPlugin.getInstance().createLifetime()
|
||||||
|
val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
|
||||||
|
val disposable =
|
||||||
|
Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
|
||||||
|
|
||||||
// Protect against double initialisation
|
// Protect against double initialisation
|
||||||
if (editor.getUserData(editorListenersDisposableKey) != null) {
|
if (editor.getUserData(editorListenersDisposableKey) != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we explicitly dispose this per-editor disposable!
|
val listenersDisposable = Disposer.newDisposable(disposable)
|
||||||
// Because the listeners are registered with a parent disposable, they add child disposables that have to call a
|
editor.putUserData(editorListenersDisposableKey, listenersDisposable)
|
||||||
// method on the editor to remove the listener. This means the disposable contains a reference to the editor (even
|
|
||||||
// if the listener handler is a singleton that doesn't hold a reference).
|
|
||||||
// Unless the per-editor disposable is disposed, all of these disposables sit in the disposer tree until the
|
|
||||||
// parent disposable is disposed, which will mean we leak editor instances.
|
|
||||||
// The per-editor disposable is explicitly disposed when the editor is released, and disposed via its parent when
|
|
||||||
// the plugin's on/off functionality is toggled, and so also when the plugin is disabled/unloaded by the platform.
|
|
||||||
// It doesn't matter if we explicitly remove all listeners before disposing onOffDisposable, as that will remove
|
|
||||||
// the per-editor disposable from the disposer tree.
|
|
||||||
val perEditorDisposable = Disposer.newDisposable(VimPlugin.getInstance().onOffDisposable)
|
|
||||||
editor.putUserData(editorListenersDisposableKey, perEditorDisposable)
|
|
||||||
|
|
||||||
Disposer.register(perEditorDisposable) {
|
Disposer.register(listenersDisposable) {
|
||||||
if (VimListenerTestObject.enabled) {
|
if (VimListenerTestObject.enabled) {
|
||||||
VimListenerTestObject.disposedCounter += 1
|
VimListenerTestObject.disposedCounter += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This listener and several below add a reference to the editor to the disposer tree
|
editor.contentComponent.addKeyListener(VimKeyListener)
|
||||||
editor.contentComponent.addKeyListener(perEditorDisposable, VimKeyListener)
|
Disposer.register(listenersDisposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
|
||||||
|
|
||||||
// Initialise the local options. We MUST do this before anything has the chance to query options
|
// Initialise the local options. We MUST do this before anything has the chance to query options
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario)
|
VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario)
|
||||||
|
|
||||||
val eventFacade = EventFacade.getInstance()
|
val eventFacade = EventFacade.getInstance()
|
||||||
eventFacade.addEditorMouseListener(editor, EditorMouseHandler, perEditorDisposable)
|
eventFacade.addEditorMouseListener(editor, EditorMouseHandler, listenersDisposable)
|
||||||
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, perEditorDisposable)
|
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, listenersDisposable)
|
||||||
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, perEditorDisposable)
|
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, listenersDisposable)
|
||||||
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, perEditorDisposable)
|
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, listenersDisposable)
|
||||||
eventFacade.addCaretListener(editor, EditorCaretHandler, perEditorDisposable)
|
eventFacade.addCaretListener(editor, EditorCaretHandler, listenersDisposable)
|
||||||
|
|
||||||
VimPlugin.getEditor().editorCreated(editor)
|
VimPlugin.getEditor().editorCreated(editor)
|
||||||
VimPlugin.getChange().editorCreated(editor, perEditorDisposable)
|
VimPlugin.getChange().editorCreated(editor, listenersDisposable)
|
||||||
|
|
||||||
(editor as EditorEx).addFocusListener(VimFocusListener, perEditorDisposable)
|
|
||||||
|
|
||||||
injector.listenersNotifier.notifyEditorCreated(vimEditor)
|
injector.listenersNotifier.notifyEditorCreated(vimEditor)
|
||||||
|
|
||||||
Disposer.register(perEditorDisposable) {
|
Disposer.register(listenersDisposable) {
|
||||||
VimPlugin.getEditor().editorDeinit(editor)
|
VimPlugin.getEditor().editorDeinit(editor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +364,7 @@ internal object VimListenerManager {
|
|||||||
* open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest
|
* open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest
|
||||||
* edits a file. Updating search highlights will be a no-op if there are no open local editors)
|
* edits a file. Updating search highlights will be a no-op if there are no open local editors)
|
||||||
*/
|
*/
|
||||||
class VimDocumentListener : DocumentListener {
|
private object VimDocumentListener : DocumentListener {
|
||||||
override fun beforeDocumentChange(event: DocumentEvent) {
|
override fun beforeDocumentChange(event: DocumentEvent) {
|
||||||
VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event)
|
VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event)
|
||||||
IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event)
|
IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event)
|
||||||
@@ -370,26 +378,6 @@ internal object VimListenerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object VimLastSelectedEditorTracker {
|
|
||||||
// This stores a weak reference to an editor against a weak reference to a project, which means there is nothing
|
|
||||||
// keeping the project or editor from being garbage collected at any time. Stale keys are automatically expunged
|
|
||||||
// whenever the map is used.
|
|
||||||
private val selectedEditors = WeakHashMap<Project, WeakReference<Editor>>()
|
|
||||||
|
|
||||||
fun getLastSelectedEditor(project: Project): Editor? = selectedEditors[project]?.get()
|
|
||||||
|
|
||||||
internal fun setLastSelectedEditor(fileEditor: FileEditor?) {
|
|
||||||
(fileEditor as? TextEditor)?.editor?.let { editor ->
|
|
||||||
editor.project?.let { project -> selectedEditors[project] = WeakReference(editor) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestOnly
|
|
||||||
internal fun resetLastSelectedEditor(project: Project) {
|
|
||||||
selectedEditors.remove(project)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the
|
* Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the
|
||||||
* last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me
|
* last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me
|
||||||
@@ -407,15 +395,14 @@ internal object VimListenerManager {
|
|||||||
editor.vim.mode = Mode.NORMAL()
|
editor.vim.mode = Mode.NORMAL()
|
||||||
KeyHandler.getInstance().reset(editor.vim)
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
}
|
}
|
||||||
// Breaks relativenumber for some reason
|
injector.scroll.scrollCaretIntoView(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)
|
||||||
|
OptionGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
|
IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
|
||||||
VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,21 +474,8 @@ internal object VimListenerManager {
|
|||||||
override fun editorReleased(event: EditorFactoryEvent) {
|
override fun editorReleased(event: EditorFactoryEvent) {
|
||||||
if (vimDisabled(event.editor)) return
|
if (vimDisabled(event.editor)) return
|
||||||
val vimEditor = event.editor.vim
|
val vimEditor = event.editor.vim
|
||||||
EditorListeners.remove(event.editor)
|
|
||||||
injector.listenersNotifier.notifyEditorReleased(vimEditor)
|
injector.listenersNotifier.notifyEditorReleased(vimEditor)
|
||||||
injector.markService.editorReleased(vimEditor)
|
injector.markService.editorReleased(vimEditor)
|
||||||
|
|
||||||
// This ticket will have a different stack trace, but it's the same problem. Originally, we tracked the last
|
|
||||||
// editor closing based on file selection (closing an editor would select the next editor - so a null selection
|
|
||||||
// was taken to mean that there were no more editors to select). This assumption broke in 242, so it's changed to
|
|
||||||
// check when the editor is released.
|
|
||||||
// However, the actions taken when the last editor closes can still be expensive/slow because we copy options, and
|
|
||||||
// some options are backed by PSI options. E.g. 'textwidth' is mapped to
|
|
||||||
// CodeStyle.getSettings(ijEditor).isWrapOnTyping(language)), and getting the document's PSI language is a slow
|
|
||||||
// operation. This underlying issue still needs to be addressed, even though the method has moved
|
|
||||||
SlowOperations.knownIssue("VIM-3658").use {
|
|
||||||
OptionGroup.editorReleased(event.editor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fileOpenedSync(
|
override fun fileOpenedSync(
|
||||||
@@ -774,7 +748,7 @@ internal object VimListenerManager {
|
|||||||
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
||||||
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
||||||
|
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
ExOutputModel.tryGetInstance(editor)?.close()
|
||||||
|
|
||||||
val caretModel = editor.caretModel
|
val caretModel = editor.caretModel
|
||||||
if (editor.vim.mode.selectionType != null) {
|
if (editor.vim.mode.selectionType != null) {
|
||||||
@@ -789,10 +763,6 @@ internal object VimListenerManager {
|
|||||||
// https://youtrack.jetbrains.com/issue/IDEA-277716
|
// https://youtrack.jetbrains.com/issue/IDEA-277716
|
||||||
// https://youtrack.jetbrains.com/issue/VIM-2368
|
// https://youtrack.jetbrains.com/issue/VIM-2368
|
||||||
if (event.mouseEvent.clickCount == 1 && !SwingUtilities.isRightMouseButton(event.mouseEvent)) {
|
if (event.mouseEvent.clickCount == 1 && !SwingUtilities.isRightMouseButton(event.mouseEvent)) {
|
||||||
val hasSelection = ApplicationManager.getApplication().runReadAction<Boolean> {
|
|
||||||
editor.selectionModel.hasSelection(true)
|
|
||||||
}
|
|
||||||
if (!hasSelection) {
|
|
||||||
if (editor.inVisualMode) {
|
if (editor.inVisualMode) {
|
||||||
editor.vim.exitVisualMode()
|
editor.vim.exitVisualMode()
|
||||||
} else if (editor.vim.inSelectMode) {
|
} else if (editor.vim.inSelectMode) {
|
||||||
@@ -800,7 +770,6 @@ internal object VimListenerManager {
|
|||||||
KeyHandler.getInstance().reset(editor.vim)
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA &&
|
} else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA &&
|
||||||
event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA &&
|
event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA &&
|
||||||
event.mouseEvent.button != MouseEvent.BUTTON3
|
event.mouseEvent.button != MouseEvent.BUTTON3
|
||||||
@@ -808,7 +777,7 @@ internal object VimListenerManager {
|
|||||||
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
|
||||||
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
|
||||||
|
|
||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
ExOutputModel.getInstance(event.editor).close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,13 +22,10 @@ import com.intellij.openapi.project.DumbService
|
|||||||
import com.intellij.openapi.project.IndexNotReadyException
|
import com.intellij.openapi.project.IndexNotReadyException
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.util.ui.EmptyClipboardOwner
|
import com.intellij.util.ui.EmptyClipboardOwner
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
|
||||||
import com.maddyhome.idea.vim.api.VimClipboardManager
|
import com.maddyhome.idea.vim.api.VimClipboardManager
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
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.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.common.VimCopiedText
|
|
||||||
import com.maddyhome.idea.vim.diagnostic.debug
|
import com.maddyhome.idea.vim.diagnostic.debug
|
||||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
||||||
import java.awt.HeadlessException
|
import java.awt.HeadlessException
|
||||||
@@ -40,52 +37,18 @@ import java.io.IOException
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
internal class IjClipboardManager : VimClipboardManager {
|
internal class IjClipboardManager : VimClipboardManager {
|
||||||
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getPrimaryTextAndTransferableData")
|
|
||||||
override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? {
|
override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? {
|
||||||
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null
|
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null
|
||||||
val contents = clipboard.getContents(null) ?: return null
|
val contents = clipboard.getContents(null) ?: return null
|
||||||
return getTextAndTransferableData(contents)
|
return getTextAndTransferableData(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPrimaryContent(editor: VimEditor, context: ExecutionContext): IjVimCopiedText? {
|
|
||||||
val (text, transferableData) = getPrimaryTextAndTransferableData() ?: return null
|
|
||||||
return IjVimCopiedText(text, transferableData ?: emptyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getClipboardTextAndTransferableData")
|
|
||||||
override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? {
|
override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? {
|
||||||
val contents = getContents() ?: return null
|
val contents = getContents() ?: return null
|
||||||
return getTextAndTransferableData(contents)
|
return getTextAndTransferableData(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getClipboardContent(editor: VimEditor, context: ExecutionContext): VimCopiedText? {
|
private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<Any>?>? {
|
||||||
val (text, transferableData) = getClipboardTextAndTransferableData() ?: return null
|
|
||||||
return IjVimCopiedText(text, transferableData ?: emptyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setClipboardContent(editor: VimEditor, context: ExecutionContext, textData: VimCopiedText): Boolean {
|
|
||||||
require(textData is IjVimCopiedText)
|
|
||||||
return handleTextSetting(textData.text, textData.text, textData.transferableData) { content -> setContents(content) } != null
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO prefer methods with ranges, because they collect and preprocess for us
|
|
||||||
// override fun createClipboardEntry(
|
|
||||||
// editor: VimEditor,
|
|
||||||
// context: ExecutionContext,
|
|
||||||
// text: String,
|
|
||||||
// range: TextRange,
|
|
||||||
// ): ClipboardEntry {
|
|
||||||
// val transferableData = getTransferableData(editor, range, text)
|
|
||||||
// val preprocessedText = preprocessText(editor, range, text, transferableData)
|
|
||||||
// return IJClipboardEntry(preprocessedText, text, transferableData)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// override fun setClipboardText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
|
|
||||||
// require(entry is IJClipboardEntry)
|
|
||||||
// return setClipboardText(entry.text, entry.rawText, entry.transferableData) != null
|
|
||||||
// }
|
|
||||||
|
|
||||||
private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<TextBlockTransferableData>?>? {
|
|
||||||
var res: String? = null
|
var res: String? = null
|
||||||
var transferableData: List<TextBlockTransferableData> = ArrayList()
|
var transferableData: List<TextBlockTransferableData> = ArrayList()
|
||||||
try {
|
try {
|
||||||
@@ -100,29 +63,10 @@ internal class IjClipboardManager : VimClipboardManager {
|
|||||||
return Pair(res, transferableData)
|
return Pair(res, transferableData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setClipboardText")
|
|
||||||
override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
|
override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
|
||||||
return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) }
|
return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setPrimaryContent(
|
|
||||||
editor: VimEditor,
|
|
||||||
context: ExecutionContext,
|
|
||||||
textData: VimCopiedText,
|
|
||||||
): Boolean {
|
|
||||||
require(textData is IjVimCopiedText)
|
|
||||||
return handleTextSetting(textData.text, textData.text, textData.transferableData) { content ->
|
|
||||||
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
|
|
||||||
clipboard.setContents(content, EmptyClipboardOwner.INSTANCE)
|
|
||||||
} != null
|
|
||||||
}
|
|
||||||
|
|
||||||
// override fun setPrimaryText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
|
|
||||||
// require(entry is IJClipboardEntry)
|
|
||||||
// return setPrimaryText(entry.text, entry.rawText, entry.transferableData) != null
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setPrimaryText")
|
|
||||||
override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
|
override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
|
||||||
return handleTextSetting(text, rawText, transferableData) { content ->
|
return handleTextSetting(text, rawText, transferableData) { content ->
|
||||||
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
|
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
|
||||||
@@ -130,16 +74,6 @@ internal class IjClipboardManager : VimClipboardManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun collectCopiedText(editor: VimEditor, context: ExecutionContext, range: TextRange, text: String): VimCopiedText {
|
|
||||||
val transferableData = getTransferableData(editor, range)
|
|
||||||
val preprocessedText = preprocessText(editor, range, text, transferableData)
|
|
||||||
return IjVimCopiedText(preprocessedText, transferableData)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumbCopiedText(text: String): VimCopiedText {
|
|
||||||
return IjVimCopiedText(text, emptyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? {
|
private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? {
|
||||||
val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList()
|
val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList()
|
||||||
@@ -158,7 +92,7 @@ internal class IjClipboardManager : VimClipboardManager {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange): List<TextBlockTransferableData> {
|
override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange, text: String): List<Any> {
|
||||||
val editor = (vimEditor as IjVimEditor).editor
|
val editor = (vimEditor as IjVimEditor).editor
|
||||||
val transferableData: MutableList<TextBlockTransferableData> = ArrayList()
|
val transferableData: MutableList<TextBlockTransferableData> = ArrayList()
|
||||||
val project = editor.project ?: return emptyList()
|
val project = editor.project ?: return emptyList()
|
||||||
@@ -183,7 +117,7 @@ internal class IjClipboardManager : VimClipboardManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(textRange.endOffset - textRange.startOffset)))
|
transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(text.length)))
|
||||||
|
|
||||||
// These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with
|
// These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with
|
||||||
// IdeaVim and I don't see a way to fix it
|
// IdeaVim and I don't see a way to fix it
|
||||||
@@ -241,7 +175,3 @@ internal class IjClipboardManager : VimClipboardManager {
|
|||||||
val logger = vimLogger<IjClipboardManager>()
|
val logger = vimLogger<IjClipboardManager>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class IjVimCopiedText(override val text: String, val transferableData: List<Any>): VimCopiedText {
|
|
||||||
override fun updateText(newText: String): VimCopiedText = IjVimCopiedText(newText, transferableData)
|
|
||||||
}
|
|
||||||
|
@@ -14,27 +14,6 @@ import com.maddyhome.idea.vim.common.LiveRange
|
|||||||
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
|
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
|
||||||
override val startOffset: Int
|
override val startOffset: Int
|
||||||
get() = marker.startOffset
|
get() = marker.startOffset
|
||||||
|
|
||||||
override val endOffset: Int
|
|
||||||
get() = marker.endOffset
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as IjLiveRange
|
|
||||||
|
|
||||||
if (startOffset != other.startOffset) return false
|
|
||||||
if (endOffset != other.endOffset) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = startOffset
|
|
||||||
result = 31 * result + endOffset
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val RangeMarker.vim: LiveRange
|
val RangeMarker.vim: LiveRange
|
||||||
|
@@ -19,7 +19,6 @@ import com.maddyhome.idea.vim.api.VimCaret
|
|||||||
import com.maddyhome.idea.vim.api.VimCaretBase
|
import com.maddyhome.idea.vim.api.VimCaretBase
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
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.common.InsertSequence
|
import com.maddyhome.idea.vim.common.InsertSequence
|
||||||
import com.maddyhome.idea.vim.common.LiveRange
|
import com.maddyhome.idea.vim.common.LiveRange
|
||||||
import com.maddyhome.idea.vim.group.visual.VisualChange
|
import com.maddyhome.idea.vim.group.visual.VisualChange
|
||||||
@@ -35,14 +34,10 @@ import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
|
|||||||
import com.maddyhome.idea.vim.helper.vimLine
|
import com.maddyhome.idea.vim.helper.vimLine
|
||||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
|
import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||||
import com.maddyhome.idea.vim.helper.vimSelectionStartClear
|
import com.maddyhome.idea.vim.helper.vimSelectionStartClear
|
||||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
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: VimRegisterGroup
|
|
||||||
get() = injector.registerGroup
|
|
||||||
|
|
||||||
override val markStorage: LocalMarkStorage
|
override val markStorage: LocalMarkStorage
|
||||||
get() {
|
get() {
|
||||||
var storage = this.caret.markStorage
|
var storage = this.caret.markStorage
|
||||||
|
@@ -38,12 +38,12 @@ import com.maddyhome.idea.vim.api.VimSelectionModel
|
|||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||||
import com.maddyhome.idea.vim.api.VirtualFile
|
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.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
|
||||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
|
|
||||||
import com.maddyhome.idea.vim.common.forgetAllReplaceMasks
|
|
||||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemBlockSelectionSilently
|
import com.maddyhome.idea.vim.group.visual.vimSetSystemBlockSelectionSilently
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper
|
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||||
import com.maddyhome.idea.vim.helper.StrictMode
|
import com.maddyhome.idea.vim.helper.StrictMode
|
||||||
@@ -53,15 +53,12 @@ import com.maddyhome.idea.vim.helper.fileSize
|
|||||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||||
import com.maddyhome.idea.vim.helper.inExMode
|
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.replaceMask
|
|
||||||
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.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
|
||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
|
|
||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
|
|
||||||
import org.jetbrains.annotations.ApiStatus
|
import org.jetbrains.annotations.ApiStatus
|
||||||
import java.lang.System.identityHashCode
|
import java.lang.System.identityHashCode
|
||||||
|
|
||||||
@@ -78,11 +75,6 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
// TBH, I don't like the names. Need to think a bit more about this
|
// TBH, I don't like the names. Need to think a bit more about this
|
||||||
val editor = editor.getTopLevelEditor()
|
val editor = editor.getTopLevelEditor()
|
||||||
val originalEditor = editor
|
val originalEditor = editor
|
||||||
override var replaceMask: VimEditorReplaceMask?
|
|
||||||
get() = editor.replaceMask
|
|
||||||
set(value) {
|
|
||||||
editor.replaceMask = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateMode(mode: Mode) {
|
override fun updateMode(mode: Mode) {
|
||||||
(injector.vimState as VimStateMachineImpl).mode = mode
|
(injector.vimState as VimStateMachineImpl).mode = mode
|
||||||
@@ -99,7 +91,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
editor.vimChangeActionSwitchMode = value
|
editor.vimChangeActionSwitchMode = value
|
||||||
}
|
}
|
||||||
override val indentConfig: VimIndentConfig
|
override val indentConfig: VimIndentConfig
|
||||||
get() = IndentConfig.create(editor)
|
get() = create(editor)
|
||||||
|
|
||||||
override fun fileSize(): Long = editor.fileSize.toLong()
|
override fun fileSize(): Long = editor.fileSize.toLong()
|
||||||
|
|
||||||
@@ -142,13 +134,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
|
|
||||||
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
|
||||||
if (injector.vimState.mode is Mode.INSERT) {
|
if (injector.vimState.mode is Mode.INSERT) {
|
||||||
val undo = injector.undo
|
injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
||||||
when (undo) {
|
|
||||||
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
|
|
||||||
is VimTimestampBasedUndoService -> {
|
|
||||||
undo.startInsertSequence(caret, atPosition, System.nanoTime())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
editor.document.insertString(atPosition, text)
|
editor.document.insertString(atPosition, text)
|
||||||
}
|
}
|
||||||
@@ -412,8 +398,8 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight))
|
return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitInsertMode(context: ExecutionContext) {
|
override fun exitInsertMode(context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
editor.exitInsertMode(context.ij)
|
editor.exitInsertMode(context.ij, operatorArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitSelectModeNative(adjustCaret: Boolean) {
|
override fun exitSelectModeNative(adjustCaret: Boolean) {
|
||||||
@@ -485,7 +471,6 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
|||||||
get() = (editor as? EditorEx)?.isInsertMode ?: false
|
get() = (editor as? EditorEx)?.isInsertMode ?: false
|
||||||
set(value) {
|
set(value) {
|
||||||
(editor as? EditorEx)?.isInsertMode = value
|
(editor as? EditorEx)?.isInsertMode = value
|
||||||
forgetAllReplaceMasks()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val document: VimDocument
|
override val document: VimDocument
|
||||||
@@ -557,7 +542,7 @@ internal class InsertTimeRecorder: ModeChangeListener {
|
|||||||
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
||||||
editor as IjVimEditor
|
editor as IjVimEditor
|
||||||
if (oldMode == Mode.INSERT) {
|
if (oldMode == Mode.INSERT) {
|
||||||
val undo = injector.undo as? VimTimestampBasedUndoService ?: return
|
val undo = injector.undo
|
||||||
val nanoTime = System.nanoTime()
|
val nanoTime = System.nanoTime()
|
||||||
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -18,8 +18,11 @@ import com.intellij.openapi.editor.event.DocumentEvent
|
|||||||
import com.intellij.openapi.editor.event.DocumentListener
|
import com.intellij.openapi.editor.event.DocumentListener
|
||||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
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.Options
|
import com.maddyhome.idea.vim.api.Options
|
||||||
|
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.VimSearchGroupBase
|
import com.maddyhome.idea.vim.api.VimSearchGroupBase
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
@@ -27,16 +30,21 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.common.Direction
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
import com.maddyhome.idea.vim.common.Direction.Companion.fromInt
|
import com.maddyhome.idea.vim.common.Direction.Companion.fromInt
|
||||||
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.TestInputModel.Companion.getInstance
|
||||||
import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight
|
import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight
|
||||||
import com.maddyhome.idea.vim.helper.highlightSearchResults
|
import com.maddyhome.idea.vim.helper.highlightSearchResults
|
||||||
|
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
|
||||||
import com.maddyhome.idea.vim.helper.shouldIgnoreCase
|
import com.maddyhome.idea.vim.helper.shouldIgnoreCase
|
||||||
import com.maddyhome.idea.vim.helper.updateSearchHighlights
|
import com.maddyhome.idea.vim.helper.updateSearchHighlights
|
||||||
import com.maddyhome.idea.vim.helper.vimLastHighlighters
|
import com.maddyhome.idea.vim.helper.vimLastHighlighters
|
||||||
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
|
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
|
||||||
|
import com.maddyhome.idea.vim.ui.ModalEntry
|
||||||
import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler
|
import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler
|
||||||
import org.jdom.Element
|
import org.jdom.Element
|
||||||
import org.jetbrains.annotations.Contract
|
import org.jetbrains.annotations.Contract
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
@State(
|
@State(
|
||||||
name = "VimSearchSettings",
|
name = "VimSearchSettings",
|
||||||
@@ -44,7 +52,7 @@ import org.jetbrains.annotations.TestOnly
|
|||||||
)
|
)
|
||||||
open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> {
|
open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> {
|
||||||
companion object {
|
companion object {
|
||||||
private val logger by lazy { vimLogger<IjVimSearchGroup>() }
|
private val logger = vimLogger<IjVimSearchGroup>()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -104,25 +112,27 @@ open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Ele
|
|||||||
return IjSearchHighlight(ijEditor, highlighter)
|
return IjSearchHighlight(ijEditor, highlighter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setLatestMatch(match: String) {
|
||||||
|
SubmatchFunctionHandler.getInstance().latestMatch = match
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun replaceString(
|
||||||
|
editor: VimEditor,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
newString: String,
|
||||||
|
) {
|
||||||
|
ApplicationManager.getApplication().runWriteAction {
|
||||||
|
(editor as IjVimEditor).editor.document.replaceString(startOffset, endOffset, newString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
override fun resetState() {
|
override fun resetState() {
|
||||||
super.resetState()
|
super.resetState()
|
||||||
showSearchHighlight = injector.globalOptions().hlsearch
|
showSearchHighlight = injector.globalOptions().hlsearch
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSomeTextHighlighted(): Boolean {
|
|
||||||
val vimEditors = injector.editorGroup.getEditors().filter {
|
|
||||||
(injector.application.isUnitTest() || it.ij.component.isShowing)
|
|
||||||
}
|
|
||||||
for (vimEditor in vimEditors) {
|
|
||||||
val editor = vimEditor.ij
|
|
||||||
if (editor.vimLastHighlighters != null) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setShouldShowSearchHighlights() {
|
override fun setShouldShowSearchHighlights() {
|
||||||
showSearchHighlight = injector.globalOptions().hlsearch
|
showSearchHighlight = injector.globalOptions().hlsearch
|
||||||
}
|
}
|
||||||
|
718
src/main/java/com/maddyhome/idea/vim/package-info.java
Normal file
718
src/main/java/com/maddyhome/idea/vim/package-info.java
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IdeaVim command index.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 1. Insert mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |i_CTRL-@| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertExitAction}
|
||||||
|
* |i_CTRL-A| {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertAction}
|
||||||
|
* |i_CTRL-C| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-D| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftLinesAction}
|
||||||
|
* |i_CTRL-E| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterBelowCursorAction}
|
||||||
|
* |i_CTRL-G_j| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-G_k| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-G_u| TO BE IMPLEMENTED
|
||||||
|
* |i_<BS>| {@link com.maddyhome.idea.vim.action.editor.VimEditorBackSpace}
|
||||||
|
* |i_digraph| IdeaVim enter digraph
|
||||||
|
* |i_CTRL-H| IntelliJ editor backspace
|
||||||
|
* |i_<Tab>| {@link com.maddyhome.idea.vim.action.editor.VimEditorTab}
|
||||||
|
* |i_CTRL-I| IntelliJ editor tab
|
||||||
|
* |i_<NL>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-J| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-K| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction}
|
||||||
|
* |i_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |i_<CR>| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-M| {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
|
||||||
|
* |i_CTRL-N| {@link com.maddyhome.idea.vim.action.window.LookupDownAction}
|
||||||
|
* |i_CTRL-O| {@link com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction}
|
||||||
|
* |i_CTRL-P| {@link com.maddyhome.idea.vim.action.window.LookupUpAction}
|
||||||
|
* |i_CTRL-Q| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R| {@link com.maddyhome.idea.vim.action.change.insert.InsertRegisterAction}
|
||||||
|
* |i_CTRL-R_CTRL-R| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-R_CTRL-P| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-T| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightLinesAction}
|
||||||
|
* |i_CTRL-U| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeleteInsertedTextAction}
|
||||||
|
* |i_CTRL-V| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
|
||||||
|
* |i_CTRL-V_digit| {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
|
||||||
|
* |i_CTRL-W| {@link com.maddyhome.idea.vim.action.change.insert.InsertDeletePreviousWordAction}
|
||||||
|
* |i_CTRL-X| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-Y| {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterAboveCursorAction}
|
||||||
|
* |i_CTRL-Z| TO BE IMPLEMENTED
|
||||||
|
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
|
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
|
||||||
|
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-]} TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-^| TO BE IMPLEMENTED
|
||||||
|
* |i_CTRL-_| TO BE IMPLEMENTED
|
||||||
|
* |i_0_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |i_^_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |i_<Del>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDelete}
|
||||||
|
* |i_<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction}
|
||||||
|
* |i_<S-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
|
||||||
|
* |i_<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
|
||||||
|
* |i_<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction}
|
||||||
|
* |i_<S-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
|
||||||
|
* |i_<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
|
||||||
|
* |i_<Up>| {@link com.maddyhome.idea.vim.action.editor.VimEditorUp}
|
||||||
|
* |i_<S-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
|
||||||
|
* |i_<Down>| {@link com.maddyhome.idea.vim.action.editor.VimEditorDown}
|
||||||
|
* |i_<S-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
|
||||||
|
* |i_<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnInsertModeAction}
|
||||||
|
* |i_<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstInsertAction}
|
||||||
|
* |i_<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnInsertAction}
|
||||||
|
* |i_<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndInsertAction}
|
||||||
|
* |i_<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertInsertAction}
|
||||||
|
* |i_<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
|
||||||
|
* |i_<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
|
||||||
|
* |i_<F1>| IntelliJ help
|
||||||
|
* |i_<Insert>| IntelliJ editor toggle insert/replace
|
||||||
|
* |i_CTRL-X_index| TO BE IMPLEMENTED
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2. Normal mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberIncAction}
|
||||||
|
* |CTRL-B| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
|
||||||
|
* |CTRL-C| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-D| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageDownAction}
|
||||||
|
* |CTRL-E| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineDownAction}
|
||||||
|
* |CTRL-F| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
|
||||||
|
* |CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetFileInfoAction}
|
||||||
|
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
|
||||||
|
* |CTRL-H| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
|
||||||
|
* |<Tab>| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-I| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpNextAction}
|
||||||
|
* |<NL>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownNotLineWiseAction}
|
||||||
|
* |CTRL-J| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-L| not applicable
|
||||||
|
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.updown.EnterNormalAction}
|
||||||
|
* |CTRL-M| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
|
||||||
|
* |CTRL-N| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction}
|
||||||
|
* |CTRL-O| {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpPreviousAction}
|
||||||
|
* |CTRL-P| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpCtrlPAction}
|
||||||
|
* |CTRL-R| {@link com.maddyhome.idea.vim.action.change.RedoAction}
|
||||||
|
* |CTRL-T| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-U| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageUpAction}
|
||||||
|
* |CTRL-V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleBlockModeAction}
|
||||||
|
* |CTRL-W| see window commands
|
||||||
|
* |CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberDecAction}
|
||||||
|
* |CTRL-Y| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineUpAction}
|
||||||
|
* |CTRL-Z| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-]| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |CTRL-6| {@link com.maddyhome.idea.vim.action.file.FilePreviousAction}
|
||||||
|
* |CTRL-\CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
|
||||||
|
* |<Space>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionSpaceAction}
|
||||||
|
* |!| {@link com.maddyhome.idea.vim.action.change.change.FilterMotionAction}
|
||||||
|
* |!!| translated to !_
|
||||||
|
* |quote| handled by command key parser
|
||||||
|
* |#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordBackwardAction}
|
||||||
|
* |$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction}
|
||||||
|
* |%| {@link com.maddyhome.idea.vim.action.motion.updown.MotionPercentOrMatchAction}
|
||||||
|
* |&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastSearchReplaceAction}
|
||||||
|
* |'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineAction}
|
||||||
|
* |''| ?
|
||||||
|
* ...
|
||||||
|
* |(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousStartAction}
|
||||||
|
* |)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextStartAction}
|
||||||
|
* |star| {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction}
|
||||||
|
* |+| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
|
||||||
|
* |,| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharReverseAction}
|
||||||
|
* |-| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpFirstNonSpaceAction}
|
||||||
|
* |.| {@link com.maddyhome.idea.vim.action.change.RepeatChangeAction}
|
||||||
|
* |/| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction}
|
||||||
|
* |:| {@link com.maddyhome.idea.vim.action.ex.ExEntryAction}
|
||||||
|
* |;| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharAction}
|
||||||
|
* |<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftMotionAction}
|
||||||
|
* |<<| translated to <_
|
||||||
|
* |=| {@link com.maddyhome.idea.vim.action.change.shift.AutoIndentMotionAction}
|
||||||
|
* |==| translated to =_
|
||||||
|
* |>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightMotionAction}
|
||||||
|
* |>>| translated to >_
|
||||||
|
* |?| {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction}
|
||||||
|
* |@| {@link com.maddyhome.idea.vim.action.macro.PlaybackRegisterAction}
|
||||||
|
* |A| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterLineEndAction}
|
||||||
|
* |B| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordLeftAction}
|
||||||
|
* |C| {@link com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction}
|
||||||
|
* |D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteEndOfLineAction}
|
||||||
|
* |E| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndRightAction}
|
||||||
|
* |F| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftMatchCharAction}
|
||||||
|
* |G| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastAction}
|
||||||
|
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionFirstScreenLineAction}
|
||||||
|
* |H| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingFirstScreenLineAction}
|
||||||
|
* |I| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeFirstNonBlankAction}
|
||||||
|
* |J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction}
|
||||||
|
* |K| {@link com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc}
|
||||||
|
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionLastScreenLineAction}
|
||||||
|
* |L| {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingLastScreenLineAction}
|
||||||
|
* |M| {@link com.maddyhome.idea.vim.action.motion.screen.MotionMiddleScreenLineAction}
|
||||||
|
* |N| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainPreviousAction}
|
||||||
|
* |O| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineAboveAction}
|
||||||
|
* |P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorAction}
|
||||||
|
* |Q| TO BE IMPLEMENTED
|
||||||
|
* |R| {@link com.maddyhome.idea.vim.action.change.change.ChangeReplaceAction}
|
||||||
|
* |S| {@link com.maddyhome.idea.vim.action.change.change.ChangeLineAction}
|
||||||
|
* |T| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftTillMatchCharAction}
|
||||||
|
* |U| ?
|
||||||
|
* |V| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleLineModeAction}
|
||||||
|
* |W| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordRightAction}
|
||||||
|
* |X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterLeftAction}
|
||||||
|
* |Y| {@link com.maddyhome.idea.vim.action.copy.YankLineAction}
|
||||||
|
* |ZZ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
|
||||||
|
* |ZQ| {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
|
||||||
|
* |[| see bracket commands
|
||||||
|
* |]| see bracket commands
|
||||||
|
* |^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstNonSpaceAction}
|
||||||
|
* |_| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction}
|
||||||
|
* |`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkAction}
|
||||||
|
* |``| ?
|
||||||
|
* ...
|
||||||
|
* |0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnAction}
|
||||||
|
* |a| {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterCursorAction}
|
||||||
|
* |b| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
|
||||||
|
* |c| {@link com.maddyhome.idea.vim.action.change.change.ChangeMotionAction}
|
||||||
|
* |cc| translated to c_
|
||||||
|
* |d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteMotionAction}
|
||||||
|
* |dd| translated to d_
|
||||||
|
* |do| TO BE IMPLEMENTED
|
||||||
|
* |dp| TO BE IMPLEMENTED
|
||||||
|
* |e| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndRightAction}
|
||||||
|
* |f| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction}
|
||||||
|
* |g| see commands starting with 'g'
|
||||||
|
* |h| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction}
|
||||||
|
* |i| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
|
||||||
|
* |j| {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownAction}
|
||||||
|
* |k| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpAction}
|
||||||
|
* |l| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction}
|
||||||
|
* |m| {@link com.maddyhome.idea.vim.action.motion.mark.MotionMarkAction}
|
||||||
|
* |n| {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainNextAction}
|
||||||
|
* |o| {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineBelowAction}
|
||||||
|
* |p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorAction}
|
||||||
|
* |q| {@link com.maddyhome.idea.vim.action.macro.ToggleRecordingAction}
|
||||||
|
* |r| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction}
|
||||||
|
* |s| {@link com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction}
|
||||||
|
* |t| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction}
|
||||||
|
* |u| {@link com.maddyhome.idea.vim.action.change.UndoAction}
|
||||||
|
* |v| {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction}
|
||||||
|
* |w| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
|
||||||
|
* |x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterRightAction}
|
||||||
|
* |y| {@link com.maddyhome.idea.vim.action.copy.YankMotionAction}
|
||||||
|
* |yy| translated to y_
|
||||||
|
* |z| see commands starting with 'z'
|
||||||
|
* |{| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphPreviousAction}
|
||||||
|
* |bar| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionColumnAction}
|
||||||
|
* |}| {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphNextAction}
|
||||||
|
* |~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction}
|
||||||
|
* |<C-End>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndAction}
|
||||||
|
* |<C-Home>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
|
||||||
|
* |<C-Left>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
|
||||||
|
* |<C-Right>| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
|
||||||
|
* |<C-Down>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlDownAction}
|
||||||
|
* |<C-Up>| {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlUpAction}
|
||||||
|
* |<Del>| {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction}
|
||||||
|
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
|
||||||
|
* |<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction}
|
||||||
|
* |<F1>| IntelliJ help
|
||||||
|
* |<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction}
|
||||||
|
* |<Insert>| {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
|
||||||
|
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction}
|
||||||
|
* |<PageDown>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
|
||||||
|
* |<PageUp>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
|
||||||
|
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction}
|
||||||
|
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
|
||||||
|
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
|
||||||
|
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
|
||||||
|
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
|
||||||
|
* |<S-Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction}
|
||||||
|
* |<S-End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction}
|
||||||
|
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.1. Text objects
|
||||||
|
*
|
||||||
|
* Text object commands are listed in the visual mode section.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.2. Window commands
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |CTRL-W_+| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_-| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_<| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_=| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_>| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_H| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_J| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_K| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_L| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_P| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_R| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_S| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
|
||||||
|
* |CTRL-W_T| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_W| {@link com.maddyhome.idea.vim.action.window.WindowPrevAction}
|
||||||
|
* |CTRL-W_]| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_^| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W__| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_b| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_c| {@link com.maddyhome.idea.vim.action.window.CloseWindowAction}
|
||||||
|
* |CTRL-W_d| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_f| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-F| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-g]| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-g}| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-gf| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W-gF| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_h| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_i| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_j| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_k| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_l| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
* |CTRL-W_n| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_o| {@link com.maddyhome.idea.vim.action.window.WindowOnlyAction}
|
||||||
|
* |CTRL-W_p| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_q| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_r| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_s| {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
|
||||||
|
* |CTRL-W_t| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_v| {@link com.maddyhome.idea.vim.action.window.VerticalSplitAction}
|
||||||
|
* |CTRL-W_w| {@link com.maddyhome.idea.vim.action.window.WindowNextAction}
|
||||||
|
* |CTRL-W_x| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_z| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_bar| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_}| TO BE IMPLEMENTED
|
||||||
|
* |CTRL-W_<Down>| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_<Up>| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_<Left>| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_<Right>| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
* |CTRL-W_CTRL-H| {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
|
||||||
|
* |CTRL-W_CTRL-J| {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
|
||||||
|
* |CTRL-W_CTRL-K| {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
|
||||||
|
* |CTRL-W_CTRL-L| {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.3. Square bracket commands
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |[_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |[_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |[#| TO BE IMPLEMENTED
|
||||||
|
* |['| TO BE IMPLEMENTED
|
||||||
|
* |[(| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenOpenAction}
|
||||||
|
* |[star| TO BE IMPLEMENTED
|
||||||
|
* |[`| TO BE IMPLEMENTED
|
||||||
|
* |[/| TO BE IMPLEMENTED
|
||||||
|
* |[D| TO BE IMPLEMENTED
|
||||||
|
* |[I| TO BE IMPLEMENTED
|
||||||
|
* |[M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousEndAction}
|
||||||
|
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
|
||||||
|
* |[P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
|
||||||
|
* |[[| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardStartAction}
|
||||||
|
* |[]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardEndAction}
|
||||||
|
* |[c| TO BE IMPLEMENTED
|
||||||
|
* |[d| TO BE IMPLEMENTED
|
||||||
|
* |[f| TO BE IMPLEMENTED
|
||||||
|
* |[i| TO BE IMPLEMENTED
|
||||||
|
* |[m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
|
||||||
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
|
* |[s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
|
||||||
|
* |[z| TO BE IMPLEMENTED
|
||||||
|
* |[{| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
|
||||||
|
* |]_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |]_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |]#| TO BE IMPLEMENTED
|
||||||
|
* |]'| TO BE IMPLEMENTED
|
||||||
|
* |])| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenCloseAction}
|
||||||
|
* |]star| TO BE IMPLEMENTED
|
||||||
|
* |]`| TO BE IMPLEMENTED
|
||||||
|
* |]/| TO BE IMPLEMENTED
|
||||||
|
* |]D| TO BE IMPLEMENTED
|
||||||
|
* |]I| TO BE IMPLEMENTED
|
||||||
|
* |]M| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction}
|
||||||
|
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
|
||||||
|
* |]P| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
|
||||||
|
* |][| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardEndAction}
|
||||||
|
* |]]| {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardStartAction}
|
||||||
|
* |]c| TO BE IMPLEMENTED
|
||||||
|
* |]d| TO BE IMPLEMENTED
|
||||||
|
* |]f| TO BE IMPLEMENTED
|
||||||
|
* |]i| TO BE IMPLEMENTED
|
||||||
|
* |]m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
|
||||||
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
|
* |]s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
|
||||||
|
* |]z| TO BE IMPLEMENTED
|
||||||
|
* |]}| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.4. Commands starting with 'g'
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |g_CTRL-A| not applicable
|
||||||
|
* |g_CTRL-G| {@link com.maddyhome.idea.vim.action.file.FileGetLocationInfoAction}
|
||||||
|
* |g_CTRL-H| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableBlockModeAction}
|
||||||
|
* |g_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |g#| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordBackwardAction}
|
||||||
|
* |g$| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
|
||||||
|
* |g&| {@link com.maddyhome.idea.vim.action.change.change.ChangeLastGlobalSearchReplaceAction}
|
||||||
|
* |v_g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineNoSaveJumpAction}
|
||||||
|
* |g'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineNoSaveJumpAction}
|
||||||
|
* |g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkNoSaveJumpAction}
|
||||||
|
* |gstar| {@link com.maddyhome.idea.vim.action.motion.search.SearchWordForwardAction}
|
||||||
|
* |g+| TO BE IMPLEMENTED
|
||||||
|
* |g,| TO BE IMPLEMENTED
|
||||||
|
* |g-| TO BE IMPLEMENTED
|
||||||
|
* |g0| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
|
||||||
|
* |g8| {@link com.maddyhome.idea.vim.action.file.FileGetHexAction}
|
||||||
|
* |g;| TO BE IMPLEMENTED
|
||||||
|
* |g<| TO BE IMPLEMENTED
|
||||||
|
* |g?| TO BE IMPLEMENTED
|
||||||
|
* |g?g?| TO BE IMPLEMENTED
|
||||||
|
* |gD| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |gE| {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndLeftAction}
|
||||||
|
* |gF| TO BE IMPLEMENTED
|
||||||
|
* |gH| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableLineModeAction}
|
||||||
|
* |gI| {@link com.maddyhome.idea.vim.action.change.insert.InsertLineStartAction}
|
||||||
|
* |gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction}
|
||||||
|
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch}
|
||||||
|
* |gN| {@link com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject}
|
||||||
|
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorMoveCursorAction}
|
||||||
|
* |gP| {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorActionMoveCursor}
|
||||||
|
* |gQ| TO BE IMPLEMENTED
|
||||||
|
* |gR| TO BE IMPLEMENTED
|
||||||
|
* |gT| {@link com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction}
|
||||||
|
* |gU| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction}
|
||||||
|
* |gV| TO BE IMPLEMENTED
|
||||||
|
* |g]| TO BE IMPLEMENTED
|
||||||
|
* |g^| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenNonSpaceAction}
|
||||||
|
* |g_| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastNonSpaceAction}
|
||||||
|
* |ga| {@link com.maddyhome.idea.vim.action.file.FileGetAsciiAction}
|
||||||
|
* |gd| {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
|
||||||
|
* |ge| {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndLeftAction}
|
||||||
|
* |gf| TO BE IMPLEMENTED
|
||||||
|
* |gg| {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
|
||||||
|
* |gh| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableCharacterModeAction}
|
||||||
|
* |gi| {@link com.maddyhome.idea.vim.action.change.insert.InsertAtPreviousInsertAction}
|
||||||
|
* |gj| TO BE IMPLEMENTED
|
||||||
|
* |gk| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
|
||||||
|
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch}
|
||||||
|
* |gn| {@link com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject}
|
||||||
|
* |gm| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionMiddleColumnAction}
|
||||||
|
* |go| {@link com.maddyhome.idea.vim.action.motion.text.MotionNthCharacterAction}
|
||||||
|
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorMoveCursorAction}
|
||||||
|
* |gp| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorActionMoveCursor}
|
||||||
|
* |gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeMotionAction}
|
||||||
|
* |gr| TO BE IMPLEMENTED
|
||||||
|
* |gs| TO BE IMPLEMENTED
|
||||||
|
* |gt| {@link com.maddyhome.idea.vim.action.window.tabs.NextTabAction}
|
||||||
|
* |gu| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction}
|
||||||
|
* |gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSelectPreviousAction}
|
||||||
|
* |gw| TO BE IMPLEMENTED
|
||||||
|
* |g@| {@link com.maddyhome.idea.vim.action.change.OperatorAction}
|
||||||
|
* |g~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction}
|
||||||
|
* |g<Down>| TO BE IMPLEMENTED
|
||||||
|
* |g<End>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
|
||||||
|
* |g<Home>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
|
||||||
|
* |g<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2.5. Commands starting with 'z'
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |z<CR>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineStartAction}
|
||||||
|
* |z+| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLinePageStartAction}
|
||||||
|
* |z-| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineStartAction}
|
||||||
|
* |z.| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineStartAction}
|
||||||
|
* |z=| TO BE IMPLEMENTED
|
||||||
|
* |zA| TO BE IMPLEMENTED
|
||||||
|
* |zC| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegionRecursively}
|
||||||
|
* |zD| TO BE IMPLEMENTED
|
||||||
|
* |zE| TO BE IMPLEMENTED
|
||||||
|
* |zF| TO BE IMPLEMENTED
|
||||||
|
* |zG| TO BE IMPLEMENTED
|
||||||
|
* |zH| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction}
|
||||||
|
* |zL| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction}
|
||||||
|
* |zM| {@link com.maddyhome.idea.vim.action.fold.VimCollapseAllRegions}
|
||||||
|
* |zN| TO BE IMPLEMENTED
|
||||||
|
* |zO| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegionRecursively}
|
||||||
|
* |zR| {@link com.maddyhome.idea.vim.action.fold.VimExpandAllRegions}
|
||||||
|
* |zW| TO BE IMPLEMENTED
|
||||||
|
* |zX| TO BE IMPLEMENTED
|
||||||
|
* |z^| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLinePageStartAction}
|
||||||
|
* |za| TO BE IMPLEMENTED
|
||||||
|
* |zb| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineAction}
|
||||||
|
* |zc| {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegion}
|
||||||
|
* |zd| not applicable
|
||||||
|
* |ze| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenColumnAction}
|
||||||
|
* |zf| not applicable
|
||||||
|
* |zg| TO BE IMPLEMENTED
|
||||||
|
* |zh| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
|
||||||
|
* |zi| TO BE IMPLEMENTED
|
||||||
|
* |zj| TO BE IMPLEMENTED
|
||||||
|
* |zk| TO BE IMPLEMENTED
|
||||||
|
* |zl| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
|
||||||
|
* |zm| TO BE IMPLEMENTED
|
||||||
|
* |zn| TO BE IMPLEMENTED
|
||||||
|
* |zo| {@link com.maddyhome.idea.vim.action.fold.VimExpandRegion}
|
||||||
|
* |zr| TO BE IMPLEMENTED
|
||||||
|
* |zs| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenColumnAction}
|
||||||
|
* |zt| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineAction}
|
||||||
|
* |zv| TO BE IMPLEMENTED
|
||||||
|
* |zw| TO BE IMPLEMENTED
|
||||||
|
* |zx| TO BE IMPLEMENTED
|
||||||
|
* |zz| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineAction}
|
||||||
|
* |z<Left>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
|
||||||
|
* |z<Right>| {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 3. Visual mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |v_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |v_CTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberIncAction}
|
||||||
|
* |v_CTRL-C| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-G| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
|
||||||
|
* |v_<BS>| NVO mapping
|
||||||
|
* |v_CTRL-H| NVO mapping
|
||||||
|
* |v_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |v_CTRL-V| NVO mapping
|
||||||
|
* |v_<Esc>| {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
|
||||||
|
* |v_CTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberDecAction}
|
||||||
|
* |v_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |v_!| {@link com.maddyhome.idea.vim.action.change.change.FilterVisualLinesAction}
|
||||||
|
* |v_:| NVO mapping
|
||||||
|
* |v_<| {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftVisualAction}
|
||||||
|
* |v_=| {@link com.maddyhome.idea.vim.action.change.change.AutoIndentLinesVisualAction}
|
||||||
|
* |v_>| {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightVisualAction}
|
||||||
|
* |v_b_A| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction}
|
||||||
|
* |v_C| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesEndAction}
|
||||||
|
* |v_D| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesEndAction}
|
||||||
|
* |v_b_I| {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction}
|
||||||
|
* |v_J| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction}
|
||||||
|
* |v_K| TO BE IMPLEMENTED
|
||||||
|
* |v_O| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsBlockAction}
|
||||||
|
* |v_P| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorAction}
|
||||||
|
* |v_R| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
|
||||||
|
* |v_S| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
|
||||||
|
* |v_U| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction}
|
||||||
|
* |v_V| NV mapping
|
||||||
|
* |v_X| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesAction}
|
||||||
|
* |v_Y| {@link com.maddyhome.idea.vim.action.copy.YankVisualLinesAction}
|
||||||
|
* |v_aquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockDoubleQuoteAction}
|
||||||
|
* |v_a'| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockSingleQuoteAction}
|
||||||
|
* |v_a(| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_a)| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_a<| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
|
||||||
|
* |v_a>| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
|
||||||
|
* |v_aB| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_aW| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction}
|
||||||
|
* |v_a[| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
|
||||||
|
* |v_a]| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
|
||||||
|
* |v_a`| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBackQuoteAction}
|
||||||
|
* |v_ab| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
|
||||||
|
* |v_ap| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterParagraphAction}
|
||||||
|
* |v_as| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterSentenceAction}
|
||||||
|
* |v_at| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockTagAction}
|
||||||
|
* |v_aw| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction}
|
||||||
|
* |v_a{| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_a}| {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
|
||||||
|
* |v_c| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
|
||||||
|
* |v_d| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
|
||||||
|
* |v_gCTRL-A| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheIncAction}
|
||||||
|
* |v_gCTRL-X| {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheDecAction}
|
||||||
|
* |v_gJ| {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction}
|
||||||
|
* |v_gq| {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeVisualAction}
|
||||||
|
* |v_gv| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapSelectionsAction}
|
||||||
|
* |v_g`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkNoSaveJumpAction}
|
||||||
|
* |v_g@| {@link com.maddyhome.idea.vim.action.change.VisualOperatorAction}
|
||||||
|
* |v_iquote| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockDoubleQuoteAction}
|
||||||
|
* |v_i'| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockSingleQuoteAction}
|
||||||
|
* |v_i(| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_i)| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_i<| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
|
||||||
|
* |v_i>| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
|
||||||
|
* |v_iB| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_iW| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBigWordAction}
|
||||||
|
* |v_i[| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
|
||||||
|
* |v_i]| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
|
||||||
|
* |v_i`| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBackQuoteAction}
|
||||||
|
* |v_ib| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
|
||||||
|
* |v_ip| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerParagraphAction}
|
||||||
|
* |v_is| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerSentenceAction}
|
||||||
|
* |v_it| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockTagAction}
|
||||||
|
* |v_iw| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerWordAction}
|
||||||
|
* |v_i{| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_i}| {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
|
||||||
|
* |v_o| {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsAction}
|
||||||
|
* |v_p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorAction}
|
||||||
|
* |v_r| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction}
|
||||||
|
* |v_s| {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
|
||||||
|
* |v_u| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction}
|
||||||
|
* |v_v| NV mapping
|
||||||
|
* |v_x| {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
|
||||||
|
* |v_y| {@link com.maddyhome.idea.vim.action.copy.YankVisualAction}
|
||||||
|
* |v_~| {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction}
|
||||||
|
* |v_`| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkAction}
|
||||||
|
* |v_'| {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 4. Select mode
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |<BS>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
|
||||||
|
* |<CR>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEnterAction}
|
||||||
|
* |<DEL>| {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
|
||||||
|
* |<ESC>| {@link com.maddyhome.idea.vim.action.motion.select.SelectEscapeAction}
|
||||||
|
* |<C-G>| {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
|
||||||
|
* |<S-Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
|
||||||
|
* |<S-Left>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
|
||||||
|
* |<S-Right>| {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
|
||||||
|
* |<S-Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
|
||||||
|
* |<Down>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
|
||||||
|
* |<Left>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction}
|
||||||
|
* |<Right>| {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction}
|
||||||
|
* |<Up>| {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
|
||||||
|
*
|
||||||
|
* 5. Command line editing
|
||||||
|
*
|
||||||
|
* tag action
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |c_CTRL-A| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-B| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
|
||||||
|
* |c_CTRL-C| {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
|
||||||
|
* |c_CTRL-D| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-E| {@link javax.swing.text.DefaultEditorKit#endLineAction}
|
||||||
|
* |c_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-H| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
|
||||||
|
* |c_CTRL-I| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-J| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_CTRL-K| Handled by KeyHandler
|
||||||
|
* |c_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-M| {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
|
||||||
|
* |c_CTRL-N| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_CTRL-P| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_CTRL-Q| Handled by KeyHandler
|
||||||
|
* |c_CTRL-R_CTRL-A| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-F| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-L| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-O| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-P| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-R| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-R_CTRL-W| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-T| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-U| {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
|
||||||
|
* |c_CTRL-V| Handled by KeyHandler
|
||||||
|
* |c_CTRL-W| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
|
||||||
|
* |c_CTRL-Y| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_e| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-\_CTRL-N| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-_| not applicable
|
||||||
|
* |c_CTRL-^| not applicable
|
||||||
|
* |c_CTRL-]| TO BE IMPLEMENTED
|
||||||
|
* |c_CTRL-[| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
|
||||||
|
* |c_<BS>| {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
|
||||||
|
* |c_<CR>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_<C-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
|
||||||
|
* |c_<C-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
|
||||||
|
* |c_<Del>| {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
|
||||||
|
* |c_<Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
|
||||||
|
* |c_<End>| {@link javax.swing.text.DefaultEditorKit#endLineAction}
|
||||||
|
* |c_<Esc>| {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
|
||||||
|
* |c_<Home>| {@link javax.swing.text.DefaultEditorKit#beginLineAction}
|
||||||
|
* |c_<Insert>| {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
|
||||||
|
* |c_<Left>| {@link javax.swing.text.DefaultEditorKit#backwardAction}
|
||||||
|
* |c_<LeftMouse>| not applicable
|
||||||
|
* |c_<MiddleMouse>| TO BE IMPLEMENTED
|
||||||
|
* |c_<NL>| {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
|
||||||
|
* |c_<PageUp>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_<PageDown>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_<Right>| {@link javax.swing.text.DefaultEditorKit#forwardAction}
|
||||||
|
* |c_<S-Down>| {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
|
||||||
|
* |c_<S-Left>| {@link javax.swing.text.DefaultEditorKit#previousWordAction}
|
||||||
|
* |c_<S-Right>| {@link javax.swing.text.DefaultEditorKit#nextWordAction}
|
||||||
|
* |c_<S-Tab>| TO BE IMPLEMENTED
|
||||||
|
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
|
||||||
|
* |c_<Tab>| TO BE IMPLEMENTED
|
||||||
|
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
|
||||||
|
* |c_digraph| {char1} <BS> {char2}
|
||||||
|
* |c_wildchar| TO BE IMPLEMENTED
|
||||||
|
* |'cedit'| TO BE IMPLEMENTED
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 6. Ex commands
|
||||||
|
*
|
||||||
|
* tag handler
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* |:map| {@link com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand}
|
||||||
|
* |:nmap| ...
|
||||||
|
* |:vmap| ...
|
||||||
|
* |:omap| ...
|
||||||
|
* |:imap| ...
|
||||||
|
* |:cmap| ...
|
||||||
|
* |:noremap| ...
|
||||||
|
* |:nnoremap| ...
|
||||||
|
* |:vnoremap| ...
|
||||||
|
* |:onoremap| ...
|
||||||
|
* |:inoremap| ...
|
||||||
|
* |:cnoremap| ...
|
||||||
|
* |:shell| {@link com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand}
|
||||||
|
* |:sort| {@link com.maddyhome.idea.vim.vimscript.model.commands.SortCommand}
|
||||||
|
* |:source| {@link com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand}
|
||||||
|
* |:qall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:quitall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:wqall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:xall| {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
|
||||||
|
* |:command| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand}
|
||||||
|
* |:delcommand| {@link com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand}
|
||||||
|
* |:comclear| {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand}
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* The list of supported Ex commands is incomplete.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* A. Misc commands
|
||||||
|
*
|
||||||
|
* tag handler
|
||||||
|
* -------------------------------------------------------------------------------------------------------------------
|
||||||
|
* |]b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndLeftAction}
|
||||||
|
* |]w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndRightAction}
|
||||||
|
* |[b| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelLeftAction}
|
||||||
|
* |[w| {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelRightAction}
|
||||||
|
* |g(| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousEndAction}
|
||||||
|
* |g)| {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextEndAction}
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See also :help index.
|
||||||
|
*
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
package com.maddyhome.idea.vim;
|
@@ -32,9 +32,9 @@ internal class Troubleshooter {
|
|||||||
fun findIncorrectMappings(): List<Problem> {
|
fun findIncorrectMappings(): List<Problem> {
|
||||||
val problems = ArrayList<Problem>()
|
val problems = ArrayList<Problem>()
|
||||||
MappingMode.entries.forEach { mode ->
|
MappingMode.entries.forEach { mode ->
|
||||||
injector.keyGroup.getKeyMapping(mode).getAllByOwner(MappingOwner.IdeaVim.InitScript).forEach { entry ->
|
injector.keyGroup.getKeyMapping(mode).getByOwner(MappingOwner.IdeaVim.InitScript).forEach { (_, to) ->
|
||||||
(entry.mappingInfo as? ToKeysMappingInfo)?.let { mappingInfo ->
|
if (to is ToKeysMappingInfo) {
|
||||||
if (":action" in mappingInfo.toKeys.joinToString { it.keyChar.toString() }) {
|
if (":action" in to.toKeys.joinToString { it.keyChar.toString() }) {
|
||||||
problems += Problem("Mappings contain `:action` call")
|
problems += Problem("Mappings contain `:action` call")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -192,13 +192,6 @@ private object VimActionsPopup {
|
|||||||
null,
|
null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
actionGroup.add(
|
|
||||||
HelpLink(
|
|
||||||
"Take Survey ↗",
|
|
||||||
"https://surveys.jetbrains.com/s3/ideavim-usage-survey",
|
|
||||||
AllIcons.Actions.IntentionBulb,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
actionGroup.addSeparator(MessageHelper.message("action.eap.choice.active.text"))
|
actionGroup.addSeparator(MessageHelper.message("action.eap.choice.active.text"))
|
||||||
|
|
||||||
actionGroup.add(JoinEap)
|
actionGroup.add(JoinEap)
|
||||||
|
263
src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
Normal file
263
src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.maddyhome.idea.vim.ui.ex
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.logger
|
||||||
|
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
|
||||||
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
|
import com.maddyhome.idea.vim.api.LocalOptionInitialisationScenario
|
||||||
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import java.awt.event.ActionEvent
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
import javax.swing.Action
|
||||||
|
import javax.swing.KeyStroke
|
||||||
|
import javax.swing.text.BadLocationException
|
||||||
|
import javax.swing.text.DefaultEditorKit
|
||||||
|
import javax.swing.text.Document
|
||||||
|
import javax.swing.text.TextAction
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal interface MultiStepAction : Action {
|
||||||
|
fun reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryUpAction : TextAction(ExEditorKit.HistoryUp) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(true, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryDownAction : TextAction(ExEditorKit.HistoryDown) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryUpFilterAction : TextAction(ExEditorKit.HistoryUpFilter) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class HistoryDownFilterAction : TextAction(ExEditorKit.HistoryDownFilter) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
val target = getTextComponent(actionEvent) as ExTextField
|
||||||
|
target.selectHistory(false, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class CompleteEntryAction : TextAction(ExEditorKit.CompleteEntry) {
|
||||||
|
override fun actionPerformed(actionEvent: ActionEvent) {
|
||||||
|
logger.debug("complete entry")
|
||||||
|
val stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
|
||||||
|
|
||||||
|
// We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
|
||||||
|
// We do this for a couple of reasons:
|
||||||
|
// * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
|
||||||
|
// write action
|
||||||
|
// * The key handler routines get the chance to clean up and reset state
|
||||||
|
val entry = ExEntryPanel.getInstance().entry
|
||||||
|
val keyHandler = KeyHandler.getInstance()
|
||||||
|
keyHandler.handleKey(entry.editor!!.vim, stroke, entry.context.vim, keyHandler.keyHandlerState)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<CompleteEntryAction>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class CancelEntryAction : TextAction(ExEditorKit.CancelEntry) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class EscapeCharAction : TextAction(ExEditorKit.EscapeChar) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.escape()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal abstract class DeleteCharAction internal constructor(name: String?) : TextAction(name) {
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deleteSelection(doc: Document, dot: Int, mark: Int): Boolean {
|
||||||
|
if (dot != mark) {
|
||||||
|
doc.remove(min(dot, mark), abs(dot - mark))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deleteNextChar(doc: Document, dot: Int): Boolean {
|
||||||
|
if (dot < doc.length) {
|
||||||
|
var delChars = 1
|
||||||
|
if (dot < doc.length - 1) {
|
||||||
|
val dotChars = doc.getText(dot, 2)
|
||||||
|
val c0 = dotChars[0]
|
||||||
|
val c1 = dotChars[1]
|
||||||
|
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
|
||||||
|
delChars = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc.remove(dot, delChars)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.Throws(BadLocationException::class)
|
||||||
|
fun deletePrevChar(doc: Document, dot: Int): Boolean {
|
||||||
|
if (dot > 0) {
|
||||||
|
var delChars = 1
|
||||||
|
if (dot > 1) {
|
||||||
|
val dotChars = doc.getText(dot - 2, 2)
|
||||||
|
val c0 = dotChars[0]
|
||||||
|
val c1 = dotChars[1]
|
||||||
|
if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
|
||||||
|
delChars = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc.remove(dot - delChars, delChars)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeleteNextCharAction : DeleteCharAction(DefaultEditorKit.deleteNextCharAction) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
try {
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val dot = caret.dot
|
||||||
|
val mark = caret.mark
|
||||||
|
if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeletePreviousCharAction : DeleteCharAction(DefaultEditorKit.deletePrevCharAction) {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
try {
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val dot = caret.dot
|
||||||
|
val mark = caret.mark
|
||||||
|
if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
|
||||||
|
if (dot == 0 && doc.length == 0) {
|
||||||
|
target.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (bl: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeletePreviousWordAction : TextAction(DefaultEditorKit.deletePrevWordAction) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
val project = target.editor!!.project
|
||||||
|
|
||||||
|
// Create a VimEditor instance on the Swing text field which we can pass to the search helpers. We need an editor
|
||||||
|
// rather than just working on a buffer because the search helpers need local options (specifically the local to
|
||||||
|
// buffer 'iskeyword'). We use the CMD_LINE scenario to initialise local options from the main editor. The options
|
||||||
|
// service will copy all local-to-buffer and local-to-window options, effectively cloning the options.
|
||||||
|
// TODO: Over time, we should migrate all ex actions to be based on VimEditor
|
||||||
|
// This will mean we always have an editor that has been initialised for options, etc. But also means that we can
|
||||||
|
// share the command line entry actions between IdeaVim implementations
|
||||||
|
val editor = TextComponentEditorImpl(project, target).vim
|
||||||
|
injector.optionGroup.initialiseLocalOptions(editor, target.editor!!.vim, LocalOptionInitialisationScenario.CMD_LINE)
|
||||||
|
|
||||||
|
val offset = injector.searchHelper.findNextWord(editor, caret.dot, -1, bigWord = false, spaceWords = false)
|
||||||
|
if (logger.isDebugEnabled) logger.debug("offset=$offset")
|
||||||
|
try {
|
||||||
|
val pos = caret.dot
|
||||||
|
doc.remove(offset, pos - offset)
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<DeletePreviousWordAction>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class DeleteToCursorAction : TextAction(ExEditorKit.DeleteToCursor) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.saveLastEntry()
|
||||||
|
val doc = target.document
|
||||||
|
val caret = target.caret
|
||||||
|
try {
|
||||||
|
doc.remove(0, caret.dot)
|
||||||
|
} catch (ex: BadLocationException) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
|
internal class ToggleInsertReplaceAction : TextAction(ExEditorKit.ToggleInsertReplace) {
|
||||||
|
/**
|
||||||
|
* Invoked when an action occurs.
|
||||||
|
*/
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
logger.debug("actionPerformed")
|
||||||
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
target.toggleInsertReplace()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
logger.debug("ToggleInsertReplaceAction()")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = logger<ToggleInsertReplaceAction>()
|
||||||
|
}
|
||||||
|
}
|
@@ -34,7 +34,7 @@ public class ExDocument extends PlainDocument {
|
|||||||
void toggleInsertReplace() {
|
void toggleInsertReplace() {
|
||||||
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
|
||||||
if (commandLine != null) {
|
if (commandLine != null) {
|
||||||
((ExEntryPanel) commandLine).isReplaceMode = !((ExEntryPanel)commandLine).isReplaceMode;
|
commandLine.toggleReplaceMode();
|
||||||
}
|
}
|
||||||
overwrite = !overwrite;
|
overwrite = !overwrite;
|
||||||
}
|
}
|
||||||
|
@@ -7,18 +7,58 @@
|
|||||||
*/
|
*/
|
||||||
package com.maddyhome.idea.vim.ui.ex
|
package com.maddyhome.idea.vim.ui.ex
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.debug
|
||||||
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
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
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
|
import javax.swing.Action
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
import javax.swing.text.DefaultEditorKit
|
import javax.swing.text.DefaultEditorKit
|
||||||
import javax.swing.text.Document
|
import javax.swing.text.Document
|
||||||
|
import javax.swing.text.TextAction
|
||||||
|
|
||||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
|
||||||
internal object ExEditorKit : DefaultEditorKit() {
|
internal object ExEditorKit : DefaultEditorKit() {
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val CancelEntry: String = "cancel-entry"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val CompleteEntry: String = "complete-entry"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val EscapeChar: String = "escape"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val DeleteToCursor: String = "delete-to-cursor"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val ToggleInsertReplace: String = "toggle-insert"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryUp: String = "history-up"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryDown: String = "history-down"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryUpFilter: String = "history-up-filter"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val HistoryDownFilter: String = "history-down-filter"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val StartDigraph: String = "start-digraph"
|
||||||
|
|
||||||
|
@NonNls
|
||||||
|
val StartLiteral: String = "start-literal"
|
||||||
|
|
||||||
|
private val logger = logger<ExEditorKit>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the MIME type of the data that this
|
* Gets the MIME type of the data that this
|
||||||
* kit represents support for.
|
* kit represents support for.
|
||||||
@@ -30,6 +70,19 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
return "text/ideavim"
|
return "text/ideavim"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the set of commands that can be used
|
||||||
|
* on a text component that is using a model and
|
||||||
|
* view produced by this kit.
|
||||||
|
*
|
||||||
|
* @return the set of actions
|
||||||
|
*/
|
||||||
|
override fun getActions(): Array<Action> {
|
||||||
|
val res = TextAction.augmentList(super.getActions(), exActions)
|
||||||
|
logger.debug { "res.length=${res.size}" }
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an uninitialized text storage model
|
* Creates an uninitialized text storage model
|
||||||
* that is appropriate for this type of editor.
|
* that is appropriate for this type of editor.
|
||||||
@@ -40,10 +93,28 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
return ExDocument()
|
return ExDocument()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val exActions = arrayOf<Action>(
|
||||||
|
CancelEntryAction(),
|
||||||
|
CompleteEntryAction(),
|
||||||
|
EscapeCharAction(),
|
||||||
|
DeleteNextCharAction(),
|
||||||
|
DeletePreviousCharAction(),
|
||||||
|
DeletePreviousWordAction(),
|
||||||
|
DeleteToCursorAction(),
|
||||||
|
HistoryUpAction(),
|
||||||
|
HistoryDownAction(),
|
||||||
|
HistoryUpFilterAction(),
|
||||||
|
HistoryDownFilterAction(),
|
||||||
|
ToggleInsertReplaceAction(),
|
||||||
|
)
|
||||||
|
|
||||||
class DefaultExKeyHandler : DefaultKeyTypedAction() {
|
class DefaultExKeyHandler : DefaultKeyTypedAction() {
|
||||||
override fun actionPerformed(e: ActionEvent) {
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
val target = getTextComponent(e) as ExTextField
|
val target = getTextComponent(e) as ExTextField
|
||||||
|
val currentAction = target.currentAction
|
||||||
|
if (currentAction != null) {
|
||||||
|
currentAction.actionPerformed(e)
|
||||||
|
} else {
|
||||||
val key = convert(e)
|
val key = convert(e)
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
val c = key.keyChar
|
val c = key.keyChar
|
||||||
@@ -66,6 +137,7 @@ internal object ExEditorKit : DefaultEditorKit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun convert(event: ActionEvent): KeyStroke? {
|
fun convert(event: ActionEvent): KeyStroke? {
|
||||||
val cmd = event.actionCommand
|
val cmd = event.actionCommand
|
||||||
|
@@ -23,10 +23,7 @@ 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.VimEditor;
|
|
||||||
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;
|
||||||
@@ -63,7 +60,7 @@ import static com.maddyhome.idea.vim.group.KeyGroup.toShortcutSet;
|
|||||||
public class ExEntryPanel extends JPanel implements VimCommandLine {
|
public class ExEntryPanel extends JPanel implements VimCommandLine {
|
||||||
public static ExEntryPanel instance;
|
public static ExEntryPanel instance;
|
||||||
public static ExEntryPanel instanceWithoutShortcuts;
|
public static ExEntryPanel instanceWithoutShortcuts;
|
||||||
public boolean isReplaceMode = false;
|
private boolean isReplaceMode = false;
|
||||||
private WeakReference<Editor> weakEditor = null;
|
private WeakReference<Editor> weakEditor = null;
|
||||||
|
|
||||||
private VimInputInterceptor myInputInterceptor = null;
|
private VimInputInterceptor myInputInterceptor = null;
|
||||||
@@ -344,14 +341,14 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a snapshot of the count for the in progress command, and coerce it to 1. This value will include all
|
// Get the current count from the command builder. This value is coerced to at least 1, so will always be valid.
|
||||||
// count components - selecting register(s), operator and motions. E.g. `2"a3"b4"c5d6/` will return 720.
|
// The aggregated value includes any counts for operator and register selections, and the uncommitted count for
|
||||||
// If we're showing highlights for an Ex command like `:s`, the command builder will be empty, but we'll still
|
// the search command (`/` or `?`). E.g., `2"a3"b4"c5d6/` would return 720.
|
||||||
// get a valid value.
|
// If we're showing highlights for an ex command like `:s`, there won't be a command, but the value is already
|
||||||
int count1 = Math.max(1, KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder()
|
// coerced to at least 1.
|
||||||
.calculateCount0Snapshot());
|
int count1 = KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder().getAggregatedUncommittedCount();
|
||||||
|
|
||||||
if ((labelText.equals("/") || labelText.equals("?") || searchCommand) && !injector.getMacro().isExecutingMacro()) {
|
if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
|
||||||
final boolean forwards = !labelText.equals("?"); // :s, :g, :v are treated as forwards
|
final boolean forwards = !labelText.equals("?"); // :s, :g, :v are treated as forwards
|
||||||
int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
|
||||||
final String pattern = searchText.substring(0, pattenEnd);
|
final String pattern = searchText.substring(0, pattenEnd);
|
||||||
@@ -405,7 +402,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toggleReplaceMode() {
|
public void toggleReplaceMode() {
|
||||||
entry.toggleInsertReplace();
|
isReplaceMode = !isReplaceMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -531,17 +528,17 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getInstance(ExEntryPanel.class.getName());
|
private static final Logger logger = Logger.getInstance(ExEntryPanel.class.getName());
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public @NotNull VimCommandLineCaret getCaret() {
|
public VimCommandLineCaret getCaret() {
|
||||||
return (VimCommandLineCaret) entry.getCaret();
|
return (VimCommandLineCaret) entry.getCaret();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setText(@NotNull String string, boolean updateLastEntry) {
|
public void setText(@NotNull String string) {
|
||||||
// It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
|
// It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
|
||||||
int offset = getCaret().getOffset();
|
int offset = getCaret().getOffset();
|
||||||
entry.updateText(string);
|
entry.updateText(string);
|
||||||
if (updateLastEntry) entry.saveLastEntry();
|
|
||||||
getCaret().setOffset(Math.min(offset, getVisibleText().length()));
|
getCaret().setOffset(Math.min(offset, getVisibleText().length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,8 +547,9 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
entry.clearCurrentAction();
|
entry.clearCurrentAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Integer getPromptCharacterOffset() {
|
public Integer getPromptCharacterOffset() {
|
||||||
int offset = entry.currentActionPromptCharacterOffset;
|
int offset = entry.currentActionPromptCharacterOffset;
|
||||||
return offset == -1 ? null : offset;
|
return offset == -1 ? null : offset;
|
||||||
}
|
}
|
||||||
@@ -571,7 +569,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
IdeFocusManager.findInstance().requestFocus(entry, true);
|
IdeFocusManager.findInstance().requestFocus(entry, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable VimInputInterceptor<?> getInputInterceptor() {
|
@Nullable
|
||||||
|
public VimInputInterceptor<?> getInputInterceptor() {
|
||||||
return myInputInterceptor;
|
return myInputInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,37 +583,18 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
|
|||||||
myInputInterceptor = vimInputInterceptor;
|
myInputInterceptor = vimInputInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Function1<String, Unit> getInputProcessing() {
|
public Function1<String, Unit> getInputProcessing() {
|
||||||
return inputProcessing;
|
return inputProcessing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Character getFinishOn() {
|
public Character getFinishOn() {
|
||||||
return finishOn;
|
return finishOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHistIndex() {
|
|
||||||
return entry.histIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHistIndex(int i) {
|
|
||||||
entry.histIndex = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getLastEntry() {
|
|
||||||
return entry.lastEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLastEntry(@NotNull String s) {
|
|
||||||
entry.lastEntry = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LafListener implements LafManagerListener {
|
public static class LafListener implements LafManagerListener {
|
||||||
@Override
|
@Override
|
||||||
public void lookAndFeelChanged(@NotNull LafManager source) {
|
public void lookAndFeelChanged(@NotNull LafManager source) {
|
||||||
|
@@ -21,6 +21,57 @@ internal object ExKeyBindings {
|
|||||||
|
|
||||||
val bindings: Array<KeyBinding> by lazy {
|
val bindings: Array<KeyBinding> by lazy {
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
// Escape will cancel a pending insert digraph/register before cancelling
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ExEditorKit.EscapeChar),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.EscapeChar),
|
||||||
|
|
||||||
|
// Cancel entry, ignoring any pending actions such as digraph/registry entry
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CancelEntry),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ExEditorKit.CompleteEntry),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x02.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), DefaultEditorKit.beginLineAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x05.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), DefaultEditorKit.endLineAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(0x08.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DefaultEditorKit.deleteNextCharAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevWordAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.DeleteToCursor),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ExEditorKit.HistoryUpFilter),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryUp),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ExEditorKit.HistoryDownFilter),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryDown),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ExEditorKit.HistoryDown),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryDown),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), ExEditorKit.ToggleInsertReplace),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.previousWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.previousWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), DefaultEditorKit.forwardAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.nextWordAction),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.nextWordAction),
|
||||||
|
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartDigraph),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
|
||||||
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
|
||||||
|
|
||||||
// These appear to be non-Vim shortcuts
|
// These appear to be non-Vim shortcuts
|
||||||
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
|
||||||
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
|
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
|
||||||
|
@@ -59,45 +59,9 @@ internal class ExShortcutKeyAction(private val exEntryPanel: ExEntryPanel) : Dum
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun registerCustomShortcutSet() {
|
fun registerCustomShortcutSet() {
|
||||||
val shortcuts = listOf(
|
val shortcuts = ExKeyBindings.bindings.map {
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
KeyboardShortcut(it.key, null)
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK),
|
}.toTypedArray()
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK),
|
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK),
|
|
||||||
)
|
|
||||||
.map { KeyboardShortcut(it, null) }
|
|
||||||
.toTypedArray()
|
|
||||||
|
|
||||||
registerCustomShortcutSet({ shortcuts }, exEntryPanel)
|
registerCustomShortcutSet({ shortcuts }, exEntryPanel)
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user