1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2024-11-25 16:42:55 +01:00

Compare commits

..

10 Commits

Author SHA1 Message Date
edb9b194bb
Set plugin version to chylex-12 2022-07-06 01:15:57 +02:00
Alex Plate
eae7ed95e2
Revert "Fix(VIM-308) Undo requires one more step if the cursor is not at the position where it was after undo"
This reverts commit 9dbe3c33
2022-07-06 01:15:56 +02:00
a1e2ae0eb9
Change matchit plugin to use HTML patterns in unrecognized files 2022-07-06 01:15:56 +02:00
eae2e3b6b8
Fix put command not working with multiple cursors 2022-07-06 01:15:56 +02:00
c2d997a520
Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2022-07-06 01:15:56 +02:00
e2a8a3c21a
Add VimScript 'renaming()' function 2022-07-06 01:08:14 +02:00
9b7fee6163
Add support for repeatable actions with ':raction' 2022-07-06 01:08:14 +02:00
d0f9d3dc70
Implement partial code completion support in macros
Works ok with insertions (Enter, Ctrl+Enter) but not with replacements (Tab)
2022-07-06 01:08:14 +02:00
8d3a69b338
Disable taking over arrow keys and Home/End 2022-07-06 01:08:14 +02:00
3c530474a1
Set custom plugin version 2022-07-06 01:08:14 +02:00
456 changed files with 7064 additions and 88648 deletions

View File

@ -4,7 +4,6 @@
name: Update Changelog On PR name: Update Changelog On PR
on: on:
workflow_dispatch:
pull_request: pull_request:
types: [ closed ] types: [ closed ]
@ -30,7 +29,7 @@ jobs:
id: update_authors id: update_authors
run: ./gradlew updateMergedPr -PprId=${{ github.event.number }} run: ./gradlew updateMergedPr -PprId=${{ github.event.number }}
env: env:
GITHUB_OAUTH: ${{ secrets.MERGE_PR }} GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }}
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4

View File

@ -1,40 +0,0 @@
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Update Changelog On PR (Test)
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 50
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Update authors
id: update_authors
run: ./gradlew updateMergedPr -PprId=525
env:
GITHUB_OAUTH: ${{ secrets.MERGE_PR }}
# - name: Commit changes
# uses: stefanzweifel/git-auto-commit-action@v4
# with:
# branch: master
# commit_message: Update changelog after merging PR
# commit_user_name: Alex Plate
# commit_user_email: aleksei.plate@jetbrains.com
# commit_author: Alex Plate <aleksei.plate@jetbrains.com>
# file_pattern: CHANGES.md

View File

@ -37,7 +37,7 @@ jobs:
run: ./gradlew updateAuthors --stacktrace run: ./gradlew updateAuthors --stacktrace
env: env:
SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }} SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }}
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }}
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4

View File

@ -5,16 +5,19 @@ object Constants {
const val EAP_CHANNEL = "eap" const val EAP_CHANNEL = "eap"
const val DEV_CHANNEL = "Dev" const val DEV_CHANNEL = "Dev"
const val VERSION = "1.11.1" const val VERSION = "1.10.3"
const val DEV_VERSION = "1.12.0" const val DEV_VERSION = "1.11.0"
const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT" const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT"
const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT" const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT"
const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT" const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT"
const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT" const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT"
const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT" const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT"
const val RELEASE = "LATEST-EAP-SNAPSHOT" const val RELEASE = "2022.1.3"
const val RELEASE_DEV = "LATEST-EAP-SNAPSHOT"
const val RELEASE_EAP = "LATEST-EAP-SNAPSHOT" // Use LATEST-EAP-SNAPSHOT only when we'll update the minimum version of IJ to 222+
// Because of some API inconcistincies, IdeaVim built on 2022+ won't run on older versions of IJ
const val RELEASE_DEV = "2022.1.3"
const val RELEASE_EAP = "2022.1.3"
} }

View File

@ -1,13 +1,6 @@
package _Self package _Self
import _Self.buildTypes.Compatibility import _Self.buildTypes.*
import _Self.buildTypes.LongRunning
import _Self.buildTypes.Nvim
import _Self.buildTypes.PluginVerifier
import _Self.buildTypes.PropertyBased
import _Self.buildTypes.Qodana
import _Self.buildTypes.TestsForIntelliJ20222
import _Self.buildTypes.TestsForIntelliJEAP
import _Self.subprojects.GitHub import _Self.subprojects.GitHub
import _Self.subprojects.OldTests import _Self.subprojects.OldTests
import _Self.subprojects.Releases import _Self.subprojects.Releases
@ -17,7 +10,6 @@ import _Self.vcsRoots.Branch_191_193
import _Self.vcsRoots.Branch_201 import _Self.vcsRoots.Branch_201
import _Self.vcsRoots.Branch_202 import _Self.vcsRoots.Branch_202
import _Self.vcsRoots.Branch_203_212 import _Self.vcsRoots.Branch_203_212
import _Self.vcsRoots.Branch_213_221
import _Self.vcsRoots.Branch_Release import _Self.vcsRoots.Branch_Release
import _Self.vcsRoots.GitHubPullRequest import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.Project import jetbrains.buildServer.configs.kotlin.v2019_2.Project
@ -34,20 +26,18 @@ object Project : Project({
vcsRoot(Branch_201) vcsRoot(Branch_201)
vcsRoot(Branch_202) vcsRoot(Branch_202)
vcsRoot(Branch_203_212) vcsRoot(Branch_203_212)
vcsRoot(Branch_213_221)
vcsRoot(Branch_Release) vcsRoot(Branch_Release)
vcsRoot(GitHubPullRequest) vcsRoot(GitHubPullRequest)
// Builds // Builds
buildType(TestsForIntelliJ20213)
buildType(TestsForIntelliJEAP) buildType(TestsForIntelliJEAP)
buildType(TestsForIntelliJ20222)
buildType(PropertyBased) buildType(PropertyBased)
buildType(LongRunning) buildType(LongRunning)
buildType(Nvim) buildType(Nvim)
buildType(PluginVerifier) buildType(PluginVerifier)
buildType(Compatibility)
buildType(Qodana) buildType(Qodana)
@ -57,7 +47,7 @@ object Project : Project({
type = "CloudImage" type = "CloudImage"
id = "PROJECT_EXT_768" id = "PROJECT_EXT_768"
param("agent_pool_id", "41") param("agent_pool_id", "41")
param("amazon-id", "ami-0fa17ce8238eb8868") param("amazon-id", "ami-0d1a6a32faa92923e")
param("ebs-optimized", "false") param("ebs-optimized", "false")
param("image-instances-limit", "") param("image-instances-limit", "")
param("image-name-prefix", "BuildAgentsIdeaVim") param("image-name-prefix", "BuildAgentsIdeaVim")

View File

@ -55,4 +55,4 @@ sealed class ActiveTests(buildName: String, ijVersion: String) : BuildType({
}) })
object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT") object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT")
object TestsForIntelliJ20222 : ActiveTests("Tests for IntelliJ 2022.2", "2022.2.1") object TestsForIntelliJ20213 : ActiveTests("Tests for IntelliJ 2021.3", "2021.3.2")

View File

@ -1,49 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
object Compatibility : BuildType({
id("IdeaVimCompatibility")
name = "IdeaVim compatibility with external plugins"
vcs {
root(DslContext.settingsRoot)
}
steps {
script {
name = "Check"
scriptContent = """
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}io.github.mishkun.ideavimsneak' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
""".trimIndent()
}
}
triggers {
schedule {
schedulingPolicy = daily {
hour = 4
}
branchFilter = ""
triggerBuild = always()
withPendingChangesOnly = false
}
}
features {
golang {
testFormat = "json"
}
}
})

View File

@ -31,7 +31,7 @@ object Nvim : BuildType({
script { script {
name = "Set up NeoVim" name = "Set up NeoVim"
scriptContent = """ scriptContent = """
wget https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz wget https://github.com/neovim/neovim/releases/download/v0.4.4/nvim-linux64.tar.gz
tar xzf nvim-linux64.tar.gz tar xzf nvim-linux64.tar.gz
cd nvim-linux64/bin cd nvim-linux64/bin
chmod +x nvim chmod +x nvim

View File

@ -4,7 +4,6 @@ import _Self.Constants.QODANA_TESTS
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange
@ -47,15 +46,12 @@ object Qodana : BuildType({
param("clonefinder-enable", "true") param("clonefinder-enable", "true")
param("clonefinder-reference-projects", "src") param("clonefinder-reference-projects", "src")
param("yaml-configuration", "") param("yaml-configuration", "")
linter = jvm {
version = Qodana.JVMVersion.LATEST
}
} }
} }
triggers { triggers {
vcs { vcs {
enabled = true enabled = false
branchFilter = "" branchFilter = ""
} }
schedule { schedule {

View File

@ -1,62 +0,0 @@
@file:Suppress("ClassName")
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
sealed class TestsForIntelliJ_213_221_branch(private val version: String) : BuildType({
name = "Tests for IntelliJ $version"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-$version")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_213_221)
checkoutMode = CheckoutMode.AUTO
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
failureConditions {
failOnMetricChange {
metric = BuildFailureOnMetric.MetricType.TEST_COUNT
threshold = 20
units = BuildFailureOnMetric.MetricUnit.PERCENTS
comparison = BuildFailureOnMetric.MetricComparison.LESS
compareTo = build {
buildRule = lastSuccessful()
}
}
}
})
object TestsForIntelliJ20213 : TestsForIntelliJ_213_221_branch("2021.3.2")

View File

@ -11,7 +11,6 @@ import _Self.buildTypes.TestsForIntelliJ20202
import _Self.buildTypes.TestsForIntelliJ20203 import _Self.buildTypes.TestsForIntelliJ20203
import _Self.buildTypes.TestsForIntelliJ20211 import _Self.buildTypes.TestsForIntelliJ20211
import _Self.buildTypes.TestsForIntelliJ20212 import _Self.buildTypes.TestsForIntelliJ20212
import _Self.buildTypes.TestsForIntelliJ20213
import jetbrains.buildServer.configs.kotlin.v2019_2.Project import jetbrains.buildServer.configs.kotlin.v2019_2.Project
object OldTests : Project({ object OldTests : Project({
@ -29,5 +28,4 @@ object OldTests : Project({
buildType(TestsForIntelliJ20203) buildType(TestsForIntelliJ20203)
buildType(TestsForIntelliJ20211) buildType(TestsForIntelliJ20211)
buildType(TestsForIntelliJ20212) buildType(TestsForIntelliJ20212)
buildType(TestsForIntelliJ20213)
}) })

View File

@ -1,12 +0,0 @@
@file:Suppress("ClassName")
package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_213_221 : GitVcsRoot({
id("HttpsGithubComJetBrainsIdeavimBranch213221")
name = "https://github.com/JetBrains/ideavim (branch 213-221)"
url = "https://github.com/JetBrains/ideavim.git"
branch = "213-221"
})

40
.teamcity/patches/buildTypes/Build.kts vendored Normal file
View File

@ -0,0 +1,40 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, create a buildType with id = 'Build'
in the root project, and delete the patch script.
*/
create(DslContext.projectId, BuildType({
id("Build")
name = "IdeaVim compatibility with external plugins"
vcs {
root(RelativeId("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster"))
}
steps {
script {
scriptContent = "go run test.go"
}
}
triggers {
vcs {
}
}
features {
golang {
testFormat = "json"
}
}
}))

25
.teamcity/patches/buildTypes/Nvim.kts vendored Normal file
View File

@ -0,0 +1,25 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
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 = 'Nvim'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("Nvim")) {
triggers {
val trigger1 = find<VcsTrigger> {
vcs {
branchFilter = ""
}
}
trigger1.apply {
enabled = false
}
}
}

View File

@ -0,0 +1,25 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
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 = 'PluginVerifier'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("PluginVerifier")) {
triggers {
val trigger1 = find<VcsTrigger> {
vcs {
branchFilter = ""
}
}
trigger1.apply {
enabled = false
}
}
}

View File

@ -2,8 +2,9 @@ package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.ScheduleTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/* /*
@ -15,9 +16,6 @@ changeBuildType(RelativeId("Qodana")) {
expectSteps { expectSteps {
qodana { qodana {
name = "Qodana" name = "Qodana"
linter = jvm {
version = Qodana.JVMVersion.LATEST
}
param("clonefinder-enable", "true") param("clonefinder-enable", "true")
param("clonefinder-languages", "Java") param("clonefinder-languages", "Java")
param("clonefinder-languages-container", "Java Kotlin") param("clonefinder-languages-container", "Java Kotlin")
@ -31,25 +29,27 @@ changeBuildType(RelativeId("Qodana")) {
} }
} }
steps { steps {
insert(0) { update<Qodana>(0) {
gradle { clearConditions()
name = "Generate grammar" linter = jvm {
tasks = "generateGrammarSource" version = Qodana.JVMVersion.LATEST
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
} }
} }
update<Qodana>(1) { }
clearConditions()
reportAsTests = true triggers {
argumentsCommandDocker = "-e QODANA_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmdhbml6YXRpb24iOiIzUFZrQSIsInByb2plY3QiOiIzN1FlQSIsInRva2VuIjoiM0t2bXoifQ.uohp81tM7iAfvvB6k8faarfpV-OjusAaEbWQ8iNrOgs" val trigger1 = find<ScheduleTrigger> {
argumentsEntryPointDocker = "--baseline qodana.sarif.json" schedule {
param("clonefinder-languages", "") schedulingPolicy = weekly {
param("collect-anonymous-statistics", "") dayOfWeek = ScheduleTrigger.DAY.Tuesday
param("licenseaudit-enable", "") }
param("clonefinder-languages-container", "") branchFilter = ""
param("clonefinder-queried-project", "") triggerBuild = always()
param("clonefinder-enable", "") }
param("clonefinder-reference-projects", "") }
trigger1.apply {
enabled = false
} }
} }
} }

View File

@ -1,27 +0,0 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.VcsLabeling
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.vcsLabeling
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 = 'ReleaseEap'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("ReleaseEap")) {
features {
val feature1 = find<VcsLabeling> {
vcsLabeling {
vcsRootId = "${DslContext.settingsRoot.id}"
labelingPattern = "%system.build.number%"
successfulOnly = true
branchFilter = ""
}
}
feature1.apply {
successfulOnly = false
}
}
}

74
.teamcity/patches/projects/_Self.kts vendored Normal file
View File

@ -0,0 +1,74 @@
package patches.projects
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.AmazonEC2CloudImage
import jetbrains.buildServer.configs.kotlin.v2019_2.AmazonEC2CloudProfile
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
import jetbrains.buildServer.configs.kotlin.v2019_2.amazonEC2CloudImage
import jetbrains.buildServer.configs.kotlin.v2019_2.amazonEC2CloudProfile
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 root project
accordingly, and delete the patch script.
*/
changeProject(DslContext.projectId) {
features {
val feature1 = find<AmazonEC2CloudImage> {
amazonEC2CloudImage {
id = "PROJECT_EXT_768"
profileId = "amazon-48"
agentPoolId = "41"
name = "BuildAgentsIdeaVim"
vpcSubnetId = "subnet-58839511"
keyPairName = ""
instanceType = "c5d.xlarge"
securityGroups = listOf("sg-eda08696", "sg-7332cf0f")
useSpotInstances = true
instanceTags = mapOf(
"project" to "idea-vim"
)
source = Source("ami-0d1a6a32faa92923e")
param("image-instances-limit", "")
param("spot-instance-price", "")
}
}
feature1.apply {
profileId = "amazon-48"
agentPoolId = "41"
name = "BuildAgentsIdeaVim"
vpcSubnetId = "subnet-58839511"
keyPairName = ""
instanceType = "c5d.xlarge"
securityGroups = listOf("sg-eda08696", "sg-7332cf0f")
useSpotInstances = true
instanceTags = mapOf(
"project" to "idea-vim"
)
source = Source("ami-0fa17ce8238eb8868")
}
val feature2 = find<AmazonEC2CloudProfile> {
amazonEC2CloudProfile {
id = "amazon-48"
name = "Cloud Agents - Single Build"
terminateAfterBuild = true
terminateIdleMinutes = 15
region = AmazonEC2CloudProfile.Regions.EU_WEST_DUBLIN
maxInstancesCount = 10
authType = accessKey {
keyId = "credentialsJSON:dbcdb2a2-de5f-4bc9-9421-292b19e83947"
secretKey = "credentialsJSON:65a87fe7-0977-4af9-96f1-344f2b82d269"
}
param("agentPushPreset", "")
}
}
feature2.apply {
name = "Cloud Agents - Single Build"
terminateAfterBuild = true
terminateIdleMinutes = 15
region = AmazonEC2CloudProfile.Regions.EU_WEST_DUBLIN
maxInstancesCount = 10
}
}
}

View File

@ -0,0 +1,25 @@
package patches.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, create a vcsRoot with id = 'HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster'
in the root project, and delete the patch script.
*/
create(DslContext.projectId, GitVcsRoot({
id("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster")
name = "https://github.com/AlexPl292/IdeaVimCompatibility#refs/heads/master"
url = "https://github.com/AlexPl292/IdeaVimCompatibility"
branch = "refs/heads/master"
branchSpec = "refs/heads/*"
authMethod = password {
userName = "AlexPl292"
password = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f"
}
param("oauthProviderId", "PROJECT_EXT_1")
param("useAlternates", "true")
}))

View File

@ -0,0 +1,23 @@
package patches.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, create a vcsRoot with id = 'IdeaVimCompatibility'
in the root project, and delete the patch script.
*/
create(DslContext.projectId, GitVcsRoot({
id("IdeaVimCompatibility")
name = "IdeaVimCompatibility"
url = "git@github.com:AlexPl292/IdeaVimCompatibility.git"
branch = "refs/heads/master"
authMethod = uploadedKey {
userName = "git"
uploadedKey = "Alex Plate TeamCity key"
}
param("useAlternates", "true")
}))

View File

@ -32,48 +32,16 @@ Contributors:
[![icon][github]](https://github.com/yole) [![icon][github]](https://github.com/yole)
&nbsp; &nbsp;
Dmitry Jemerov Dmitry Jemerov
* [![icon][mail]](mailto:tony.kay@gmail.com)
[![icon][github]](https://github.com/awkay)
&nbsp;
Tony Kay
* [![icon][mail]](mailto:jamescmartinez@gmail.com)
[![icon][github]](https://github.com/jamescmartinez)
&nbsp;
James Martinez
* [![icon][mail]](mailto:almas337519@gmail.com)
[![icon][github]](https://github.com/strogiyotec)
&nbsp;
strogiyotec
* [![icon][mail]](mailto:raimon49@hotmail.com)
[![icon][github]](https://github.com/raimon49)
&nbsp;
raimon
* [![icon][mail]](mailto:agrsbm@gmail.com)
[![icon][github-off]](#)
&nbsp;
Alexander Griesbaum
* [![icon][mail]](mailto:manwe64@gmail.com)
[![icon][github]](https://github.com/baldrs)
&nbsp;
Baldrs
* [![icon][mail]](mailto:yury@shurup.com)
[![icon][github]](https://github.com/zyv)
&nbsp;
Yury V. Zaytsev
* [![icon][mail]](mailto:jflorian@doubledog.org)
[![icon][github]](https://github.com/jflorian)
&nbsp;
John Florian
* [![icon][mail]](mailto:marquis@marquiswang.com) * [![icon][mail]](mailto:marquis@marquiswang.com)
[![icon][github]](https://github.com/marquiswang) [![icon][github]](https://github.com/marquiswang)
&nbsp; &nbsp;
Marquis Wang Marquis Wang
* [![icon][mail]](mailto:madgnome@gmail.com) * [![icon][mail]](mailto:madgnome@gmail.com)
[![icon][github]](https://github.com/madgnome) [![icon][github-off]](#)
&nbsp; &nbsp;
Julien Hoarau Julien Hoarau
* [![icon][mail]](mailto:masanobu.imai@gmail.com) * [![icon][mail]](mailto:masanobu.imai@gmail.com)
[![icon][github]](https://github.com/masanobuimai) [![icon][github-off]](#)
&nbsp; &nbsp;
Masanobu Imai Masanobu Imai
* [![icon][mail]](mailto:poxvuibr@gmail.com) * [![icon][mail]](mailto:poxvuibr@gmail.com)
@ -89,7 +57,7 @@ Contributors:
&nbsp; &nbsp;
John Lindquist John Lindquist
* [![icon][mail]](mailto:iklotzko@ltech.com) * [![icon][mail]](mailto:iklotzko@ltech.com)
[![icon][github]](https://github.com/iklotzko) [![icon][github-off]](#)
&nbsp; &nbsp;
Ira Klotzko Ira Klotzko
* [![icon][mail]](mailto:alex@selesse.com) * [![icon][mail]](mailto:alex@selesse.com)
@ -97,7 +65,7 @@ Contributors:
&nbsp; &nbsp;
Alex Selesse Alex Selesse
* [![icon][mail]](mailto:dbennett@palantir.com) * [![icon][mail]](mailto:dbennett@palantir.com)
[![icon][github]](https://github.com/dathanb) [![icon][github-off]](#)
&nbsp; &nbsp;
Dathan Bennett Dathan Bennett
* [![icon][mail]](mailto:kphayen@gmail.com) * [![icon][mail]](mailto:kphayen@gmail.com)
@ -109,11 +77,11 @@ Contributors:
&nbsp; &nbsp;
Alexey Shmalko Alexey Shmalko
* [![icon][mail]](mailto:a.m.brookins@gmail.com) * [![icon][mail]](mailto:a.m.brookins@gmail.com)
[![icon][github]](https://github.com/abrookins) [![icon][github-off]](#)
&nbsp; &nbsp;
Andrew Brookins Andrew Brookins
* [![icon][mail]](mailto:changwang83@gmail.com) * [![icon][mail]](mailto:changwang83@gmail.com)
[![icon][github]](https://github.com/changwang) [![icon][github-off]](#)
&nbsp; &nbsp;
Chang Wang Chang Wang
* [![icon][mail]](mailto:josejaime.sanchez@gmail.com) * [![icon][mail]](mailto:josejaime.sanchez@gmail.com)
@ -121,19 +89,19 @@ Contributors:
&nbsp; &nbsp;
Jaime Sanchez Jaime Sanchez
* [![icon][mail]](mailto:thomas@homburg.dk) * [![icon][mail]](mailto:thomas@homburg.dk)
[![icon][github]](https://github.com/homburg) [![icon][github-off]](#)
&nbsp; &nbsp;
Thomas B Homburg Thomas B Homburg
* [![icon][mail]](mailto:smartbomb@server.fake) * [![icon][mail]](mailto:smartbomb@server.fake)
[![icon][github]](https://github.com/smartbomb) [![icon][github-off]](#)
&nbsp; &nbsp;
smartbomb smartbomb
* [![icon][mail]](mailto:tuomas.tynkkynen@iki.fi) * [![icon][mail]](mailto:tuomas.tynkkynen@iki.fi)
[![icon][github]](https://github.com/dezgeg) [![icon][github-off]](#)
&nbsp; &nbsp;
Tuomas Tynkkynen Tuomas Tynkkynen
* [![icon][mail]](mailto:jackson@donorschoose.org) * [![icon][mail]](mailto:jackson@donorschoose.org)
[![icon][github]](https://github.com/jdpopkin) [![icon][github-off]](#)
&nbsp; &nbsp;
Jackson Popkin Jackson Popkin
* [![icon][mail]](mailto:yuyuyu1999@gmail.com) * [![icon][mail]](mailto:yuyuyu1999@gmail.com)
@ -141,7 +109,7 @@ Contributors:
&nbsp; &nbsp;
Teruo Kunihiro Teruo Kunihiro
* [![icon][mail]](mailto:lubashka.994@mail.ru) * [![icon][mail]](mailto:lubashka.994@mail.ru)
[![icon][github]](https://github.com/lubba) [![icon][github-off]](#)
&nbsp; &nbsp;
Liubov Paina Liubov Paina
* [![icon][mail]](mailto:me@dhleong.net) * [![icon][mail]](mailto:me@dhleong.net)
@ -169,7 +137,7 @@ Contributors:
&nbsp; &nbsp;
tieTYT tieTYT
* [![icon][mail]](mailto:nickgieschen@gmail.com) * [![icon][mail]](mailto:nickgieschen@gmail.com)
[![icon][github]](https://github.com/nickgieschen) [![icon][github-off]](#)
&nbsp; &nbsp;
Nick Gieschen Nick Gieschen
* [![icon][mail]](mailto:ikenox@gmail.com) * [![icon][mail]](mailto:ikenox@gmail.com)
@ -181,7 +149,7 @@ Contributors:
&nbsp; &nbsp;
Maximilian Luz Maximilian Luz
* [![icon][mail]](mailto:vparfinenko@excelsior-usa.com) * [![icon][mail]](mailto:vparfinenko@excelsior-usa.com)
[![icon][github]](https://github.com/cypok) [![icon][github-off]](#)
&nbsp; &nbsp;
Vladimir Parfinenko Vladimir Parfinenko
* [![icon][mail]](mailto:hassmann@hwdev.de) * [![icon][mail]](mailto:hassmann@hwdev.de)
@ -225,7 +193,7 @@ Contributors:
&nbsp; &nbsp;
Marcel Hild Marcel Hild
* [![icon][mail]](mailto:vedranb@gmail.com) * [![icon][mail]](mailto:vedranb@gmail.com)
[![icon][github]](https://github.com/vedran) [![icon][github-off]](#)
&nbsp; &nbsp;
Vedran Budimcic Vedran Budimcic
* [![icon][mail]](mailto:andreigasparovici1@gmail.com) * [![icon][mail]](mailto:andreigasparovici1@gmail.com)
@ -240,13 +208,10 @@ Contributors:
[![icon][github]](https://github.com/TonyArra) [![icon][github]](https://github.com/TonyArra)
&nbsp; &nbsp;
Tony Arra Tony Arra
* [![icon][mail]](mailto:mj@ziolko.dev) * [![icon][mail]](mailto:bradziolko@gmail.com)
[![icon][github]](https://github.com/mjziolko) [![icon][github]](https://github.com/bradziolko)
&nbsp; &nbsp;
Madeline Ziolko Brad Ziolko
[Original contribution from:
[![icon][mail]](mailto:bradziolko@gmail.com)
[![icon][github]](https://github.com/bradziolko)]
* [![icon][mail]](mailto:sumoooru2@gmail.com) * [![icon][mail]](mailto:sumoooru2@gmail.com)
[![icon][github]](https://github.com/sumoooru2) [![icon][github]](https://github.com/sumoooru2)
&nbsp; &nbsp;
@ -451,10 +416,6 @@ Contributors:
[![icon][github]](https://github.com/Vvalter) [![icon][github]](https://github.com/Vvalter)
&nbsp; &nbsp;
Simon Rainer Simon Rainer
* [![icon][mail]](mailto:filipp.vakhitov@jetbrains.com)
[![icon][github]](https://github.com/lippfi)
&nbsp;
lippfi
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
contact the maintainers. contact the maintainers.

View File

@ -25,17 +25,6 @@ usual beta standards.
## To Be Released ## To Be Released
### Fixes:
* [VIM-1758](https://youtrack.jetbrains.com/issue/VIM-1758) Commentary plugin in rider
* [VIM-1903](https://youtrack.jetbrains.com/issue/VIM-1903) Autoindent now works in rider
* [VIM-2744](https://youtrack.jetbrains.com/issue/VIM-2744) Fix undo from ex line
* [VIM-2749](https://youtrack.jetbrains.com/issue/VIM-2749) Fix :tabn and :tabN commands
* [VIM-2718](https://youtrack.jetbrains.com/issue/VIM-2718) Fixed case where the primary caret was changed
* [VIM-2766](https://youtrack.jetbrains.com/issue/VIM-2766) Move NERDTree update to background thread
* [VIM-2768](https://youtrack.jetbrains.com/issue/VIM-2768) Refactor listeners
## 1.11.0, 2022-08-09
### Features: ### Features:
* Add `gcu` command for Commentary plugin * Add `gcu` command for Commentary plugin
* Add `:Commentary` command, which works great for commands such as `:%g/fun/Commentary` * Add `:Commentary` command, which works great for commands such as `:%g/fun/Commentary`
@ -47,7 +36,6 @@ usual beta standards.
E.g. `<Plug>Commentary` instead of `<Plug>(CommentMotion)`. Old mappings are maintained for compatibility. E.g. `<Plug>Commentary` instead of `<Plug>(CommentMotion)`. Old mappings are maintained for compatibility.
* If you open `~/.ideavimrc` in IDE, remove a mapping, and reload the config using the reload button, * If you open `~/.ideavimrc` in IDE, remove a mapping, and reload the config using the reload button,
the mapping will actually be unmapped. the mapping will actually be unmapped.
* New vim (and IdeaVim) behaviour: `ci(`& friends searches for the brackets in the line.
### Fixes: ### Fixes:
* [VIM-2587](https://youtrack.jetbrains.com/issue/VIM-2587) Use ctrl-6 as ctrl-^ * [VIM-2587](https://youtrack.jetbrains.com/issue/VIM-2587) Use ctrl-6 as ctrl-^
@ -64,14 +52,11 @@ usual beta standards.
* [VIM-2595](https://youtrack.jetbrains.com/issue/VIM-2595) Support plugins in macro execution * [VIM-2595](https://youtrack.jetbrains.com/issue/VIM-2595) Support plugins in macro execution
* [VIM-2671](https://youtrack.jetbrains.com/issue/VIM-2671) Fix using plugins from mappings * [VIM-2671](https://youtrack.jetbrains.com/issue/VIM-2671) Fix using plugins from mappings
* [VIM-2675](https://youtrack.jetbrains.com/issue/VIM-2675) Fix numbering register in visual mode * [VIM-2675](https://youtrack.jetbrains.com/issue/VIM-2675) Fix numbering register in visual mode
* [VIM-696](https://youtrack.jetbrains.com/issue/VIM-696/vim-selection-issue-after-undo) Fix selection after undo
* [VIM-744](https://youtrack.jetbrains.com/issue/VIM-744/Use-undoredo-with-count-modifier) Add count to undo/redo * [VIM-744](https://youtrack.jetbrains.com/issue/VIM-744/Use-undoredo-with-count-modifier) Add count to undo/redo
* [VIM-1862](https://youtrack.jetbrains.com/issue/VIM-1862/Ex-commands-executed-in-keymaps-and-macros-are-added-to-the-command-history) Fix command history * [VIM-1862](https://youtrack.jetbrains.com/issue/VIM-1862/Ex-commands-executed-in-keymaps-and-macros-are-added-to-the-command-history) Fix command history
* [VIM-2227](https://youtrack.jetbrains.com/issue/VIM-2227) Wrong behavior when deleting / changing surround with invalid character * [VIM-2227](https://youtrack.jetbrains.com/issue/VIM-2227) Wrong behavior when deleting / changing surround with invalid character
* [VIM-2691](https://youtrack.jetbrains.com/issue/VIM-2691) Save file on :w * [VIM-2691](https://youtrack.jetbrains.com/issue/VIM-2691) Save file on :w
* [VIM-2710](https://youtrack.jetbrains.com/issue/VIM-2710) Show options value on `set opt`
* [VIM-913](https://youtrack.jetbrains.com/issue/VIM-913) Partially fix the issue with macros and autocompletion
* [VIM-2723](https://youtrack.jetbrains.com/issue/VIM-2723) Move focus to editor after :q
* [VIM-2728](https://youtrack.jetbrains.com/issue/VIM-2728) Give access to global variables
### Merged PRs: ### Merged PRs:
* [468](https://github.com/JetBrains/ideavim/pull/468) by [Thomas Schouten](https://github.com/PHPirates): Implement UserDataHolder for EditorDataContext * [468](https://github.com/JetBrains/ideavim/pull/468) by [Thomas Schouten](https://github.com/PHPirates): Implement UserDataHolder for EditorDataContext
@ -81,10 +66,6 @@ usual beta standards.
* [494](https://github.com/JetBrains/ideavim/pull/494) by [Matt Ellis](https://github.com/citizenmatt): Cleanup pre-212 CaretVisualAttributes compatibility code * [494](https://github.com/JetBrains/ideavim/pull/494) by [Matt Ellis](https://github.com/citizenmatt): Cleanup pre-212 CaretVisualAttributes compatibility code
* [504](https://github.com/JetBrains/ideavim/pull/504) by [Matt Ellis](https://github.com/citizenmatt): Minor bug fixes * [504](https://github.com/JetBrains/ideavim/pull/504) by [Matt Ellis](https://github.com/citizenmatt): Minor bug fixes
* [519](https://github.com/JetBrains/ideavim/pull/519) by [chylex](https://github.com/chylex): Fix(VIM-2227): Wrong behavior when deleting / changing surround with invalid character * [519](https://github.com/JetBrains/ideavim/pull/519) by [chylex](https://github.com/chylex): Fix(VIM-2227): Wrong behavior when deleting / changing surround with invalid character
* [525](https://github.com/JetBrains/ideavim/pull/525) by [Matt Ellis](https://github.com/citizenmatt): Improve handling of fractional width fonts
* [526](https://github.com/JetBrains/ideavim/pull/526) by [Alex Pláte](https://github.com/AlexPl292): Create gradle.properties
* [528](https://github.com/JetBrains/ideavim/pull/528) by [chylex](https://github.com/chylex): Implement partial code completion support in macros
* [531](https://github.com/JetBrains/ideavim/pull/531) by [Matt Ellis](https://github.com/citizenmatt): Consolidate doTest methods
## 1.10.0, 2022-02-17 ## 1.10.0, 2022-02-17

View File

@ -5,7 +5,7 @@ IdeaVim is an open source project created by 80+ contributors. Would you like to
This page is created to help you start contributing. And who knows, maybe in a few days this project will be brighter than ever! This page is created to help you start contributing. And who knows, maybe in a few days this project will be brighter than ever!
:warning: The plugin is currently under a huge refactoring aiming to split into vim-engine and IdeaVim in order to :warning: The plugin is currently under a huge refactoring aiming to split into vim-engine and IdeaVim in order to
support the new [Fleet IDE](https://www.jetbrains.com/fleet/). Please see [Fleet refactoring](#Fleet-refactoring). support the new [Fleet IDE](https://www.jetbrains.com/fleet/).
## Before you begin ## Before you begin
@ -32,7 +32,7 @@ OK, ready to do some coding?
Yoo hoo! Youre all set to begin contributing. Yoo hoo! Youre all set to begin contributing.
We've prepared some useful configurations for you: We've prepared some useful configurations for you:
![Prepared configurations light](assets/contributing/configs-light.png#gh-light-mode-only)![Prepared configurations dark](assets/contributing/configs-dark.png#gh-dark-mode-only) ![Prepared configurations](assets/contributing/configurations.png)
And here are useful gradle commands: And here are useful gradle commands:
@ -120,17 +120,6 @@ so you can reuse your `.vimrc` settings.
We also support proper command mappings (functions are mapped to `<Plug>...`), the operator function (`OperatorFunction`), and so on. We also support proper command mappings (functions are mapped to `<Plug>...`), the operator function (`OperatorFunction`), and so on.
- Magic is supported as well. See `Magic`. - Magic is supported as well. See `Magic`.
## Fleet refactoring
At the moment, IdeaVim is under an active refactoring aiming to split IdeaVim into two modules: vim-engine and IdeaVim.
If you develop a plugin that depends on IdeaVim: We have an instrument to check that our changes don't affect
the plugins in the marketplace. Also, we commit to support currently used API at least till the end of 2022.
If you still encounter any issues with the newer versions of IdeaVim, please [contact maintainers](https://github.com/JetBrains/ideavim#contact-maintainers).
We kindly ask you not to use anything from the new API (like `VimEditor`, `injector`) because at the moment we don't
guarantee the compatibility of this API in the future versions.
----- -----
### I read the whole page but something is still unclear. ### I read the whole page but something is still unclear.

View File

@ -11,7 +11,7 @@ IdeaVim
[![Gitter][gitter-svg]][gitter] [![Gitter][gitter-svg]][gitter]
[![Twitter][twitter-svg]][twitter] [![Twitter][twitter-svg]][twitter]
IdeaVim is a Vim engine for JetBrains IDEs. IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
##### Contact maintainers: ##### Contact maintainers:
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM) * [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
@ -36,7 +36,7 @@ Setup
- IdeaVim can be installed via `Settings | Plugins`. - IdeaVim can be installed via `Settings | Plugins`.
See the [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#). See the [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#).
- Use `Tools | Vim` in the menu to enable or disable vim. - Use `Tools | Vim Emulator` in the menu to enable or disable emulation.
- Use the `~/.ideavimrc` file as an analog of `~/.vimrc` ([learn more](#Files)). The XDG standard is supported, as well. - Use the `~/.ideavimrc` file as an analog of `~/.vimrc` ([learn more](#Files)). The XDG standard is supported, as well.
@ -88,7 +88,7 @@ Here are some examples of supported vim features and commands:
* Vim web help * Vim web help
* `~/.ideavimrc` configuration file * `~/.ideavimrc` configuration file
[IdeaVim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins): [Emulated Vim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins):
* vim-easymotion * vim-easymotion
* NERDTree * NERDTree
@ -198,7 +198,7 @@ Alternatively, you can set up initialization commands using [XDG](https://specif
Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file. Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file.
IdeaVim Plugins Emulated Vim Plugins
-------------------- --------------------
See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins) See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins)
@ -226,10 +226,7 @@ Ex commands or via `:map` command mappings:
<details> <details>
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary> <summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
<picture> <img src="assets/readme/track_action_id.gif" alt="track action ids"/>
<source media="(prefers-color-scheme: dark)" srcset="assets/readme/track_action_dark.gif">
<img src="assets/readme/track_action_light.gif" alt="track action ids"/>
</picture>
</details> </details>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 KiB

View File

@ -15,9 +15,7 @@ buildscript {
classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2") classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2")
classpath("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r") classpath("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r")
classpath("org.kohsuke:github-api:1.305") classpath("org.kohsuke:github-api:1.305")
classpath("org.jetbrains:markdown:0.3.1")
// This comes from the changelog plugin
// classpath("org.jetbrains:markdown:0.3.1")
} }
} }
@ -26,11 +24,11 @@ plugins {
java java
kotlin("jvm") version "1.6.21" kotlin("jvm") version "1.6.21"
id("org.jetbrains.intellij") version "1.10.0-SNAPSHOT" id("org.jetbrains.intellij") version "1.7.0-SNAPSHOT"
id("org.jetbrains.changelog") version "1.3.1" id("org.jetbrains.changelog") version "1.3.1"
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
id("org.jlleitschuh.gradle.ktlint") version "10.3.0" id("org.jlleitschuh.gradle.ktlint") version "10.2.1"
} }
// Import variables from gradle.properties file // Import variables from gradle.properties file
@ -73,8 +71,6 @@ dependencies {
antlr("org.antlr:antlr4:$antlrVersion") antlr("org.antlr:antlr4:$antlrVersion")
api(project(":vim-engine")) api(project(":vim-engine"))
testApi("com.squareup.okhttp3:okhttp:4.10.0")
} }
configurations { configurations {
@ -89,8 +85,6 @@ tasks.register<Test>("testWithNeovim") {
group = "verification" group = "verification"
systemProperty("ideavim.nvim.test", "true") systemProperty("ideavim.nvim.test", "true")
exclude("/ui/**") exclude("/ui/**")
exclude("**/longrunning/**")
exclude("**/propertybased/**")
} }
tasks.register<Test>("testPropertyBased") { tasks.register<Test>("testPropertyBased") {
@ -121,8 +115,6 @@ tasks {
include("**/*test.class") include("**/*test.class")
include("**/*Tests.class") include("**/*Tests.class")
exclude("**/ParserTest.class") exclude("**/ParserTest.class")
exclude("**/longrunning/**")
exclude("**/propertybased/**")
} }
val testPropertyBased by getting(Test::class) { val testPropertyBased by getting(Test::class) {
@ -152,7 +144,7 @@ tasks {
compileKotlin { compileKotlin {
kotlinOptions { kotlinOptions {
jvmTarget = javaVersion jvmTarget = javaVersion
apiVersion = "1.6" apiVersion = "1.5"
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility") freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
// allWarningsAsErrors = true // allWarningsAsErrors = true
} }
@ -160,24 +152,12 @@ tasks {
compileTestKotlin { compileTestKotlin {
kotlinOptions { kotlinOptions {
jvmTarget = javaVersion jvmTarget = javaVersion
apiVersion = "1.6" apiVersion = "1.5"
// allWarningsAsErrors = true // allWarningsAsErrors = true
} }
} }
} }
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(javaVersion))
}
}
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(javaVersion))
}
}
gradle.projectsEvaluated { gradle.projectsEvaluated {
tasks.compileJava { tasks.compileJava {
// options.compilerArgs.add("-Werror") // options.compilerArgs.add("-Werror")
@ -220,7 +200,7 @@ tasks {
runPluginVerifier { runPluginVerifier {
downloadDir.set("${project.buildDir}/pluginVerifier/ides") downloadDir.set("${project.buildDir}/pluginVerifier/ides")
teamCityOutputFormat.set(true) teamCityOutputFormat.set(true)
// ideVersions.set(listOf("IC-2021.3.4")) ideVersions.set(listOf("IC-2021.3.4"))
} }
generateGrammarSource { generateGrammarSource {
@ -251,18 +231,12 @@ tasks {
dependsOn(createOpenApiSourceJar) dependsOn(createOpenApiSourceJar)
from(createOpenApiSourceJar) { into("lib/src") } from(createOpenApiSourceJar) { into("lib/src") }
} }
// Don't forget to update plugin.xml
patchPluginXml {
sinceBuild.set("222")
}
} }
// --- Linting // --- Linting
ktlint { ktlint {
disabledRules.add("no-wildcard-imports") disabledRules.add("no-wildcard-imports")
version.set("0.43.0")
} }
// --- Tests // --- Tests
@ -287,7 +261,7 @@ changelog {
itemPrefix.set("*") itemPrefix.set("*")
path.set("${project.projectDir}/CHANGES.md") path.set("${project.projectDir}/CHANGES.md")
unreleasedTerm.set("To Be Released") unreleasedTerm.set("To Be Released")
headerParserRegex.set("(\\d\\.\\d+(.\\d+)?)".toRegex()) headerParserRegex.set("\\d\\.\\d+(.\\d+)?".toRegex())
// header = { "${project.version}" } // header = { "${project.version}" }
// version = "0.60" // version = "0.60"
} }
@ -340,30 +314,20 @@ tasks.register("slackNotification") {
println("Response code: $postRc") println("Response code: $postRc")
if (postRc == 200) { if (postRc == 200) {
println(inputStream.bufferedReader().use { it.readText() }) println(inputStream.bufferedReader().use { it.readText() })
} else {
println(errorStream.bufferedReader().use { it.readText() })
} }
} }
} }
} }
// Uncomment to enable FUS testing mode
// tasks {
// withType<org.jetbrains.intellij.tasks.RunIdeTask> {
// jvmArgs("-Didea.is.internal=true")
// jvmArgs("-Dfus.internal.test.mode=true")
// }
// }
// --- Update authors // --- Update authors
tasks.register("updateAuthors") { tasks.register("updateAuthors") {
doLast { doLast {
val uncheckedEmails = setOf( val uncheckedEmails = setOf(
"aleksei.plate@jetbrains.com", "aleksei.plate@jetbrains.com",
"aleksei.plate@teamcity", "aleksei.plate@teamcity",
"aleksei.plate@TeamCity", "aleksei.plate@TeamCity",
"alex.plate@192.168.0.109", "alex.plate@192.168.0.109"
"nikita.koshcheev@TeamCity",
) )
updateAuthors(uncheckedEmails) updateAuthors(uncheckedEmails)
} }
@ -374,7 +338,6 @@ val prId: String by project
tasks.register("updateMergedPr") { tasks.register("updateMergedPr") {
doLast { doLast {
if (project.hasProperty("prId")) { if (project.hasProperty("prId")) {
println("Got pr id: $prId")
updateMergedPr(prId.toInt()) updateMergedPr(prId.toInt())
} else { } else {
error("Cannot get prId") error("Cannot get prId")
@ -538,9 +501,7 @@ data class Change(val id: String, val text: String)
fun updateMergedPr(number: Int) { fun updateMergedPr(number: Int) {
val gitHub = org.kohsuke.github.GitHub.connect() val gitHub = org.kohsuke.github.GitHub.connect()
println("Connecting to the repo...")
val repository = gitHub.getRepository("JetBrains/ideavim") val repository = gitHub.getRepository("JetBrains/ideavim")
println("Getting pull requests...")
val pullRequest = repository.getPullRequest(number) val pullRequest = repository.getPullRequest(number)
if (pullRequest.user.login == "dependabot[bot]") return if (pullRequest.user.login == "dependabot[bot]") return

View File

@ -1,11 +1,11 @@
# suppress inspection "UnusedProperty" for whole file # suppress inspection "UnusedProperty" for whole file
ideaVersion=2022.2.2 ideaVersion=2022.1.2
downloadIdeaSources=true downloadIdeaSources=true
instrumentPluginCode=true instrumentPluginCode=true
version=chylex-13 version=chylex-12
javaVersion=17 javaVersion=11
remoteRobotVersion=0.11.15 remoteRobotVersion=0.11.10
antlrVersion=4.10.1 antlrVersion=4.10.1
# Please don't forget to update kotlin version in buildscript section # Please don't forget to update kotlin version in buildscript section

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@ import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.actionSystem.TypedAction; import com.intellij.openapi.editor.actionSystem.TypedAction;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler; import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.util.Disposer;
import com.maddyhome.idea.vim.helper.HandlerInjector; import com.maddyhome.idea.vim.helper.HandlerInjector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -102,41 +101,38 @@ public class EventFacade {
EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable);
} }
public void addEditorMouseListener(@NotNull Editor editor, @SuppressWarnings("deprecation")
@NotNull EditorMouseListener listener, public void removeEditorFactoryListener(@NotNull EditorFactoryListener listener) {
@NotNull Disposable disposable) { // Listener is removed not only if application is disposed
editor.addEditorMouseListener(listener, disposable); EditorFactory.getInstance().removeEditorFactoryListener(listener);
}
public void addEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) {
editor.addEditorMouseListener(listener);
} }
public void removeEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) { public void removeEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) {
editor.removeEditorMouseListener(listener); editor.removeEditorMouseListener(listener);
} }
public void addComponentMouseListener(@NotNull Component component, public void addComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) {
@NotNull MouseListener mouseListener,
@NotNull Disposable disposable) {
component.addMouseListener(mouseListener); component.addMouseListener(mouseListener);
Disposer.register(disposable, () -> component.removeMouseListener(mouseListener));
} }
public void removeComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) { public void removeComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) {
component.removeMouseListener(mouseListener); component.removeMouseListener(mouseListener);
} }
public void addEditorMouseMotionListener(@NotNull Editor editor, public void addEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) {
@NotNull EditorMouseMotionListener listener, editor.addEditorMouseMotionListener(listener);
@NotNull Disposable disposable) {
editor.addEditorMouseMotionListener(listener, disposable);
} }
public void removeEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) { public void removeEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) {
editor.removeEditorMouseMotionListener(listener); editor.removeEditorMouseMotionListener(listener);
} }
public void addEditorSelectionListener(@NotNull Editor editor, public void addEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) {
@NotNull SelectionListener listener, editor.getSelectionModel().addSelectionListener(listener);
@NotNull Disposable disposable) {
editor.getSelectionModel().addSelectionListener(listener, disposable);
} }
public void removeEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) { public void removeEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) {

View File

@ -18,14 +18,8 @@
package com.maddyhome.idea.vim package com.maddyhome.idea.vim
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManagerListener
import com.intellij.openapi.startup.StartupActivity import com.intellij.openapi.startup.StartupActivity
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.localEditors
import com.maddyhome.idea.vim.options.OptionScope
/** /**
* @author Alex Plate * @author Alex Plate
@ -42,19 +36,3 @@ class PluginStartup : StartupActivity.DumbAware/*, LightEditCompatible*/ {
VimPlugin.getInstance().initialize() VimPlugin.getInstance().initialize()
} }
} }
// This is a temporal workaround for VIM-2487
class PyNotebooksCloseWorkaround : ProjectManagerListener {
override fun projectClosingBeforeSave(project: Project) {
val close = injector.optionService.getOptionValue(OptionScope.GLOBAL, "closenotebooks").asBoolean()
if (close) {
localEditors().forEach { editor ->
val virtualFile = EditorHelper.getVirtualFile(editor)
if (virtualFile?.extension == "ipynb") {
val fileEditorManager = FileEditorManagerEx.getInstanceEx(project)
fileEditorManager.closeFile(virtualFile)
}
}
}
}
}

View File

@ -19,6 +19,8 @@ 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.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application; import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
@ -30,9 +32,9 @@ import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.intellij.openapi.keymap.impl.DefaultKeymap; import com.intellij.openapi.keymap.impl.DefaultKeymap;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project; 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.SystemInfo; import com.intellij.openapi.util.SystemInfo;
import com.maddyhome.idea.vim.api.VimInjectorKt; import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.api.VimKeyGroup; import com.maddyhome.idea.vim.api.VimKeyGroup;
@ -46,17 +48,20 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
import com.maddyhome.idea.vim.helper.MacKeyRepeat; import com.maddyhome.idea.vim.helper.MacKeyRepeat;
import com.maddyhome.idea.vim.listener.VimListenerManager; import com.maddyhome.idea.vim.listener.VimListenerManager;
import com.maddyhome.idea.vim.newapi.IjVimInjector; import com.maddyhome.idea.vim.newapi.IjVimInjector;
import com.maddyhome.idea.vim.options.OptionService;
import com.maddyhome.idea.vim.ui.StatusBarIconFactory; import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel; import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage; import com.maddyhome.idea.vim.vimscript.services.FunctionStorage;
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService; import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService;
import com.maddyhome.idea.vim.vimscript.services.OptionService; import com.maddyhome.idea.vim.vimscript.services.VimVariableService;
import com.maddyhome.idea.vim.vimscript.services.VariableService;
import org.jdom.Element; import org.jdom.Element;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import static com.maddyhome.idea.vim.group.EditorGroup.EDITOR_STORE_ELEMENT; import static com.maddyhome.idea.vim.group.EditorGroup.EDITOR_STORE_ELEMENT;
import static com.maddyhome.idea.vim.group.KeyGroup.SHORTCUT_CONFLICTS_ELEMENT; import static com.maddyhome.idea.vim.group.KeyGroup.SHORTCUT_CONFLICTS_ELEMENT;
import static com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc; import static com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc;
@ -89,8 +94,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
private final @NotNull VimState state = new VimState(); private final @NotNull VimState state = new VimState();
public Disposable onOffDisposable;
VimPlugin() { VimPlugin() {
ApplicationConfigurationMigrator.getInstance().migrate(); ApplicationConfigurationMigrator.getInstance().migrate();
} }
@ -114,7 +117,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
@Override @Override
public void dispose() { public void dispose() {
LOG.debug("disposeComponent"); LOG.debug("disposeComponent");
turnOffPlugin(false); turnOffPlugin();
LOG.debug("done"); LOG.debug("done");
} }
@ -223,8 +226,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
return (PutGroup)VimInjectorKt.getInjector().getPut(); return (PutGroup)VimInjectorKt.getInjector().getPut();
} }
public static @NotNull VariableService getVariableService() { public static @NotNull VimVariableService getVariableService() {
return ApplicationManager.getApplication().getService(VariableService.class); return ApplicationManager.getApplication().getService(VimVariableService.class);
} }
public static @NotNull OptionService getOptionService() { public static @NotNull OptionService getOptionService() {
@ -272,7 +275,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
if (isEnabled() == enabled) return; if (isEnabled() == enabled) return;
if (!enabled) { if (!enabled) {
getInstance().turnOffPlugin(true); getInstance().turnOffPlugin();
} }
getInstance().enabled = enabled; getInstance().enabled = enabled;
@ -338,8 +341,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
* execution, what theoretically may cause bugs (e.g. VIM-2540) * execution, what theoretically may cause bugs (e.g. VIM-2540)
*/ */
private void turnOnPlugin() { private void turnOnPlugin() {
onOffDisposable = Disposer.newDisposable(this, "IdeaVimOnOffDisposer");
// 1) Update state // 1) Update state
ApplicationManager.getApplication().invokeLater(this::updateState); ApplicationManager.getApplication().invokeLater(this::updateState);
@ -365,20 +366,16 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
VimListenerManager.INSTANCE.turnOn(); VimListenerManager.INSTANCE.turnOn();
} }
private void turnOffPlugin(boolean unsubscribe) { private void turnOffPlugin() {
SearchGroup searchGroup = getSearchIfCreated(); SearchGroup searchGroup = getSearchIfCreated();
if (searchGroup != null) { if (searchGroup != null) {
searchGroup.turnOff(); searchGroup.turnOff();
} }
if (unsubscribe) { VimListenerManager.INSTANCE.turnOff();
VimListenerManager.INSTANCE.turnOff();
}
ExEntryPanel.fullReset(); ExEntryPanel.fullReset();
// Unregister vim actions in command mode // Unregister vim actions in command mode
RegisterActions.unregisterActions(); RegisterActions.unregisterActions();
Disposer.dispose(onOffDisposable);
} }
private boolean stateUpdated = false; private boolean stateUpdated = false;
@ -392,9 +389,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
final Boolean enabled = keyRepeat.isEnabled(); final Boolean enabled = keyRepeat.isEnabled();
final Boolean isKeyRepeat = getEditor().isKeyRepeat(); final Boolean isKeyRepeat = getEditor().isKeyRepeat();
if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) { if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) {
// This system property is used in IJ ui robot to hide the startup tips if (VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) {
boolean showNotification = Boolean.getBoolean("ide.show.tips.on.startup.default.value");
if (showNotification && VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) {
getEditor().setKeyRepeat(true); getEditor().setKeyRepeat(true);
keyRepeat.setEnabled(true); keyRepeat.setEnabled(true);
} }
@ -413,6 +408,12 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
keymap = manager.getKeymap(DefaultKeymap.getInstance().getDefaultKeymapName()); keymap = manager.getKeymap(DefaultKeymap.getInstance().getDefaultKeymapName());
} }
assert keymap != null : "Default keymap not found"; assert keymap != null : "Default keymap not found";
VimPlugin.getNotifications().specialKeymap(keymap, new NotificationListener.Adapter() {
@Override
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
ShowSettingsUtil.getInstance().showSettingsDialog(null, VimEmulationConfigurable.class);
}
});
manager.setActiveKeymap(keymap); manager.setActiveKeymap(keymap);
} }
if (previousStateVersion > 0 && previousStateVersion < 4) { if (previousStateVersion > 0 && previousStateVersion < 4) {

View File

@ -19,7 +19,6 @@
package com.maddyhome.idea.vim.action package com.maddyhome.idea.vim.action
import com.intellij.openapi.actionSystem.ActionPlaces import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.project.DumbAwareToggleAction
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
@ -43,6 +42,4 @@ class VimPluginToggleAction : DumbAwareToggleAction()/*, LightEditCompatible*/ {
if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable") if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable")
} else MessageHelper.message("action.VimPluginToggle.text") } else MessageHelper.message("action.VimPluginToggle.text")
} }
override fun getActionUpdateThread() = ActionUpdateThread.BGT
} }

View File

@ -20,7 +20,6 @@ package com.maddyhome.idea.vim.action
import com.google.common.collect.ImmutableSet import com.google.common.collect.ImmutableSet
import com.intellij.codeInsight.lookup.LookupManager import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.EmptyAction import com.intellij.openapi.actionSystem.EmptyAction
@ -96,10 +95,6 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
} }
} }
// There is a chance that we can use BGT, but we call for isCell inside the update.
// Not sure if can can use BGT with this call. Let's use EDT for now.
override fun getActionUpdateThread() = ActionUpdateThread.EDT
override fun update(e: AnActionEvent) { override fun update(e: AnActionEvent) {
val start = if (traceTime) System.currentTimeMillis() else null val start = if (traceTime) System.currentTimeMillis() else null
e.presentation.isEnabled = isEnabled(e) e.presentation.isEnabled = isEnabled(e)

View File

@ -22,7 +22,6 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
@ -35,13 +34,13 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import java.util.* import java.util.*
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean { private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
val operatorFunction = injector.keyGroup.operatorFunction val operatorFunction = VimPlugin.getKey().operatorFunction
if (operatorFunction == null) { if (operatorFunction == null) {
VimPlugin.showMessage(MessageHelper.message("E774")) VimPlugin.showMessage(MessageHelper.message("E774"))
return false return false
@ -50,7 +49,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
val saveRepeatHandler = VimRepeater.repeatHandler val saveRepeatHandler = VimRepeater.repeatHandler
VimPlugin.getMark().setChangeMarks(editor, textRange) VimPlugin.getMark().setChangeMarks(editor, textRange)
KeyHandler.getInstance().reset(editor) KeyHandler.getInstance().reset(editor)
val result = operatorFunction.apply(editor, context, selectionType) val result = operatorFunction.apply(editor.ij, context.ij, selectionType)
VimRepeater.repeatHandler = saveRepeatHandler VimRepeater.repeatHandler = saveRepeatHandler
return result return result
} }

View File

@ -45,7 +45,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.SingleExecution() {
val res = arrayOf(true) val res = arrayOf(true)
editor.forEachNativeCaret( editor.forEachNativeCaret(
{ caret: VimCaret -> { caret: VimCaret ->
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)) res[0] = false if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false)) res[0] = false
}, },
true true
) )

View File

@ -45,7 +45,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
val res = arrayOf(true) val res = arrayOf(true)
editor.forEachNativeCaret( editor.forEachNativeCaret(
{ caret: VimCaret -> { caret: VimCaret ->
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) res[0] = false if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true)) res[0] = false
}, },
true true
) )

View File

@ -57,14 +57,7 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution(
caret: VimCaret -> caret: VimCaret ->
if (!caret.isValid) return@forEachNativeCaret if (!caret.isValid) return@forEachNativeCaret
val range = caretsAndSelections[caret] ?: return@forEachNativeCaret val range = caretsAndSelections[caret] ?: return@forEachNativeCaret
if (!injector.changeGroup.deleteJoinRange( if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), false)) {
editor,
caret,
range.toVimTextRange(true).normalize(),
false,
operatorArguments
)
) {
res[0] = false res[0] = false
} }
}, true }, true

View File

@ -56,14 +56,7 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec
{ caret: VimCaret -> { caret: VimCaret ->
if (!caret.isValid) return@forEachNativeCaret if (!caret.isValid) return@forEachNativeCaret
val range = caretsAndSelections[caret] ?: return@forEachNativeCaret val range = caretsAndSelections[caret] ?: return@forEachNativeCaret
if (!injector.changeGroup.deleteJoinRange( if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), true)) {
editor,
caret,
range.toVimTextRange(true).normalize(),
true,
operatorArguments
)
) {
res[0] = false res[0] = false
} }
}, },

View File

@ -18,7 +18,6 @@
package com.maddyhome.idea.vim.action.internal package com.maddyhome.idea.vim.action.internal
import com.intellij.ide.ui.AntialiasingType import com.intellij.ide.ui.AntialiasingType
import com.intellij.ide.ui.UISettings
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
@ -125,7 +124,7 @@ class AddBlockInlaysAction : AnAction() {
val editorContext = FontInfo.getFontRenderContext(editor.contentComponent) val editorContext = FontInfo.getFontRenderContext(editor.contentComponent)
return FontRenderContext( return FontRenderContext(
editorContext.transform, AntialiasingType.getKeyForCurrentScope(false), editorContext.transform, AntialiasingType.getKeyForCurrentScope(false),
if (editor is EditorImpl) UISettings.editorFractionalMetricsHint else RenderingHints.VALUE_FRACTIONALMETRICS_OFF if (editor is EditorImpl) editor.myFractionalMetricsHintValue else RenderingHints.VALUE_FRACTIONALMETRICS_OFF
) )
} }

View File

@ -24,22 +24,12 @@ import com.maddyhome.idea.vim.newapi.vim
/** /**
* COMPATIBILITY-LAYER: Additional class * COMPATIBILITY-LAYER: Additional class
* Please see: https://jb.gg/zo8n0r
*/ */
class CommandState(private val machine: VimStateMachine) { class CommandState(private val machine: VimStateMachine) {
val isOperatorPending: Boolean val isOperatorPending: Boolean
get() = machine.isOperatorPending get() = machine.isOperatorPending
val mode: CommandState.Mode
get() = machine.mode.ij
val commandBuilder: CommandBuilder
get() = machine.commandBuilder
val mappingState: MappingState
get() = machine.mappingState
enum class Mode { enum class Mode {
// Basic modes // Basic modes
COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/ COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/
@ -60,6 +50,7 @@ class CommandState(private val machine: VimStateMachine) {
} }
} }
val CommandState.SubMode.engine: VimStateMachine.SubMode val CommandState.SubMode.engine: VimStateMachine.SubMode
get() = when (this) { get() = when (this) {
CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE
@ -82,6 +73,7 @@ val CommandState.Mode.engine: VimStateMachine.Mode
CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT
} }
val VimStateMachine.Mode.ij: CommandState.Mode val VimStateMachine.Mode.ij: CommandState.Mode
get() = when (this) { get() = when (this) {
VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND

View File

@ -23,7 +23,6 @@ import com.intellij.openapi.editor.Editor
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.change.Extension import com.maddyhome.idea.vim.action.change.Extension
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.CommandAlias import com.maddyhome.idea.vim.common.CommandAlias
@ -60,9 +59,8 @@ object VimExtensionFacade {
} }
/** /**
* COMPATIBILITY-LAYER: Additional method * COMPATIBILITY-LAYER: Additional method
* Please see: https://jb.gg/zo8n0r */
*/
/** The 'map' command for mapping keys to handlers defined in extensions. */ /** The 'map' command for mapping keys to handlers defined in extensions. */
@JvmStatic @JvmStatic
fun putExtensionHandlerMapping( fun putExtensionHandlerMapping(
@ -127,7 +125,7 @@ object VimExtensionFacade {
/** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */ /** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */
@JvmStatic @JvmStatic
fun setOperatorFunction(function: OperatorFunction) { fun setOperatorFunction(function: OperatorFunction) {
VimPlugin.getKey().operatorFunction = function VimPlugin.getKey().setOperatorFunction(function)
} }
/** /**
@ -184,24 +182,12 @@ object VimExtensionFacade {
return reg.keys return reg.keys
} }
@JvmStatic
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
val reg = caret.registerStorage.getRegister(caret, register) ?: return null
return reg.keys
}
/** Set the current contents of the given register */ /** Set the current contents of the given register */
@JvmStatic @JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?) { fun setRegister(register: Char, keys: List<KeyStroke?>?) {
VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList()) VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList())
} }
/** Set the current contents of the given register */
@JvmStatic
fun setRegisterForCaret(register: Char, caret: VimCaret, keys: List<KeyStroke?>?) {
caret.registerStorage.setKeys(caret, register, keys?.filterNotNull() ?: emptyList())
}
/** Set the current contents of the given register */ /** Set the current contents of the given register */
@JvmStatic @JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) { fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) {

View File

@ -26,7 +26,6 @@ import com.maddyhome.idea.vim.newapi.ij
/** /**
* COMPATIBILITY-LAYER: Created a class, renamed original class * COMPATIBILITY-LAYER: Created a class, renamed original class
* Please see: https://jb.gg/zo8n0r
*/ */
interface VimExtensionHandler : ExtensionHandler { interface VimExtensionHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {

View File

@ -25,9 +25,9 @@ import com.maddyhome.idea.vim.api.VimExtensionRegistrator
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.OptionChangeListener import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.statistic.PluginState import com.maddyhome.idea.vim.statistic.PluginState
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType

View File

@ -17,11 +17,10 @@
*/ */
package com.maddyhome.idea.vim.extension.commentary package com.maddyhome.idea.vim.extension.commentary
import com.intellij.codeInsight.actions.AsyncActionExecutionService import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
@ -35,14 +34,13 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.TextObjectVisualType import com.maddyhome.idea.vim.command.TextObjectVisualType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.CommandAliasHandler import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
@ -50,6 +48,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.handler.TextObjectActionHandler import com.maddyhome.idea.vim.handler.TextObjectActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper import com.maddyhome.idea.vim.helper.PsiHelper
@ -57,65 +56,47 @@ import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.OperatorFunction import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import java.util.* import java.util.*
class CommentaryExtension : VimExtension { class CommentaryExtension : VimExtension {
companion object { companion object {
fun doCommentary( fun doCommentary(editor: VimEditor, context: ExecutionContext, range: TextRange, selectionType: SelectionType, resetCaret: Boolean): Boolean {
editor: VimEditor,
context: ExecutionContext,
range: TextRange,
selectionType: SelectionType,
resetCaret: Boolean,
): Boolean {
val mode = editor.vimStateMachine.mode val mode = editor.vimStateMachine.mode
if (mode !== VimStateMachine.Mode.VISUAL) { if (mode !== VimStateMachine.Mode.VISUAL) {
editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset) editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset)
} }
return runWriteAction { return runWriteAction {
// Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action try {
// isn't available // Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action
val actions = if (selectionType === SelectionType.LINE_WISE) { // isn't available
listOf(IdeActions.ACTION_COMMENT_LINE, IdeActions.ACTION_COMMENT_BLOCK) val actions = if (selectionType === SelectionType.LINE_WISE) {
} else { listOf(IdeActions.ACTION_COMMENT_LINE, IdeActions.ACTION_COMMENT_BLOCK)
listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE) } else {
listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE)
}
injector.actionExecutor.executeAction(actions[0], context) ||
injector.actionExecutor.executeAction(actions[1], context)
} finally {
// Remove the selection, if we added it
if (mode !== VimStateMachine.Mode.VISUAL) {
editor.removeSelection()
}
// Put the caret back at the start of the range, as though it was moved by the operator's motion argument.
// This is what Vim does. If IntelliJ is configured to add comments at the start of the line, this might put
// the caret in the "wrong" place. E.g. gc_ should put the caret on the first non-whitespace character. This
// is calculated by the motion, saved in the marks, and then we insert the comment. If it's inserted at the
// first non-whitespace character, then the caret is in the right place. If it's inserted at the first column,
// then the caret is now in a bit of a weird place. We can't detect this scenario, so we just have to accept
// the difference
if (resetCaret) {
editor.primaryCaret().moveToOffset(range.startOffset)
}
} }
val res = Ref.create<Boolean>(true)
AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[0], {
res.set(injector.actionExecutor.executeAction(actions[0], context))
}, { afterCommenting(mode, editor, resetCaret, range) })
if (!res.get()) {
AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[1], {
res.set(injector.actionExecutor.executeAction(actions[1], context))
}, { afterCommenting(mode, editor, resetCaret, range) })
}
res.get()
}
}
private fun afterCommenting(
mode: VimStateMachine.Mode,
editor: VimEditor,
resetCaret: Boolean,
range: TextRange,
) {
// Remove the selection, if we added it
if (mode !== VimStateMachine.Mode.VISUAL) {
editor.removeSelection()
}
// Put the caret back at the start of the range, as though it was moved by the operator's motion argument.
// This is what Vim does. If IntelliJ is configured to add comments at the start of the line, this might put
// the caret in the "wrong" place. E.g. gc_ should put the caret on the first non-whitespace character. This
// is calculated by the motion, saved in the marks, and then we insert the comment. If it's inserted at the
// first non-whitespace character, then the caret is in the right place. If it's inserted at the first column,
// then the caret is now in a bit of a weird place. We can't detect this scenario, so we just have to accept
// the difference
if (resetCaret) {
editor.primaryCaret().moveToOffset(range.startOffset)
} }
} }
} }
@ -131,13 +112,7 @@ class CommentaryExtension : VimExtension {
putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("gc"), owner, plugCommentaryKeys, true) putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("gc"), owner, plugCommentaryKeys, true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcc"), owner, plugCommentaryLineKeys, true) putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcc"), owner, plugCommentaryLineKeys, true)
putKeyMappingIfMissing( putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcu"), owner, injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"), true)
MappingMode.N,
injector.parser.parseKeys("gcu"),
owner,
injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"),
true
)
// Previous versions of IdeaVim used different mappings to Vim's Commentary. Make sure everything works if someone // Previous versions of IdeaVim used different mappings to Vim's Commentary. Make sure everything works if someone
// is still using the old mapping // is still using the old mapping
@ -157,19 +132,14 @@ class CommentaryExtension : VimExtension {
private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler { private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler {
override val isRepeatable = true override val isRepeatable = true
// In this operator we process selection by ourselves. This is necessary for rider, VIM-1758
override fun postProcessSelection(): Boolean {
return false
}
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {
setOperatorFunction(this) setOperatorFunction(this)
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
} }
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val range = VimPlugin.getMark().getChangeMarks(editor) ?: return false val range = VimPlugin.getMark().getChangeMarks(editor.vim) ?: return false
return doCommentary(editor, context, range, selectionType, true) return doCommentary(editor.vim, context.vim, range, selectionType, true)
} }
} }
@ -204,7 +174,7 @@ class CommentaryExtension : VimExtension {
context: ExecutionContext, context: ExecutionContext,
count: Int, count: Int,
rawCount: Int, rawCount: Int,
argument: Argument?, argument: Argument?
): TextRange? { ): TextRange? {
val nativeEditor = (editor as IjVimEditor).editor val nativeEditor = (editor as IjVimEditor).editor

View File

@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.extension.exchange package com.maddyhome.idea.vim.extension.exchange
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.LogicalPosition import com.intellij.openapi.editor.LogicalPosition
@ -30,11 +31,10 @@ 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.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
@ -42,6 +42,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition
@ -132,7 +133,7 @@ class VimExchangeExtension : VimExtension {
val subMode = editor.subMode val subMode = editor.subMode
// Leave visual mode to create selection marks // Leave visual mode to create selection marks
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
Operator(true).apply(editor, context, SelectionType.fromSubMode(subMode)) Operator(true).apply(editor.ij, context.ij, SelectionType.fromSubMode(subMode))
} }
} }
} }
@ -146,8 +147,7 @@ class VimExchangeExtension : VimExtension {
else -> error("Invalid SubMode: $this") else -> error("Invalid SubMode: $this")
} }
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val editor = vimEditor.ij
fun highlightExchange(ex: Exchange): RangeHighlighter { fun highlightExchange(ex: Exchange): RangeHighlighter {
val attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES) val attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES)
val hlArea = when (ex.type) { val hlArea = when (ex.type) {

View File

@ -33,21 +33,21 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
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.Direction import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.handler.Motion import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotionOrError import com.maddyhome.idea.vim.handler.toMotionOrError
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
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 java.util.* import java.util.*

View File

@ -29,8 +29,8 @@ 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.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension

View File

@ -21,7 +21,6 @@ package com.maddyhome.idea.vim.extension.nerdtree
import com.intellij.ide.projectView.ProjectView import com.intellij.ide.projectView.ProjectView
import com.intellij.ide.projectView.impl.ProjectViewImpl import com.intellij.ide.projectView.impl.ProjectViewImpl
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
@ -45,18 +44,18 @@ import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.CommandAlias import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.common.addLeafs
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.VimExtension 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.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.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
@ -173,7 +172,7 @@ class NerdTree : VimExtension {
} }
class ProjectViewListener(private val project: Project) : ToolWindowManagerListener { class ProjectViewListener(private val project: Project) : ToolWindowManagerListener {
override fun toolWindowShown(toolWindow: ToolWindow) { override fun toolWindowShown(id: String, toolWindow: ToolWindow) {
if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return
val dispatcher = NerdDispatcher.getInstance(project) val dispatcher = NerdDispatcher.getInstance(project)
@ -243,8 +242,6 @@ class NerdTree : VimExtension {
e.presentation.isEnabled = !speedSearchIsHere(project) e.presentation.isEnabled = !speedSearchIsHere(project)
} }
override fun getActionUpdateThread() = ActionUpdateThread.EDT
private fun speedSearchIsHere(project: Project): Boolean { private fun speedSearchIsHere(project: Project): Boolean {
val component = ProjectView.getInstance(project).currentProjectViewPane.tree ?: return false val component = ProjectView.getInstance(project).currentProjectViewPane.tree ?: return false
return SpeedSearchSupply.getSupply(component) != null return SpeedSearchSupply.getSupply(component) != null
@ -345,7 +342,7 @@ class NerdTree : VimExtension {
if (file.isDirectory) return@Code if (file.isDirectory) return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow val currentWindow = splitters.currentWindow
currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true) currentWindow.split(SwingConstants.HORIZONTAL, true, file, true)
} }
) )
registerCommand( registerCommand(
@ -354,7 +351,7 @@ class NerdTree : VimExtension {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow val currentWindow = splitters.currentWindow
currentWindow?.split(SwingConstants.VERTICAL, true, file, true) currentWindow.split(SwingConstants.VERTICAL, true, file, true)
// FIXME: 22.01.2021 This solution bouncing a bit // FIXME: 22.01.2021 This solution bouncing a bit
callAction("ActivateProjectToolWindow", context.vim) callAction("ActivateProjectToolWindow", context.vim)
@ -366,7 +363,7 @@ class NerdTree : VimExtension {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow val currentWindow = splitters.currentWindow
currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true) currentWindow.split(SwingConstants.HORIZONTAL, true, file, true)
callAction("ActivateProjectToolWindow", context.vim) callAction("ActivateProjectToolWindow", context.vim)
} }
@ -563,3 +560,7 @@ class NerdTree : VimExtension {
} }
} }
} }
private fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder)
}

View File

@ -24,10 +24,10 @@ 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.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.SearchHelper import com.maddyhome.idea.vim.helper.SearchHelper

View File

@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.extension.replacewithregister package com.maddyhome.idea.vim.extension.replacewithregister
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
@ -25,7 +26,6 @@ import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.isLine import com.maddyhome.idea.vim.command.isLine
@ -38,10 +38,8 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissin
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.group.visual.VimSelection import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.helper.EditorDataContext import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.mode import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.subMode import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.OperatorFunction import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjExecutionContext import com.maddyhome.idea.vim.newapi.IjExecutionContext
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
@ -67,14 +65,15 @@ class ReplaceWithRegister : VimExtension {
private class RwrVisual : ExtensionHandler { private class RwrVisual : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {
val caretsAndSelections = mutableMapOf<VimCaret, VimSelection>()
val typeInEditor = SelectionType.fromSubMode(editor.subMode) val typeInEditor = SelectionType.fromSubMode(editor.subMode)
editor.forEachCaret { caret -> editor.forEachCaret { caret ->
val selectionStart = caret.selectionStart val selectionStart = caret.selectionStart
val selectionEnd = caret.selectionEnd val selectionEnd = caret.selectionEnd
val visualSelection = caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor) caretsAndSelections += caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor)
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), typeInEditor))
} }
doReplace(editor.ij, PutData.VisualSelection(caretsAndSelections, typeInEditor))
editor.exitVisualModeNative() editor.exitVisualModeNative()
} }
} }
@ -98,12 +97,12 @@ class ReplaceWithRegister : VimExtension {
val lineStart = editor.getLineStartOffset(logicalLine) val lineStart = editor.getLineStartOffset(logicalLine)
val lineEnd = editor.getLineEndOffset(logicalLine, true) val lineEnd = editor.getLineEndOffset(logicalLine, true)
val visualSelection = caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor) caretsAndSelections += caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor)
caretsAndSelections += visualSelection
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), SelectionType.LINE_WISE))
} }
val visualSelection = PutData.VisualSelection(caretsAndSelections, SelectionType.LINE_WISE)
doReplace(editor.ij, visualSelection)
editor.forEachCaret { caret -> editor.forEachCaret { caret ->
val vimStart = caretsAndSelections[caret]?.vimStart val vimStart = caretsAndSelections[caret]?.vimStart
if (vimStart != null) { if (vimStart != null) {
@ -114,22 +113,20 @@ class ReplaceWithRegister : VimExtension {
} }
private class Operator : OperatorFunction { private class Operator : OperatorFunction {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val editor = (vimEditor as IjVimEditor).editor
val range = getRange(editor) ?: return false val range = getRange(editor) ?: return false
val visualSelection = PutData.VisualSelection( val visualSelection = PutData.VisualSelection(
mapOf( mapOf(
vimEditor.primaryCaret() to VimSelection.create( editor.caretModel.primaryCaret.vim to VimSelection.create(
range.startOffset, range.startOffset,
range.endOffset - 1, range.endOffset - 1,
selectionType, selectionType,
vimEditor IjVimEditor(editor)
) )
), ),
selectionType selectionType
) )
// todo multicaret doReplace(editor, visualSelection)
doReplace(editor, vimEditor.primaryCaret(), visualSelection)
return true return true
} }
@ -150,9 +147,8 @@ class ReplaceWithRegister : VimExtension {
@NonNls @NonNls
private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual" private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
private fun doReplace(editor: Editor, caret: VimCaret, visualSelection: PutData.VisualSelection) { private fun doReplace(editor: Editor, visualSelection: PutData.VisualSelection) {
val lastRegisterChar = injector.registerGroup.lastRegisterChar val savedRegister = VimPlugin.getRegister().lastRegister ?: return
val savedRegister = caret.registerStorage.getRegister(caret, lastRegisterChar) ?: return
var usedType = savedRegister.type var usedType = savedRegister.type
var usedText = savedRegister.text var usedText = savedRegister.text
@ -174,19 +170,11 @@ class ReplaceWithRegister : VimExtension {
putToLine = -1 putToLine = -1
) )
ClipboardOptionHelper.IdeaputDisabler().use { ClipboardOptionHelper.IdeaputDisabler().use {
VimPlugin.getPut().putText( VimPlugin.getPut().putText(IjVimEditor(editor), IjExecutionContext(EditorDataContext.init(editor)), putData)
IjVimEditor(editor),
IjExecutionContext(EditorDataContext.init(editor)),
putData,
operatorArguments = OperatorArguments(
editor.vimStateMachine?.isOperatorPending ?: false,
0, editor.editorMode, editor.subMode
)
)
} }
caret.registerStorage.saveRegister(caret, savedRegister.name, savedRegister) VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister)
caret.registerStorage.saveRegister(caret, VimPlugin.getRegister().defaultRegister, savedRegister) VimPlugin.getRegister().saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister)
} }
} }
} }

View File

@ -17,11 +17,11 @@
*/ */
package com.maddyhome.idea.vim.extension.surround package com.maddyhome.idea.vim.extension.surround
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimChangeGroup import com.maddyhome.idea.vim.api.VimChangeGroup
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
@ -32,13 +32,14 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegisterForCaret import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.editorMode import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
import com.maddyhome.idea.vim.key.OperatorFunction import com.maddyhome.idea.vim.key.OperatorFunction
@ -47,7 +48,6 @@ import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
import com.maddyhome.idea.vim.put.PutData
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
@ -94,7 +94,7 @@ class VimSurroundExtension : VimExtension {
private class VSurroundHandler : ExtensionHandler { private class VSurroundHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {
// NB: Operator ignores SelectionType anyway // NB: Operator ignores SelectionType anyway
if (!Operator(supportsMultipleCursors = true).apply(editor, context, SelectionType.CHARACTER_WISE)) { if (!Operator(supportsMultipleCursors = true).apply(editor.ij, context.ij, SelectionType.CHARACTER_WISE)) {
return return
} }
runWriteAction { runWriteAction {
@ -115,74 +115,37 @@ class VimSurroundExtension : VimExtension {
if (charTo.code == 0) return if (charTo.code == 0) return
val newSurround = getOrInputPair(charTo, editor.ij) ?: return val newSurround = getOrInputPair(charTo, editor.ij) ?: return
runWriteAction { change(editor, context, charFrom, newSurround) } runWriteAction { change(editor.ij, charFrom, newSurround) }
} }
companion object { companion object {
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { fun change(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) } editor.runWithEveryCaretAndRestore { changeAtCaret(editor, charFrom, newSurround) }
} }
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { fun changeAtCaret(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets // We take over the " register, so preserve it
val surroundings = editor.sortedCarets() val oldValue: List<KeyStroke>? = getRegister(REGISTER)
.map { // Empty the " register
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it) setRegister(REGISTER, null)
setRegisterForCaret(REGISTER, it, null) // Extract the inner value
SurroundingInfo(it, null, oldValue, null) perform("di" + pick(charFrom), editor)
} val innerValue: MutableList<KeyStroke> = getRegister(REGISTER)?.toMutableList() ?: mutableListOf()
// If the surrounding characters were not found, the register will be empty
// Delete surrounding's content if (innerValue.isNotEmpty()) {
perform("di" + pick(charFrom), editor.ij) // Delete the surrounding
perform("da" + pick(charFrom), editor)
// Add info about surrounding's inner text and location // Insert the surrounding characters and paste
surroundings.forEach { if (newSurround != null) {
val registerValue = getRegisterForCaret(REGISTER, it.caret) innerValue.addAll(0, injector.parser.parseKeys(newSurround.first))
val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue innerValue.addAll(injector.parser.parseKeys(newSurround.second))
it.innerText = innerValue
val lineEndOffset = injector.engineEditorHelper.getLineEndOffset(editor, it.caret.getLine().line, false)
if (lineEndOffset == it.caret.offset.point) {
it.isLineEnd = true
} }
pasteSurround(innerValue, editor)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
} }
// Restore the old value
// Remove surrounding setRegister(REGISTER, oldValue)
perform("da" + pick(charFrom), editor.ij)
surroundings.forEach {
if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
it.innerText = emptyList()
}
// caret should be placed at the first char of inserted text
// the best solution would be using [ mark after the paste, but marks are not supported by multicaret
// todo
if (it.innerText != null) {
it.offset = it.caret.offset.point
}
}
surroundings
.filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
.map { surrounding ->
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList())
val putData = PutData(textData, null, 1, insertTextBeforeCaret = !surrounding.isLineEnd, rawIndent = true, caretAfterInsertedText = false)
surrounding.caret to putData
}.forEach {
injector.put.putTextForCaret(editor, it.first, context, it.second)
}
surroundings.forEach {
it.restoreRegister()
}
if (surroundings.size == 1) {
surroundings.first().moveCaret()
}
} }
private fun perform(sequence: String, editor: Editor) { private fun perform(sequence: String, editor: Editor) {
@ -190,6 +153,21 @@ class VimSurroundExtension : VimExtension {
.use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) } .use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) }
} }
private fun pasteSurround(
innerValue: List<KeyStroke?>,
editor: Editor,
) { // This logic is direct from vim-surround
val offset = editor.caretModel.offset
val lineEndOffset = EditorHelper.getLineEndForOffset(editor, offset)
val motionEndMark = VimPlugin.getMark().getMark(editor.vim, ']')
val motionEndOffset = if (motionEndMark != null) {
EditorHelper.getOffset(editor, motionEndMark.logicalLine, motionEndMark.col)
} else -1
val pasteCommand = if (motionEndOffset == lineEndOffset && offset + 1 == lineEndOffset) "p" else "P"
setRegister(REGISTER, innerValue)
perform(pasteCommand, editor)
}
private fun pick(charFrom: Char) = when (charFrom) { private fun pick(charFrom: Char) = when (charFrom) {
'a' -> '>' 'a' -> '>'
'r' -> ']' 'r' -> ']'
@ -198,18 +176,6 @@ class VimSurroundExtension : VimExtension {
} }
} }
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var offset: Int?, var isLineEnd: Boolean = false) {
fun restoreRegister() {
setRegisterForCaret(REGISTER, caret, oldRegisterContent)
}
fun moveCaret() {
if (innerText != null && offset != null) {
caret.moveToOffset(offset!! + if (isLineEnd) 1 else 0)
}
}
}
private class DSurroundHandler : ExtensionHandler { private class DSurroundHandler : ExtensionHandler {
override val isRepeatable = true override val isRepeatable = true
@ -218,13 +184,12 @@ class VimSurroundExtension : VimExtension {
val charFrom = getChar(editor.ij) val charFrom = getChar(editor.ij)
if (charFrom.code == 0) return if (charFrom.code == 0) return
runWriteAction { CSurroundHandler.change(editor, context, charFrom, null) } runWriteAction { CSurroundHandler.change(editor.ij, charFrom, null) }
} }
} }
private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction { private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val editor = vimEditor.ij
val c = getChar(editor) val c = getChar(editor)
if (c.code == 0) return true if (c.code == 0) return true

View File

@ -20,10 +20,7 @@ package com.maddyhome.idea.vim.group;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.codeInsight.actions.AsyncActionExecutionService;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.UndoConfirmationPolicy;
@ -36,9 +33,6 @@ import com.intellij.openapi.editor.event.EditorMouseEvent;
import com.intellij.openapi.editor.event.EditorMouseListener; import com.intellij.openapi.editor.event.EditorMouseListener;
import com.intellij.openapi.editor.impl.TextRangeInterval; import com.intellij.openapi.editor.impl.TextRangeInterval;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleManager;
@ -54,7 +48,6 @@ import com.maddyhome.idea.vim.ex.ranges.LineRange;
import com.maddyhome.idea.vim.group.visual.VimSelection; import com.maddyhome.idea.vim.group.visual.VimSelection;
import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt; import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.icons.VimIcons;
import com.maddyhome.idea.vim.key.KeyHandlerKeeper; import com.maddyhome.idea.vim.key.KeyHandlerKeeper;
import com.maddyhome.idea.vim.listener.VimInsertListener; import com.maddyhome.idea.vim.listener.VimInsertListener;
import com.maddyhome.idea.vim.newapi.IjExecutionContext; import com.maddyhome.idea.vim.newapi.IjExecutionContext;
@ -65,8 +58,6 @@ import com.maddyhome.idea.vim.options.OptionConstants;
import com.maddyhome.idea.vim.options.OptionScope; import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString; import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString;
import kotlin.Pair; import kotlin.Pair;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.text.StringsKt; import kotlin.text.StringsKt;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -97,8 +88,6 @@ public class ChangeGroup extends VimChangeGroupBase {
private final List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private long lastShownTime = 0L;
/** /**
* Inserts a new line above the caret position * Inserts a new line above the caret position
* *
@ -156,12 +145,14 @@ public class ChangeGroup extends VimChangeGroupBase {
} }
}; };
public void editorCreated(Editor editor, @NotNull Disposable disposable) { @Override
EventFacade.getInstance().addEditorMouseListener(editor, listener, disposable); public void editorCreated(VimEditor editor) {
EventFacade.getInstance().addEditorMouseListener(((IjVimEditor) editor).getEditor(), listener);
} }
public void editorReleased(Editor editor) { @Override
EventFacade.getInstance().removeEditorMouseListener(editor, listener); public void editorReleased(VimEditor editor) {
EventFacade.getInstance().removeEditorMouseListener(((IjVimEditor) editor).getEditor(), listener);
} }
@Override @Override
@ -212,6 +203,61 @@ public class ChangeGroup extends VimChangeGroupBase {
return new Pair<>(range, type); return new Pair<>(range, type);
} }
/**
* Delete the range of text.
*
* @param editor The editor to delete the text from
* @param caret The caret to be moved after deletion
* @param range The range to delete
* @param type The type of deletion
* @param isChange Is from a change action
* @return true if able to delete the text, false if not
*/
@Override
public boolean deleteRange(@NotNull VimEditor editor,
@NotNull VimCaret caret,
@NotNull TextRange range,
@Nullable SelectionType type,
boolean isChange,
boolean noYank) {
// Update the last column before we delete, or we might be retrieving the data for a line that no longer exists
UserDataManager.setVimLastColumn(((IjVimCaret) caret).getCaret(), InlayHelperKt.getInlayAwareVisualColumn(((IjVimCaret) caret).getCaret()));
boolean removeLastNewLine = removeLastNewLine(editor, range, type);
final boolean res = deleteText(editor, range, type, noYank);
if (removeLastNewLine) {
int textLength = ((IjVimEditor) editor).getEditor().getDocument().getTextLength();
((IjVimEditor) editor).getEditor().getDocument().deleteString(textLength - 1, textLength);
}
if (res) {
int pos = EditorHelper.normalizeOffset(((IjVimEditor) editor).getEditor(), range.getStartOffset(), isChange);
if (type == SelectionType.LINE_WISE) {
pos = VimPlugin.getMotion()
.moveCaretToLineWithStartOfLineOption(editor, editor.offsetToLogicalPosition(pos).getLine(),
caret);
}
injector.getMotion().moveCaret(editor, caret, pos);
}
return res;
}
private boolean removeLastNewLine(@NotNull VimEditor editor, @NotNull TextRange range, @Nullable SelectionType type) {
int endOffset = range.getEndOffset();
int fileSize = EditorHelperRt.getFileSize(((IjVimEditor) editor).getEditor());
if (endOffset > fileSize) {
if (injector.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, OptionConstants.ideastrictmodeName, OptionConstants.ideastrictmodeName)) {
throw new IllegalStateException("Incorrect offset. File size: " + fileSize + ", offset: " + endOffset);
}
endOffset = fileSize;
}
return type == SelectionType.LINE_WISE &&
range.getStartOffset() != 0 &&
((IjVimEditor) editor).getEditor().getDocument().getCharsSequence().charAt(endOffset - 1) != '\n' &&
endOffset == fileSize;
}
@Override @Override
public void insertLineAround(@NotNull VimEditor editor, @NotNull ExecutionContext context, int shift) { public void insertLineAround(@NotNull VimEditor editor, @NotNull ExecutionContext context, int shift) {
com.maddyhome.idea.vim.newapi.ChangeGroupKt.insertLineAround(editor, context, shift); com.maddyhome.idea.vim.newapi.ChangeGroupKt.insertLineAround(editor, context, shift);
@ -240,7 +286,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret, @NotNull VimCaret caret,
@NotNull ExecutionContext context, @NotNull ExecutionContext context,
@NotNull Argument argument, @NotNull Argument argument,
@NotNull OperatorArguments operatorArguments) { @NotNull OperatorArguments operatorArguments,
boolean noYank) {
int count0 = operatorArguments.getCount0(); int count0 = operatorArguments.getCount0();
// Vim treats cw as ce and cW as cE if cursor is on a non-blank character // Vim treats cw as ce and cW as cE if cursor is on a non-blank character
final Command motion = argument.getMotion(); final Command motion = argument.getMotion();
@ -257,7 +304,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final boolean lastWordChar = final boolean lastWordChar =
offset >= fileSize - 1 || CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType; offset >= fileSize - 1 || CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType;
if (wordMotions.contains(id) && lastWordChar && motion.getCount() == 1) { if (wordMotions.contains(id) && lastWordChar && motion.getCount() == 1) {
final boolean res = deleteCharacter(editor, caret, 1, true, operatorArguments); final boolean res = deleteCharacter(editor, caret, 1, true);
if (res) { if (res) {
editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT); editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT);
} }
@ -318,8 +365,7 @@ public class ChangeGroup extends VimChangeGroupBase {
Pair<TextRange, SelectionType> deleteRangeAndType = Pair<TextRange, SelectionType> deleteRangeAndType =
getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0)); getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0));
if (deleteRangeAndType == null) return false; if (deleteRangeAndType == null) return false;
return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context, return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context, noYank);
operatorArguments);
} }
} }
@ -438,11 +484,10 @@ public class ChangeGroup extends VimChangeGroupBase {
/** /**
* Deletes the range of text and enters insert mode * Deletes the range of text and enters insert mode
* *
* @param editor The editor to change * @param editor The editor to change
* @param caret The caret to be moved after range deletion * @param caret The caret to be moved after range deletion
* @param range The range to change * @param range The range to change
* @param type The type of the range * @param type The type of the range
* @param operatorArguments
* @return true if able to delete the range, false if not * @return true if able to delete the range, false if not
*/ */
@Override @Override
@ -451,7 +496,7 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull TextRange range, @NotNull TextRange range,
@NotNull SelectionType type, @NotNull SelectionType type,
@Nullable ExecutionContext context, @Nullable ExecutionContext context,
@NotNull OperatorArguments operatorArguments) { boolean noYank) {
int col = 0; int col = 0;
int lines = 0; int lines = 0;
if (type == SelectionType.BLOCK_WISE) { if (type == SelectionType.BLOCK_WISE) {
@ -465,7 +510,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret)); final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret));
boolean res = deleteRange(editor, caret, range, type, true, operatorArguments); boolean res = deleteRange(editor, caret, range, type, true, noYank);
if (res) { if (res) {
if (type == SelectionType.LINE_WISE) { if (type == SelectionType.LINE_WISE) {
// Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String // Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String
@ -583,31 +628,17 @@ public class ChangeGroup extends VimChangeGroupBase {
final int startOffset = injector.getEngineEditorHelper().getLineStartForOffset(editor, range.getStartOffset()); final int startOffset = injector.getEngineEditorHelper().getLineStartForOffset(editor, range.getStartOffset());
final int endOffset = injector.getEngineEditorHelper().getLineEndForOffset(editor, range.getEndOffset()); final int endOffset = injector.getEngineEditorHelper().getLineEndForOffset(editor, range.getEndOffset());
Editor ijEditor = ((IjVimEditor)editor).getEditor(); VisualModeHelperKt.vimSetSystemSelectionSilently(((IjVimEditor) editor).getEditor().getSelectionModel(), startOffset, endOffset);
VisualModeHelperKt.vimSetSystemSelectionSilently(ijEditor.getSelectionModel(), startOffset, endOffset);
Project project = ijEditor.getProject(); NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines();
Function0<Unit> actionExecution = () -> { if (joinLinesAction != null) {
NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines(); VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context);
if (joinLinesAction != null) {
VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context);
}
return null;
};
Function0<Unit> afterAction = () -> {
final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine();
final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine);
injector.getMotion().moveCaret(editor, caret, newOffset);
restoreCursor(editor, caret, ((IjVimCaret)caret).getCaret().getLogicalPosition().line);
return null;
};
if (project != null) {
AsyncActionExecutionService.Companion.getInstance(project)
.withExecutionAfterAction(IdeActions.ACTION_EDITOR_AUTO_INDENT_LINES, actionExecution, afterAction);
} else {
actionExecution.invoke();
afterAction.invoke();
} }
final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine();
final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine);
injector.getMotion().moveCaret(editor, caret, newOffset);
restoreCursor(editor, caret, ((IjVimCaret) caret).getCaret().getLogicalPosition().line);
} }
@Override @Override
@ -615,11 +646,10 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret, @NotNull VimCaret caret,
@NotNull ExecutionContext context, @NotNull ExecutionContext context,
int lines, int lines,
int dir, int dir) {
@NotNull OperatorArguments operatorArguments) {
int start = ((IjVimCaret) caret).getCaret().getOffset(); int start = ((IjVimCaret) caret).getCaret().getOffset();
int end = VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret, lines - 1, true); int end = VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret, lines - 1, true);
indentRange(editor, caret, context, new TextRange(start, end), 1, dir, operatorArguments); indentRange(editor, caret, context, new TextRange(start, end), 1, dir);
} }
@Override @Override
@ -632,7 +662,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final TextRange range = final TextRange range =
injector.getMotion().getMotionRange(editor, caret, context, argument, operatorArguments); injector.getMotion().getMotionRange(editor, caret, context, argument, operatorArguments);
if (range != null) { if (range != null) {
indentRange(editor, caret, context, range, 1, dir, operatorArguments); indentRange(editor, caret, context, range, 1, dir);
} }
} }
@ -659,8 +689,7 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull ExecutionContext context, @NotNull ExecutionContext context,
@NotNull TextRange range, @NotNull TextRange range,
int count, int count,
int dir, int dir) {
@NotNull OperatorArguments operatorArguments) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("count=" + count); logger.debug("count=" + count);
} }
@ -706,7 +735,7 @@ public class ChangeGroup extends VimChangeGroupBase {
} }
} }
if (pos > wsoff) { if (pos > wsoff) {
deleteText(editor, new TextRange(wsoff, pos), null, caret, operatorArguments); deleteText(editor, new TextRange(wsoff, pos), null, false);
} }
} }
} }
@ -799,23 +828,6 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull TextRange selectedRange, @NotNull TextRange selectedRange,
final int count, final int count,
boolean avalanche) { boolean avalanche) {
// Just an easter egg
if (avalanche) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastShownTime > 60_000) {
lastShownTime = currentTime;
ApplicationManager.getApplication().invokeLater(() -> {
final Balloon balloon = JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder("Wow, nice vim skills!", VimIcons.IDEAVIM,
MessageType.INFO.getTitleForeground(), MessageType.INFO.getPopupBackground(),
null).createBalloon();
balloon.show(JBPopupFactory.getInstance().guessBestPopupLocation(((IjVimEditor)editor).getEditor()),
Balloon.Position.below);
});
}
}
String nf = ((VimString) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(editor), OptionConstants.nrformatsName, OptionConstants.nrformatsName)).getValue(); String nf = ((VimString) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(editor), OptionConstants.nrformatsName, OptionConstants.nrformatsName)).getValue();
boolean alpha = nf.contains("alpha"); boolean alpha = nf.contains("alpha");
boolean hex = nf.contains("hex"); boolean hex = nf.contains("hex");

View File

@ -232,7 +232,7 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
KeyHandler.getInstance().reset(new IjVimEditor(editor)); KeyHandler.getInstance().reset(new IjVimEditor(editor));
} }
updateCaretsVisualAttributes(editor); updateCaretsVisualAttributes(editor);
//editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE); editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
} }
public void editorDeinit(@NotNull Editor editor, boolean isReleased) { public void editorDeinit(@NotNull Editor editor, boolean isReleased) {

View File

@ -20,7 +20,6 @@ package com.maddyhome.idea.vim.group;
import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
@ -28,7 +27,6 @@ import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorWindow; import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
@ -161,10 +159,6 @@ public class FileGroup extends VimFileBase {
if (virtualFile != null && window != null) { if (virtualFile != null && window != null) {
window.closeFile(virtualFile); window.closeFile(virtualFile);
} }
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// This thing doesn't have an implementation in test mode
EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project);
}
} }
} }
@ -181,10 +175,6 @@ public class FileGroup extends VimFileBase {
if (number >= 0 && number < editors.length) { if (number >= 0 && number < editors.length) {
fileEditorManager.closeFile(editors[number], window); fileEditorManager.closeFile(editors[number], window);
} }
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// This thing doesn't have an implementation in test mode
EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project);
}
} }
/** /**

View File

@ -36,7 +36,6 @@ class IjVimStorageService : VimStorageServiceBase() {
editor.ij.putUserData(getOrCreateIjKey(key), data) editor.ij.putUserData(getOrCreateIjKey(key), data)
} }
@Suppress("UNCHECKED_CAST")
override fun <T> getDataFromBuffer(editor: VimEditor, key: com.maddyhome.idea.vim.api.Key<T>): T? { override fun <T> getDataFromBuffer(editor: VimEditor, key: com.maddyhome.idea.vim.api.Key<T>): T? {
val buffer = EditorHelper.getVirtualFile(editor.ij)?.path ?: "empty path" val buffer = EditorHelper.getVirtualFile(editor.ij)?.path ?: "empty path"
return bufferToKey[buffer]?.get(key.name) as T? return bufferToKey[buffer]?.get(key.name) as T?
@ -61,7 +60,6 @@ class IjVimStorageService : VimStorageServiceBase() {
} }
private val ijKeys = mutableMapOf<String, Key<out Any?>>() private val ijKeys = mutableMapOf<String, Key<out Any?>>()
@Suppress("UNCHECKED_CAST")
private fun <T> getOrCreateIjKey(key: com.maddyhome.idea.vim.api.Key<T>): Key<T> { private fun <T> getOrCreateIjKey(key: com.maddyhome.idea.vim.api.Key<T>): Key<T> {
val storedIjKey = ijKeys[key.name] val storedIjKey = ijKeys[key.name]
if (storedIjKey != null) { if (storedIjKey != null) {

View File

@ -38,7 +38,8 @@ import com.maddyhome.idea.vim.action.ComplicatedKeysAction;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction; import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.api.*; import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.MappingMode; import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.key.Node; import com.maddyhome.idea.vim.common.Node;
import com.maddyhome.idea.vim.common.NodesKt;
import com.maddyhome.idea.vim.ex.ExOutputModel; import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase; import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.HelperKt; import com.maddyhome.idea.vim.helper.HelperKt;
@ -73,6 +74,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
private static final Logger logger = Logger.getInstance(KeyGroup.class); private static final Logger logger = Logger.getInstance(KeyGroup.class);
private @Nullable OperatorFunction operatorFunction = null;
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()),
@ -117,6 +120,14 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
} }
} }
public @Nullable OperatorFunction getOperatorFunction() {
return operatorFunction;
}
public void setOperatorFunction(@NotNull OperatorFunction function) {
operatorFunction = function;
}
public void saveData(@NotNull Element element) { public void saveData(@NotNull Element element) {
final Element conflictsElement = new Element(SHORTCUT_CONFLICTS_ELEMENT); final Element conflictsElement = new Element(SHORTCUT_CONFLICTS_ELEMENT);
for (Map.Entry<KeyStroke, ShortcutOwnerInfo> entry : myShortcutConflicts.entrySet()) { for (Map.Entry<KeyStroke, ShortcutOwnerInfo> entry : myShortcutConflicts.entrySet()) {

View File

@ -108,9 +108,7 @@ public class MacroGroup extends VimMacroBase {
KeyHandler.getInstance().handleKey(editor, key, context); KeyHandler.getInstance().handleKey(editor, key, context);
}); });
} }
keyStack.resetFirst();
} }
keyStack.removeFirst();
}); });
} }
} }

View File

@ -411,7 +411,6 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
/** /**
* COMPATIBILITY-LAYER: Method added * COMPATIBILITY-LAYER: Method added
* Please see: <a href="https://jb.gg/zo8n0r">doc</a>
* *
* @deprecated Please use method with VimEditor * @deprecated Please use method with VimEditor
*/ */

View File

@ -23,10 +23,8 @@ import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer; import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer;
import com.intellij.openapi.fileEditor.impl.EditorWindow; import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileManager;
@ -1170,25 +1168,15 @@ public class MotionGroup extends VimMotionGroupBase {
@Override @Override
public int moveCaretGotoPreviousTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { public int moveCaretGotoPreviousTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) {
Project project = ((IjVimEditor)editor).getEditor().getProject(); switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), rawCount >= 1 ? -rawCount : -1, false);
if (project == null) {
return editor.currentCaret().getOffset().getPoint();
}
EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow();
switchEditorTab(currentWindow, rawCount >= 1 ? -rawCount : -1, false);
return editor.currentCaret().getOffset().getPoint(); return editor.currentCaret().getOffset().getPoint();
} }
@Override @Override
public int moveCaretGotoNextTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { public int moveCaretGotoNextTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) {
final boolean absolute = rawCount >= 1; final boolean absolute = rawCount >= 1;
switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), absolute ? rawCount - 1 : 1,
Project project = ((IjVimEditor)editor).getEditor().getProject(); absolute);
if (project == null) {
return editor.currentCaret().getOffset().getPoint();
}
EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow();
switchEditorTab(currentWindow, absolute ? rawCount - 1 : 1, absolute);
return editor.currentCaret().getOffset().getPoint(); return editor.currentCaret().getOffset().getPoint();
} }

View File

@ -20,24 +20,26 @@ package com.maddyhome.idea.vim.group
import com.intellij.icons.AllIcons import com.intellij.icons.AllIcons
import com.intellij.ide.BrowserUtil import com.intellij.ide.BrowserUtil
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.OpenFileAction import com.intellij.ide.actions.OpenFileAction
import com.intellij.ide.actions.RevealFileAction import com.intellij.ide.actions.RevealFileAction
import com.intellij.notification.ActionCenter
import com.intellij.notification.Notification import com.intellij.notification.Notification
import com.intellij.notification.NotificationGroup import com.intellij.notification.NotificationGroup
import com.intellij.notification.NotificationGroupManager import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType import com.intellij.notification.NotificationType
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.KeyboardShortcut import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.ide.CopyPasteManager import com.intellij.openapi.ide.CopyPasteManager
import com.intellij.openapi.keymap.Keymap
import com.intellij.openapi.keymap.KeymapUtil import com.intellij.openapi.keymap.KeymapUtil
import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.registry.Registry
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.key.ShortcutOwner import com.maddyhome.idea.vim.key.ShortcutOwner
@ -48,6 +50,7 @@ import com.maddyhome.idea.vim.statistic.ActionTracker
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable import com.maddyhome.idea.vim.ui.VimEmulationConfigurable
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
import com.maddyhome.idea.vim.vimscript.services.VimRcService import com.maddyhome.idea.vim.vimscript.services.VimRcService
import org.jetbrains.annotations.Nls
import java.awt.datatransfer.StringSelection import java.awt.datatransfer.StringSelection
import java.io.File import java.io.File
import javax.swing.KeyStroke import javax.swing.KeyStroke
@ -112,6 +115,23 @@ class NotificationService(private val project: Project?) {
Messages.getQuestionIcon() Messages.getQuestionIcon()
) )
fun specialKeymap(keymap: Keymap, listener: NotificationListener.Adapter) {
val notification = IDEAVIM_STICKY_GROUP.createNotification(
IDEAVIM_NOTIFICATION_TITLE,
"IdeaVim plugin doesn't use the special \"Vim\" keymap any longer. " +
"Switching to \"${keymap.presentableName}\" keymap.<br/><br/>" +
"Now it is possible to set up:<br/>" +
"<ul>" +
"<li>Vim keys in your ~/.ideavimrc file using key mapping commands</li>" +
"<li>IDE action shortcuts in \"File | Settings | Keymap\"</li>" +
"<li>Vim or IDE handlers for conflicting shortcuts in <a href='#settings'>Vim Emulation</a> settings</li>" +
"</ul>",
NotificationType.INFORMATION
)
notification.setListener(listener)
notification.notify(project)
}
fun noVimrcAsDefault() { fun noVimrcAsDefault() {
val notification = IDEAVIM_STICKY_GROUP.createNotification( val notification = IDEAVIM_STICKY_GROUP.createNotification(
IDEAVIM_NOTIFICATION_TITLE, IDEAVIM_NOTIFICATION_TITLE,
@ -188,7 +208,7 @@ class NotificationService(private val project: Project?) {
Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let { Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let {
notification = it notification = it
it.whenExpired { notification = null } it.whenExpired { notification = null }
it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>") it.setContent(it.content + "<br><br><small>Use ${getToolwindowName()} to see previous ids</small>")
it.addAction(StopTracking()) it.addAction(StopTracking())
@ -202,6 +222,15 @@ class NotificationService(private val project: Project?) {
} }
} }
// [VERSION UPDATE] 221+ Use ActionCenter.getToolWindowName
private fun getToolwindowName(): @Nls String {
return IdeBundle.message(if (isEnabled()) "toolwindow.stripe.Notifications" else "toolwindow.stripe.Event_Log")
}
private fun isEnabled(): Boolean {
return Registry.`is`("ide.notification.action.center", true)
}
class CopyActionId(val id: String?, val project: Project?) : DumbAwareAction(MessageHelper.message("action.copy.action.id.text")) { class CopyActionId(val id: String?, val project: Project?) : DumbAwareAction(MessageHelper.message("action.copy.action.id.text")) {
override fun actionPerformed(e: AnActionEvent) { override fun actionPerformed(e: AnActionEvent) {
CopyPasteManager.getInstance().setContents(StringSelection(id ?: "")) CopyPasteManager.getInstance().setContents(StringSelection(id ?: ""))
@ -222,8 +251,6 @@ class NotificationService(private val project: Project?) {
override fun update(e: AnActionEvent) { override fun update(e: AnActionEvent) {
e.presentation.isEnabled = id != null e.presentation.isEnabled = id != null
} }
override fun getActionUpdateThread() = ActionUpdateThread.BGT
} }
class StopTracking : DumbAwareAction("Stop Tracking") { class StopTracking : DumbAwareAction("Stop Tracking") {
@ -260,8 +287,6 @@ class NotificationService(private val project: Project?) {
val actionText = if (VimRcService.findIdeaVimRc() != null) "Open ~/.ideavimrc" else "Create ~/.ideavimrc" val actionText = if (VimRcService.findIdeaVimRc() != null) "Open ~/.ideavimrc" else "Create ~/.ideavimrc"
e.presentation.text = actionText e.presentation.text = actionText
} }
override fun getActionUpdateThread() = ActionUpdateThread.BGT
} }
@Suppress("DialogTitleCapitalization") @Suppress("DialogTitleCapitalization")

View File

@ -61,10 +61,7 @@ internal fun Project.createLineBookmark(editor: Editor, line: Int, mnemonic: Cha
val type = BookmarkType.get(mnemonic) val type = BookmarkType.get(mnemonic)
if (type == BookmarkType.DEFAULT) return null if (type == BookmarkType.DEFAULT) return null
val group = bookmarksManager.defaultGroup val group = bookmarksManager.defaultGroup ?: bookmarksManager.addGroup("IdeaVim", true) ?: return null
?: bookmarksManager.getGroup("IdeaVim")
?: bookmarksManager.addGroup("IdeaVim", true)
?: return null
if (group.canAdd(bookmark)) { if (group.canAdd(bookmark)) {
group.add(bookmark, type) group.add(bookmark, type)
return bookmark return bookmark

View File

@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.group;
import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
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.fileEditor.impl.EditorWithProviderComposite;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.concurrency.annotations.RequiresReadLock; import com.intellij.util.concurrency.annotations.RequiresReadLock;
@ -183,7 +183,7 @@ public class WindowGroup extends WindowGroupBase {
} }
private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) { private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) {
final EditorComposite editor = window.getSelectedComposite(); final EditorWithProviderComposite editor = window.getSelectedEditor();
if (editor != null) { if (editor != null) {
final Point point = editor.getComponent().getLocationOnScreen(); final Point point = editor.getComponent().getLocationOnScreen();
final Dimension dimension = editor.getComponent().getSize(); final Dimension dimension = editor.getComponent().getSize();

View File

@ -34,9 +34,8 @@ import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.isBlock import com.maddyhome.idea.vim.command.isBlock
import com.maddyhome.idea.vim.command.isChar import com.maddyhome.idea.vim.command.isChar
import com.maddyhome.idea.vim.command.isLine import com.maddyhome.idea.vim.command.isLine
@ -44,9 +43,7 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.TestClipboardModel import com.maddyhome.idea.vim.helper.TestClipboardModel
import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS
import com.maddyhome.idea.vim.newapi.IjVimCaret import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
@ -63,20 +60,10 @@ import java.awt.datatransfer.DataFlavor
import kotlin.math.min import kotlin.math.min
class PutGroup : VimPutBase() { class PutGroup : VimPutBase() {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean): Boolean { override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean {
val additionalData = collectPreModificationData(editor, data) val additionalData = collectPreModificationData(editor, data)
data.visualSelection?.let {
deleteSelectedText(
editor,
data,
OperatorArguments(false, 0, editor.mode, editor.subMode)
)
}
val processedText = processText(editor, data) ?: return false val processedText = processText(editor, data) ?: return false
putForCaret(editor, caret, data, additionalData, context, processedText) putForCaret(editor, caret, data, additionalData, context, processedText)
if (editor.primaryCaret() == caret && updateVisualMarks) {
wrapInsertedTextWithVisualMarks(editor, data, processedText)
}
return true return true
} }
@ -102,6 +89,7 @@ class PutGroup : VimPutBase() {
} }
} }
notifyAboutIdeaPut(editor)
logger.debug("Perform put via plugin") logger.debug("Perform put via plugin")
val myCarets = if (visualSelection != null) { val myCarets = if (visualSelection != null) {
visualSelection.caretsAndSelections.keys.sortedByDescending { it.getLogicalPosition() } visualSelection.caretsAndSelections.keys.sortedByDescending { it.getLogicalPosition() }
@ -109,7 +97,22 @@ class PutGroup : VimPutBase() {
EditorHelper.getOrderedCaretsList(editor.ij).map { IjVimCaret(it) } EditorHelper.getOrderedCaretsList(editor.ij).map { IjVimCaret(it) }
} }
injector.application.runWriteAction { injector.application.runWriteAction {
myCarets.forEach { caret -> putForCaret(editor, caret, data, additionalData, context, text) } val singleCaret = myCarets.singleOrNull()
if (singleCaret != null) {
putForCaret(editor, singleCaret, data, additionalData, context, text)
}
else {
val lines = text.text.split('\n')
if (lines.size != myCarets.size) {
myCarets.forEach { caret -> putForCaret(editor, caret, data, additionalData, context, text) }
}
else {
myCarets.asReversed().forEachIndexed { index, caret ->
val line = ProcessedTextData(lines[index], text.typeInRegister, text.transferableData)
putForCaret(editor, caret, data, additionalData, context, line)
}
}
}
} }
} }
@ -121,7 +124,6 @@ class PutGroup : VimPutBase() {
context: ExecutionContext, context: ExecutionContext,
text: ProcessedTextData, text: ProcessedTextData,
) { ) {
notifyAboutIdeaPut(editor)
if (data.visualSelection?.typeInEditor?.isLine == true && editor.isOneLineMode()) return if (data.visualSelection?.typeInEditor?.isLine == true && editor.isOneLineMode()) return
val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, text.typeInRegister, data, additionalData) val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, text.typeInRegister, data, additionalData)
@ -131,9 +133,7 @@ class PutGroup : VimPutBase() {
editor, caret, context, text.text, text.typeInRegister, subMode, editor, caret, context, text.text, text.typeInRegister, subMode,
startOffset, data.count, data.indent, data.caretAfterInsertedText startOffset, data.count, data.indent, data.caretAfterInsertedText
) )
if (caret == editor.primaryCaret()) { VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
}
moveCaretToEndPosition( moveCaretToEndPosition(
editor, editor,
caret, caret,
@ -190,12 +190,7 @@ class PutGroup : VimPutBase() {
} }
} }
visualSelection.typeInEditor.isLine -> { visualSelection.typeInEditor.isLine -> {
val lastChar = if (editor.fileSize > 0) { if (caret.offset == editor.fileSize && editor.fileSize != 0) {
editor.document.getText(com.intellij.openapi.util.TextRange(editor.fileSize - 1, editor.fileSize))[0]
} else {
null
}
if (caret.offset == editor.fileSize && editor.fileSize != 0 && lastChar != '\n') {
application.runWriteAction { editor.document.insertString(caret.offset, "\n") } application.runWriteAction { editor.document.insertString(caret.offset, "\n") }
listOf(caret.offset + 1) listOf(caret.offset + 1)
} else listOf(caret.offset) } else listOf(caret.offset)
@ -249,13 +244,13 @@ class PutGroup : VimPutBase() {
} }
private fun putTextViaIde( private fun putTextViaIde(
pasteProvider: PasteProvider, pasteProvider: PasteProvider,
vimEditor: VimEditor, vimEditor: VimEditor,
vimContext: ExecutionContext, vimContext: ExecutionContext,
text: ProcessedTextData, text: ProcessedTextData,
subMode: VimStateMachine.SubMode, subMode: VimStateMachine.SubMode,
data: PutData, data: PutData,
additionalData: Map<String, Any>, additionalData: Map<String, Any>,
) { ) {
val editor = (vimEditor as IjVimEditor).editor val editor = (vimEditor as IjVimEditor).editor
val context = vimContext.context as DataContext val context = vimContext.context as DataContext

View File

@ -18,20 +18,23 @@
package com.maddyhome.idea.vim.group.copy package com.maddyhome.idea.vim.group.copy
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.listener.VimYankListener import com.maddyhome.idea.vim.listener.VimYankListener
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.yank.YankGroupBase import com.maddyhome.idea.vim.yank.YankGroupBase
import org.jetbrains.annotations.Contract import org.jetbrains.annotations.Contract
import kotlin.math.min import kotlin.math.min
@ -43,8 +46,8 @@ class YankGroup : YankGroupBase() {
fun removeListener(listener: VimYankListener) = yankListeners.remove(listener) fun removeListener(listener: VimYankListener) = yankListeners.remove(listener)
private fun notifyListeners(editor: VimEditor, textRange: TextRange) = yankListeners.forEach { private fun notifyListeners(editor: Editor, textRange: TextRange) = yankListeners.forEach {
it.yankPerformed(editor.ij, textRange) it.yankPerformed(editor, textRange)
} }
/** /**
@ -64,38 +67,32 @@ class YankGroup : YankGroupBase() {
operatorArguments: OperatorArguments operatorArguments: OperatorArguments
): Boolean { ): Boolean {
val motion = argument.motion val motion = argument.motion
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val nativeCaretCount = editor.nativeCarets().size val caretModel = editor.ij.caretModel
if (nativeCaretCount <= 0) return false if (caretModel.caretCount <= 0) return false
val carretToRange = HashMap<VimCaret, TextRange>(nativeCaretCount) val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
val ranges = ArrayList<Pair<Int, Int>>(nativeCaretCount)
// This logic is from original vim // This logic is from original vim
val startOffsets = if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<VimCaret, Int>(nativeCaretCount) val startOffsets =
if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<Caret, Int>(caretModel.caretCount)
for (caret in editor.nativeCarets()) { for (caret in caretModel.allCarets) {
val motionRange = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments) val motionRange = MotionGroup.getMotionRange(editor.ij, caret, context.ij, argument, operatorArguments)
?: continue ?: continue
assert(motionRange.size() == 1) assert(motionRange.size() == 1)
ranges.add(motionRange.startOffset to motionRange.endOffset) ranges.add(motionRange.startOffset to motionRange.endOffset)
startOffsets?.put(caret, motionRange.normalize().startOffset) startOffsets?.put(caret, motionRange.normalize().startOffset)
carretToRange[caret] = TextRange(motionRange.startOffset, motionRange.endOffset)
} }
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val range = getTextRange(ranges, type) ?: return false val range = getTextRange(ranges, type) ?: return false
if (range.size() == 0) return false if (range.size() == 0) return false
return yankRange( val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
editor, return yankRange(editor.ij, range, selectionType, startOffsets)
carretToRange,
range,
type,
startOffsets
)
} }
/** /**
@ -106,21 +103,19 @@ class YankGroup : YankGroupBase() {
* @return true if able to yank the lines, false if not * @return true if able to yank the lines, false if not
*/ */
override fun yankLine(editor: VimEditor, count: Int): Boolean { override fun yankLine(editor: VimEditor, count: Int): Boolean {
val caretCount = editor.nativeCarets().size val caretModel = editor.ij.caretModel
val ranges = ArrayList<Pair<Int, Int>>(caretCount) val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
val caretToRange = HashMap<VimCaret, TextRange>(caretCount) for (caret in caretModel.allCarets) {
for (caret in editor.nativeCarets()) { val start = VimPlugin.getMotion().moveCaretToLineStart(editor, caret.vim)
val start = injector.motion.moveCaretToLineStart(editor, caret) val end = min(VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret.vim, count - 1, true) + 1, editor.fileSize().toInt())
val end = min(injector.motion.moveCaretToLineEndOffset(editor, caret, count - 1, true) + 1, editor.fileSize().toInt())
if (end == -1) continue if (end == -1) continue
ranges.add(start to end) ranges.add(start to end)
caretToRange[caret] = TextRange(start, end)
} }
val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false
return yankRange(editor, caretToRange, range, SelectionType.LINE_WISE, null) return yankRange(editor.ij, range, SelectionType.LINE_WISE, null)
} }
/** /**
@ -134,7 +129,6 @@ class YankGroup : YankGroupBase() {
override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean { override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean {
range ?: return false range ?: return false
val caretToRange = HashMap<VimCaret, TextRange>()
val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
if (type == SelectionType.LINE_WISE) { if (type == SelectionType.LINE_WISE) {
@ -149,25 +143,24 @@ class YankGroup : YankGroupBase() {
} }
} }
val caretModel = editor.ij.caretModel
val rangeStartOffsets = range.startOffsets val rangeStartOffsets = range.startOffsets
val rangeEndOffsets = range.endOffsets val rangeEndOffsets = range.endOffsets
val startOffsets = HashMap<VimCaret, Int>(editor.nativeCarets().size)
if (type == SelectionType.BLOCK_WISE) {
startOffsets[editor.primaryCaret()] = range.normalize().startOffset
caretToRange[editor.primaryCaret()] = range
} else {
for ((i, caret) in editor.nativeCarets().withIndex()) {
val textRange = TextRange(rangeStartOffsets[i], rangeEndOffsets[i])
startOffsets[caret] = textRange.normalize().startOffset
caretToRange[caret] = textRange
}
}
return if (moveCursor) { return if (moveCursor) {
yankRange(editor, caretToRange, range, selectionType, startOffsets) val startOffsets = HashMap<Caret, Int>(caretModel.caretCount)
if (type == SelectionType.BLOCK_WISE) {
startOffsets[caretModel.primaryCaret] = range.normalize().startOffset
} else {
val carets = caretModel.allCarets
for (i in carets.indices) {
startOffsets[carets[i]] = TextRange(rangeStartOffsets[i], rangeEndOffsets[i]).normalize().startOffset
}
}
yankRange(editor.ij, range, selectionType, startOffsets)
} else { } else {
yankRange(editor, caretToRange, range, selectionType, null) yankRange(editor.ij, range, selectionType, null)
} }
} }
@ -199,20 +192,15 @@ class YankGroup : YankGroupBase() {
} }
private fun yankRange( private fun yankRange(
editor: VimEditor, editor: Editor,
caretToRange: Map<VimCaret, TextRange>,
range: TextRange, range: TextRange,
type: SelectionType, type: SelectionType,
startOffsets: Map<VimCaret, Int>?, startOffsets: Map<Caret, Int>?,
): Boolean { ): Boolean {
startOffsets?.forEach { (caret, offset) -> injector.motion.moveCaret(editor, caret, offset) } startOffsets?.forEach { (caret, offset) -> MotionGroup.moveCaret(editor, caret, offset) }
notifyListeners(editor, range) notifyListeners(editor, range)
var result = true return VimPlugin.getRegister().storeText(editor.vim, range, type, false)
for ((caret, myRange) in caretToRange) {
result = caret.registerStorage.storeText(caret, editor, myRange, type, false) && result
}
return result
} }
} }

View File

@ -25,7 +25,7 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorDataContext import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.editorMode import com.maddyhome.idea.vim.helper.vimStateMachine
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
@ -35,8 +35,8 @@ import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.isTemplateActive import com.maddyhome.idea.vim.helper.isTemplateActive
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.popAllModes import com.maddyhome.idea.vim.helper.popAllModes
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.listener.VimListenerManager import com.maddyhome.idea.vim.listener.VimListenerManager
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim

View File

@ -25,11 +25,11 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimMotionGroupBase import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.inBlockSubMode import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.inSelectMode import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes

View File

@ -44,7 +44,6 @@ class VisualMotionGroup : VimVisualMotionGroupBase() {
/** /**
* COMPATIBILITY-LAYER: Added a method * COMPATIBILITY-LAYER: Added a method
* Please see: https://jb.gg/zo8n0r
*/ */
fun enterVisualMode(editor: Editor, subMode: CommandState.SubMode? = null): Boolean { fun enterVisualMode(editor: Editor, subMode: CommandState.SubMode? = null): Boolean {
return this.enterVisualMode(editor.vim, subMode?.engine) return this.enterVisualMode(editor.vim, subMode?.engine)

View File

@ -60,14 +60,12 @@ val Editor.editorMode
/** /**
* COMPATIBILITY-LAYER: New method * COMPATIBILITY-LAYER: New method
* Please see: https://jb.gg/zo8n0r
*/ */
val Editor.mode val Editor.mode
get() = this.vim.vimStateMachine.mode.ij get() = this.vim.vimStateMachine.mode.ij
/** /**
* COMPATIBILITY-LAYER: New method * COMPATIBILITY-LAYER: New method
* Please see: https://jb.gg/zo8n0r
*/ */
val CommandState.Mode.isEndAllowed: Boolean val CommandState.Mode.isEndAllowed: Boolean
get() = this.engine.isEndAllowed get() = this.engine.isEndAllowed

View File

@ -37,7 +37,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range; import org.jetbrains.annotations.Range;
import java.awt.*; import java.awt.*;
import java.awt.geom.Point2D;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -155,7 +154,6 @@ public class EditorHelper {
/** /**
* COMPATIBILITY-LAYER: Created a function * COMPATIBILITY-LAYER: Created a function
* Please see: <a href="https://jb.gg/zo8n0r">doc</a>
*/ */
public static int getVisualLineCount(final @NotNull Editor editor) { public static int getVisualLineCount(final @NotNull Editor editor) {
return getVisualLineCount(new IjVimEditor(editor)); return getVisualLineCount(new IjVimEditor(editor));
@ -247,27 +245,12 @@ public class EditorHelper {
* font. It does not include inlays or folds. * font. It does not include inlays or folds.
* <p> * <p>
* Note that this value is only approximate and should be avoided whenever possible! * Note that this value is only approximate and should be avoided whenever possible!
* </p>
* *
* @param editor The editor * @param editor The editor
* @return The number of screen columns * @return The number of screen columns
*/ */
public static int getApproximateScreenWidth(final @NotNull Editor editor) { public static int getApproximateScreenWidth(final @NotNull Editor editor) {
return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor)); return getVisibleArea(editor).width / EditorUtil.getPlainSpaceWidth(editor);
}
/**
* Gets the width of the space character in the editor's plain font as a float.
* <p>
* Font width can be fractional, but {@link EditorUtil#getPlainSpaceWidth(Editor)} returns it as an int, which can
* lead to rounding errors.
* </p>
*
* @param editor The editor
* @return The width of the space character in the editor's plain font in pixels. It might be a fractional value.
*/
public static float getPlainSpaceWidthFloat(final @NotNull Editor editor) {
return EditorUtil.fontForChar(' ', Font.PLAIN, editor).charWidth2D(' ');
} }
/** /**
@ -819,20 +802,19 @@ public class EditorHelper {
} }
} }
final int columnLeftX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn)).getX()); final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
scrollHorizontally(editor, columnLeftX); scrollHorizontally(editor, columnLeftX);
} }
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) { public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
final Point2D point = editor.visualPositionToPoint2D(new VisualPosition(visualLine, visualColumn)); final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
final int screenWidth = getVisibleArea(editor).width; final int screenWidth = getVisibleArea(editor).width;
// Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number // Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number
// of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is // of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts? // still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
final float standardColumnWidth = EditorHelper.getPlainSpaceWidthFloat(editor); final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
final int screenMidColumn = (int) (screenWidth / standardColumnWidth / 2); final int x = max(0, point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth));
final int x = max(0, (int) Math.round(point.getX() - (screenMidColumn * standardColumnWidth)));
scrollHorizontally(editor, x); scrollHorizontally(editor, x);
} }
@ -857,7 +839,7 @@ public class EditorHelper {
} }
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays // Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
final int targetColumnRightX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn + 1)).getX()); final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
final int screenWidth = getVisibleArea(editor).width; final int screenWidth = getVisibleArea(editor).width;
scrollHorizontally(editor, targetColumnRightX - screenWidth); scrollHorizontally(editor, targetColumnRightX - screenWidth);
} }
@ -1019,18 +1001,18 @@ public class EditorHelper {
// Note that visualPos.leansRight will be true for the right half side of the character grid // Note that visualPos.leansRight will be true for the right half side of the character grid
VisualPosition closestVisualPosition = editor.xyToVisualPosition(new Point(x, y)); VisualPosition closestVisualPosition = editor.xyToVisualPosition(new Point(x, y));
// Make sure we get the character that contains this XY, not the editor's decision about the closest character. The // Make sure we get the character that contains this XY, not the editor's decision about closest character. The
// editor will give us the next character if X is over halfway through the character grid. Take into account that // editor will give us the next character if X is over half way through the character grid.
// the font size might be fractional, but the editor's area is integer. Use floating point values and round. int xActualLeft = editor.visualPositionToXY(closestVisualPosition).x;
long xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX());
if (xActualLeft > x) { if (xActualLeft > x) {
closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition); closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition);
xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX()); xActualLeft = editor.visualPositionToXY(closestVisualPosition).x;
} }
if (xActualLeft >= leftBound) { if (xActualLeft >= leftBound) {
final VisualPosition nextVisualPosition = new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1); final int xActualRight =
final long xActualRight = Math.round(editor.visualPositionToPoint2D(nextVisualPosition).getX()) - 1; editor.visualPositionToXY(new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1)).x -
1;
if (xActualRight <= rightBound) { if (xActualRight <= rightBound) {
return closestVisualPosition.column; return closestVisualPosition.column;
} }

View File

@ -22,7 +22,6 @@ import com.intellij.codeInsight.template.TemplateManager
import com.intellij.codeWithMe.ClientId import com.intellij.codeWithMe.ClientId
import com.intellij.injected.editor.EditorWindow import com.intellij.injected.editor.EditorWindow
import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.ClientEditorManager
import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.editor.EditorFactory
@ -31,7 +30,6 @@ import com.intellij.openapi.util.Key
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
import kotlin.streams.toList
/** /**
* This annotation is created for test functions (methods). * This annotation is created for test functions (methods).
@ -85,9 +83,10 @@ fun Editor.getTopLevelEditor() = if (this is EditorWindow) this.delegate else th
/** /**
* Return list of editors for local host (for code with me plugin) * Return list of editors for local host (for code with me plugin)
* [VERSION UPDATE] 212+ ClientEditorManager.editors()
*/ */
fun localEditors(): List<Editor> { fun localEditors(): List<Editor> {
return ClientEditorManager.getCurrentInstance().editors().toList() return EditorFactory.getInstance().allEditors.filter { editor -> editor.editorClientId.let { it == null || it == ClientId.currentOrNull } }
} }
fun localEditors(doc: Document): List<Editor> { fun localEditors(doc: Document): List<Editor> {

View File

@ -24,8 +24,11 @@ import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys
import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.actionSystem.Presentation
import com.intellij.openapi.actionSystem.ex.ActionManagerEx import com.intellij.openapi.actionSystem.ex.ActionManagerEx
import com.intellij.openapi.actionSystem.ex.ActionUtil import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.command.CommandProcessor
@ -83,7 +86,7 @@ class IjActionExecutor : VimActionExecutor {
// This method executes inside of lastUpdateAndCheckDumb // This method executes inside of lastUpdateAndCheckDumb
// Another related issue: VIM-2604 // Another related issue: VIM-2604
if (!ActionUtil.lastUpdateAndCheckDumb(ijAction, event, false)) return false if (!ActionUtil.lastUpdateAndCheckDumb(ijAction, event, false)) return false
if (ijAction is ActionGroup && !event.presentation.isPerformGroup) { if (ijAction is ActionGroup && !canBePerformed(event, ijAction, context.ij)) {
// Some ActionGroups should not be performed, but shown as a popup // Some ActionGroups should not be performed, but shown as a popup
val popup = JBPopupFactory.getInstance() val popup = JBPopupFactory.getInstance()
.createActionGroupPopup(event.presentation.text, ijAction, context.ij, false, null, -1) .createActionGroupPopup(event.presentation.text, ijAction, context.ij, false, null, -1)
@ -115,9 +118,10 @@ class IjActionExecutor : VimActionExecutor {
var indexError: IndexNotReadyException? = null var indexError: IndexNotReadyException? = null
val manager = ActionManagerEx.getInstanceEx() val manager = ActionManagerEx.getInstanceEx()
manager.fireBeforeActionPerformed(action, event) manager.fireBeforeActionPerformed(action, event)
val component = event.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT)
var result: AnActionResult? = null var result: AnActionResult? = null
try { try {
SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use { SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use { ignore ->
performRunnable.run() performRunnable.run()
result = AnActionResult.PERFORMED result = AnActionResult.PERFORMED
} }
@ -139,6 +143,17 @@ class IjActionExecutor : VimActionExecutor {
} }
} }
private fun canBePerformed(event: AnActionEvent, action: ActionGroup, context: DataContext): Boolean {
val presentation = event.presentation
return try {
// [VERSION UPDATE] 221+ Just use Presentation.isPerformGroup
val method = Presentation::class.java.getMethod("isPerformGroup")
method.invoke(presentation) as Boolean
} catch (e: Exception) {
action.canBePerformed(context)
}
}
/** /**
* Execute an action by name * Execute an action by name
* *

View File

@ -25,9 +25,9 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjExecutionContext import com.maddyhome.idea.vim.newapi.IjExecutionContext

View File

@ -31,7 +31,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.VimSearchHelperBase;
import com.maddyhome.idea.vim.command.VimStateMachine; import com.maddyhome.idea.vim.command.VimStateMachine;
import com.maddyhome.idea.vim.common.CharacterPosition; import com.maddyhome.idea.vim.common.CharacterPosition;
import com.maddyhome.idea.vim.common.Direction; import com.maddyhome.idea.vim.common.Direction;
@ -530,9 +529,6 @@ public class SearchHelper {
CharSequence subSequence = chars.subSequence(startOffset, endOffset); CharSequence subSequence = chars.subSequence(startOffset, endOffset);
int inQuotePos = pos - startOffset; int inQuotePos = pos - startOffset;
int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false); int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false);
if (inQuoteStart == -1) {
inQuoteStart = findBlockLocation(subSequence, close, type, Direction.FORWARDS, inQuotePos, count, false);
}
if (inQuoteStart != -1) { if (inQuoteStart != -1) {
startPosInStringFound = true; startPosInStringFound = true;
int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false); int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false);
@ -546,9 +542,6 @@ public class SearchHelper {
if (!startPosInStringFound) { if (!startPosInStringFound) {
bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false); bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false);
if (bstart == -1) {
bstart = findBlockLocation(chars, close, type, Direction.FORWARDS, pos, count, false);
}
if (bstart != -1) { if (bstart != -1) {
bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false); bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false);
} }
@ -1202,7 +1195,7 @@ public class SearchHelper {
int last = -1; int last = -1;
int res = start; int res = start;
while (true) { while (true) {
res = (int)VimSearchHelperBase.Companion.findNextWordOne(chars, res, end, 1, true, false); res = findNextWordOne(chars, res, end, 1, true, false);
if (res == start || res == 0 || res > end || res == last) { if (res == start || res == 0 || res > end || res == last) {
break; break;
} }
@ -1231,6 +1224,105 @@ public class SearchHelper {
return new CountPosition(count, position); return new CountPosition(count, position);
} }
public static int findNextWord(@NotNull Editor editor, int searchFrom, int count, boolean bigWord) {
CharSequence chars = editor.getDocument().getCharsSequence();
final int size = EditorHelperRt.getFileSize(editor);
return findNextWord(chars, searchFrom, size, count, bigWord, false);
}
public static int findNextWord(@NotNull CharSequence chars,
int pos,
int size,
int count,
boolean bigWord,
boolean spaceWords) {
int step = count >= 0 ? 1 : -1;
count = Math.abs(count);
int res = pos;
for (int i = 0; i < count; i++) {
res = findNextWordOne(chars, res, size, step, bigWord, spaceWords);
if (res == pos || res == 0 || res == size - 1) {
break;
}
}
return res;
}
private static int findNextWordOne(@NotNull CharSequence chars,
int pos,
int size,
int step,
boolean bigWord,
boolean spaceWords) {
boolean found = false;
pos = pos < size ? pos : Math.min(size, chars.length() - 1);
// For back searches, skip any current whitespace so we start at the end of a word
if (step < 0 && pos > 0) {
if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE &&
!spaceWords) {
pos = skipSpace(chars, pos - 1, step, size) + 1;
}
if (pos > 0 &&
CharacterHelper.charType(chars.charAt(pos), bigWord) !=
CharacterHelper.charType(chars.charAt(pos - 1), bigWord)) {
pos += step;
}
}
int res = pos;
if (pos < 0 || pos >= size) {
return pos;
}
CharacterHelper.CharacterType type = CharacterHelper.charType(chars.charAt(pos), bigWord);
if (type == CharacterHelper.CharacterType.WHITESPACE && step < 0 && pos > 0 && !spaceWords) {
type = CharacterHelper.charType(chars.charAt(pos - 1), bigWord);
}
pos += step;
while (pos >= 0 && pos < size && !found) {
CharacterHelper.CharacterType newType = CharacterHelper.charType(chars.charAt(pos), bigWord);
if (newType != type) {
if (newType == CharacterHelper.CharacterType.WHITESPACE && step >= 0 && !spaceWords) {
pos = skipSpace(chars, pos, step, size);
res = pos;
}
else if (step < 0) {
res = pos + 1;
}
else {
res = pos;
}
type = CharacterHelper.charType(chars.charAt(res), bigWord);
found = true;
}
pos += step;
}
if (found) {
if (res < 0) //(pos <= 0)
{
res = 0;
}
else if (res >= size) //(pos >= size)
{
res = size - 1;
}
}
else if (pos <= 0) {
res = 0;
}
else if (pos >= size) {
res = size;
}
return res;
}
public static @NotNull List<Pair<TextRange, NumberType>> findNumbersInRange(final @NotNull Editor editor, public static @NotNull List<Pair<TextRange, NumberType>> findNumbersInRange(final @NotNull Editor editor,
@NotNull TextRange textRange, @NotNull TextRange textRange,
final boolean alpha, final boolean alpha,
@ -1556,10 +1648,10 @@ public class SearchHelper {
if ((!onWordStart && !(startSpace && isOuter)) || hasSelection || (count > 1 && dir == -1)) { if ((!onWordStart && !(startSpace && isOuter)) || hasSelection || (count > 1 && dir == -1)) {
if (dir == 1) { if (dir == 1) {
start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -1, isBig, !isOuter); start = findNextWord(chars, pos, max, -1, isBig, !isOuter);
} }
else { else {
start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter); start = findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter);
} }
start = EditorHelper.normalizeOffset(editor, start, false); start = EditorHelper.normalizeOffset(editor, start, false);
@ -1707,7 +1799,7 @@ public class SearchHelper {
if (step > 0 && pos < size - 1) { if (step > 0 && pos < size - 1) {
if (CharacterHelper.charType(chars.charAt(pos + 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && if (CharacterHelper.charType(chars.charAt(pos + 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE &&
!spaceWords) { !spaceWords) {
pos = (int)(VimSearchHelperBase.Companion.skipSpace(chars, pos + 1, step, size) - 1); pos = skipSpace(chars, pos + 1, step, size) - 1;
} }
if (pos < size - 1 && if (pos < size - 1 &&
CharacterHelper.charType(chars.charAt(pos), bigWord) != CharacterHelper.charType(chars.charAt(pos), bigWord) !=
@ -1732,7 +1824,7 @@ public class SearchHelper {
res = pos - 1; res = pos - 1;
} }
else if (newType == CharacterHelper.CharacterType.WHITESPACE && step < 0 && !spaceWords) { else if (newType == CharacterHelper.CharacterType.WHITESPACE && step < 0 && !spaceWords) {
pos = (int)VimSearchHelperBase.Companion.skipSpace(chars, pos, step, size); pos = skipSpace(chars, pos, step, size);
res = pos; res = pos;
} }
else { else {
@ -1760,6 +1852,34 @@ public class SearchHelper {
return res; return res;
} }
/**
* Skip whitespace starting with the supplied position.
* <p>
* An empty line is considered a whitespace break.
*
* @param chars The text as a character array
* @param offset The starting position
* @param step The direction to move
* @param size The size of the document
* @return The new position. This will be the first non-whitespace character found or an empty line
*/
private static int skipSpace(@NotNull CharSequence chars, int offset, int step, int size) {
char prev = 0;
while (offset >= 0 && offset < size) {
final char c = chars.charAt(offset);
if (c == '\n' && c == prev) {
break;
}
if (CharacterHelper.charType(c, false) != CharacterHelper.CharacterType.WHITESPACE) {
break;
}
prev = c;
offset += step;
}
return offset < size ? offset : size - 1;
}
/** /**
* This locates the position with the document of the count-th occurrence of ch on the current line * This locates the position with the document of the count-th occurrence of ch on the current line
* *

View File

@ -16,18 +16,24 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.jetbrains.plugins.ideavim.ex.implementation.expressions package com.maddyhome.idea.vim.helper;
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys import javax.swing.*;
import com.maddyhome.idea.vim.vimscript.model.expressions.Register import java.util.Arrays;
import org.jetbrains.plugins.ideavim.VimTestCase import java.util.List;
import org.jetbrains.plugins.ideavim.ex.evaluate import java.util.stream.Collectors;
class ExpressionTest : VimTestCase() { import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
fun `test multiline register content`() { /**
configureByText("${c}Oh\nHi\nMark\n") * COMPATIBILITY-LAYER: Created a helper class
typeText(parseKeys("VGy")) */
assertEquals("Oh\nHi\nMark\n", Register('"').evaluate().toString()) public class StringHelper {
public static List<KeyStroke> parseKeys(String string) {
return injector.getParser().parseKeys(string);
}
public static List<KeyStroke> parseKeys(String... string) {
return Arrays.stream(string).flatMap(o -> injector.getParser().parseKeys(o).stream()).collect(Collectors.toList());
} }
} }

View File

@ -1,45 +0,0 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2022 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.helper
import com.maddyhome.idea.vim.api.injector
import java.util.*
import java.util.stream.Collectors
import javax.swing.KeyStroke
/**
* COMPATIBILITY-LAYER: Created a helper class
* Please see: https://jb.gg/zo8n0r
*/
object StringHelper {
@JvmStatic
fun parseKeys(string: String): List<KeyStroke> {
return injector.parser.parseKeys(string)
}
@JvmStatic
fun parseKeys(vararg string: String): List<KeyStroke> {
return Arrays.stream(string).flatMap { o: String -> injector.parser.parseKeys(o).stream() }
.collect(Collectors.toList())
}
@JvmStatic
fun isCloseKeyStroke(stroke: KeyStroke): Boolean {
return stroke.isCloseKeyStroke()
}
}

View File

@ -21,16 +21,11 @@ package com.maddyhome.idea.vim.helper
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.command.impl.UndoManagerImpl
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.fileEditor.impl.text.TextEditorProvider
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.ChangesListener
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
@ -42,36 +37,27 @@ import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
*/ */
@Service @Service
class UndoRedoHelper : UndoRedoBase() { class UndoRedoHelper : UndoRedoBase() {
init {
injector.optionService.addListener(IjVimOptionService.oldUndo, { UndoManagerImpl.ourNeverAskUser = !injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo) }, true)
}
override fun undo(context: ExecutionContext): Boolean { override fun undo(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 editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val vimEditor = editor.vim
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
if (undoManager.isUndoAvailable(fileEditor)) { if (fileEditor != null && undoManager.isUndoAvailable(fileEditor)) {
if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
} else { } else {
performUntilFileChanges(vimEditor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
undoManager.undo(fileEditor)
vimEditor.carets().forEach { editor?.carets()?.forEach {
val ijCaret = it.ij val ijCaret = it.ij
val hasSelection = ijCaret.hasSelection() val hasSelection = ijCaret.hasSelection()
if (hasSelection) { if (hasSelection) {
val selectionStart = ijCaret.selectionStart val selectionStart = ijCaret.selectionStart
CommandProcessor.getInstance().runUndoTransparentAction { it.ij.removeSelection()
it.ij.removeSelection() it.ij.moveToOffset(selectionStart)
it.ij.moveToOffset(selectionStart)
}
} }
} }
} }
return true return true
} }
return false return false
@ -80,45 +66,21 @@ class UndoRedoHelper : UndoRedoBase() {
override fun redo(context: ExecutionContext): Boolean { override fun redo(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 editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val vimEditor = editor.vim
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
if (undoManager.isRedoAvailable(fileEditor)) { if (fileEditor != null && undoManager.isRedoAvailable(fileEditor)) {
if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
} else { } else {
performUntilFileChanges(vimEditor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
CommandProcessor.getInstance().runUndoTransparentAction { undoManager.redo(fileEditor)
vimEditor.carets().forEach { it.ij.removeSelection() } if (editor?.primaryCaret()?.ij?.hasSelection() == true) {
undoManager.redo(fileEditor)
} }
editor?.carets()?.forEach { it.ij.removeSelection() }
} }
return true return true
} }
return false return false
} }
private fun performUntilFileChanges(editor: IjVimEditor?, check: () -> Boolean, action: Runnable) {
if (editor == null) return
val vimDocument = editor.document
val changeListener = object : ChangesListener {
var hasChanged = false
override fun documentChanged(change: ChangesListener.Change) {
hasChanged = true
}
}
val oldPath = editor.getPath()
vimDocument.addChangeListener(changeListener)
while (check() && !changeListener.hasChanged && !ifFilePathChanged(editor, oldPath)) {
action.run()
}
vimDocument.removeChangeListener(changeListener)
}
private fun ifFilePathChanged(editor: IjVimEditor, oldPath: String?): Boolean {
return editor.getPath() != oldPath
}
} }

View File

@ -27,9 +27,8 @@ import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.markup.RangeHighlighter import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.UserDataHolder import com.intellij.openapi.util.UserDataHolder
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
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
@ -74,7 +73,6 @@ var Caret.vimInsertStart: RangeMarker by userDataOr {
this.offset this.offset
) )
} }
var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
// ------------------ Editor // ------------------ Editor
fun unInitializeEditor(editor: Editor) { fun unInitializeEditor(editor: Editor) {

View File

@ -19,6 +19,8 @@
package com.maddyhome.idea.vim.key package com.maddyhome.idea.vim.key
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.addLeafs
fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) { fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder) addLeafs(injector.parser.parseKeys(keys), actionHolder)

View File

@ -15,23 +15,22 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.maddyhome.idea.vim.key
import com.maddyhome.idea.vim.api.ExecutionContext package com.maddyhome.idea.vim.key;
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.SelectionType import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.command.SelectionType;
import org.jetbrains.annotations.NotNull;
/** /**
* @author vlan * @author vlan
*/ */
interface OperatorFunction { public interface OperatorFunction {
/** /**
* The value of 'operatorfunc' to be used as the operator function in 'g@'. * The value of 'operatorfunc' to be used as the operator function in 'g@'.
* * <p>
*
* Make sure to synchronize your function properly using read/write actions. * Make sure to synchronize your function properly using read/write actions.
*/ */
fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean boolean apply(@NotNull Editor editor, @NotNull DataContext context, @NotNull SelectionType selectionType);
fun postProcessSelection(): Boolean = true
} }

View File

@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Caret
@ -35,6 +35,7 @@ import com.maddyhome.idea.vim.group.visual.VimVisualTimer
import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.inVisualMode import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.annotations.NotNull
/** /**
* A collection of hacks to improve the interaction with fancy AppCode templates * A collection of hacks to improve the interaction with fancy AppCode templates
@ -49,16 +50,16 @@ object AppCodeTemplates {
private var editor: Editor? = null private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
} }
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
if (ActionManager.getInstance().getId(action) == IdeActions.ACTION_CHOOSE_LOOKUP_ITEM) { if (ActionManager.getInstance().getId(action) == IdeActions.ACTION_CHOOSE_LOOKUP_ITEM) {
@ -76,8 +77,8 @@ object AppCodeTemplates {
@JvmStatic @JvmStatic
fun onMovement( fun onMovement(
editor: Editor, editor: @NotNull Editor,
caret: Caret, caret: @NotNull Caret,
toRight: Boolean, toRight: Boolean,
) { ) {
val offset = caret.offset val offset = caret.offset

View File

@ -31,8 +31,8 @@ import com.intellij.find.FindModelListener
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@ -42,9 +42,9 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorDataContext import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.inNormalMode import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
@ -66,17 +66,17 @@ object IdeaSpecifics {
private var editor: Editor? = null private var editor: Editor? = null
private var completionPrevDocumentLength: Int? = null private var completionPrevDocumentLength: Int? = null
private var completionPrevDocumentOffset: Int? = null private var completionPrevDocumentOffset: Int? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) { if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) {
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
} }
if (hostEditor != null && action is ChooseItemAction && hostEditor.vimStateMachine?.isRecording == true) { if (hostEditor != null && action is ChooseItemAction && hostEditor.vimStateMachine?.isRecording == true) {
@ -96,7 +96,7 @@ object IdeaSpecifics {
} }
} }
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val editor = editor val editor = editor
@ -132,7 +132,7 @@ object IdeaSpecifics {
while (commandState.mode != VimStateMachine.Mode.COMMAND) { while (commandState.mode != VimStateMachine.Mode.COMMAND) {
commandState.popModes() commandState.popModes()
} }
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim) VimPlugin.getChange().insertBeforeCursor(it.vim, dataContext.vim)
KeyHandler.getInstance().reset(it.vim) KeyHandler.getInstance().reset(it.vim)
} }
} }

View File

@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@ -36,16 +36,16 @@ import com.maddyhome.idea.vim.helper.getTopLevelEditor
class RiderActionListener : AnActionListener { class RiderActionListener : AnActionListener {
private var editor: Editor? = null private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
} }
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
//region Extend Selection for Rider //region Extend Selection for Rider

View File

@ -36,14 +36,9 @@ 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.impl.EditorComponentImpl import com.intellij.openapi.editor.impl.EditorComponentImpl
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.rd.createLifetime
import com.intellij.openapi.rd.createNestedDisposable
import com.intellij.openapi.util.Disposer
import com.intellij.util.ExceptionUtil import com.intellij.util.ExceptionUtil
import com.jetbrains.rd.util.lifetime.intersect
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
@ -78,6 +73,8 @@ import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipEvents import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipEvents
import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.remove
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
@ -125,9 +122,9 @@ object VimListenerManager {
VimPlugin.getOptionService().addListener(OptionConstants.guicursorName, GuicursorChangeListener) VimPlugin.getOptionService().addListener(OptionConstants.guicursorName, GuicursorChangeListener)
VimPlugin.getOptionService().addListener(OptionConstants.iskeywordName, KeywordOptionChangeListener, true) VimPlugin.getOptionService().addListener(OptionConstants.iskeywordName, KeywordOptionChangeListener, true)
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable) EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance().onOffDisposable) EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance())
} }
fun disable() { fun disable() {
@ -139,6 +136,10 @@ object VimListenerManager {
VimPlugin.getOptionService().removeListener(OptionConstants.showcmdName, ShowCmdOptionChangeListener) VimPlugin.getOptionService().removeListener(OptionConstants.showcmdName, ShowCmdOptionChangeListener)
VimPlugin.getOptionService().removeListener(OptionConstants.guicursorName, GuicursorChangeListener) VimPlugin.getOptionService().removeListener(OptionConstants.guicursorName, GuicursorChangeListener)
VimPlugin.getOptionService().removeListener(OptionConstants.iskeywordName, KeywordOptionChangeListener) VimPlugin.getOptionService().removeListener(OptionConstants.iskeywordName, KeywordOptionChangeListener)
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
EditorFactory.getInstance().eventMulticaster.removeCaretListener(VimCaretListener)
} }
} }
@ -156,26 +157,17 @@ object VimListenerManager {
} }
fun add(editor: Editor) { fun add(editor: Editor) {
val pluginLifetime = VimPlugin.getInstance().createLifetime()
val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
val disposable = editorLifetime.intersect(pluginLifetime).createNestedDisposable("MyLifetimedDisposable")
editor.contentComponent.addKeyListener(VimKeyListener) editor.contentComponent.addKeyListener(VimKeyListener)
Disposer.register(disposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
val eventFacade = EventFacade.getInstance() val eventFacade = EventFacade.getInstance()
eventFacade.addEditorMouseListener(editor, EditorMouseHandler, disposable) eventFacade.addEditorMouseListener(editor, EditorMouseHandler)
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable) eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler)
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable) eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler)
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable) eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener)
VimPlugin.getEditor().editorCreated(editor) VimPlugin.getEditor().editorCreated(editor)
VimPlugin.getChange().editorCreated(editor, disposable) VimPlugin.getChange().editorCreated(IjVimEditor(editor))
Disposer.register(disposable) {
VimPlugin.getEditorIfCreated()?.editorDeinit(editor, true)
}
} }
fun remove(editor: Editor, isReleased: Boolean) { fun remove(editor: Editor, isReleased: Boolean) {
@ -189,7 +181,7 @@ object VimListenerManager {
VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased) VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased)
VimPlugin.getChange().editorReleased(editor) VimPlugin.getChange().editorReleased(IjVimEditor(editor))
} }
} }
@ -221,6 +213,7 @@ object VimListenerManager {
} }
override fun editorReleased(event: EditorFactoryEvent) { override fun editorReleased(event: EditorFactoryEvent) {
remove(event.editor, true)
VimPlugin.getMark().editorReleased(event) VimPlugin.getMark().editorReleased(event)
} }
} }

View File

@ -32,8 +32,8 @@ import com.maddyhome.idea.vim.api.VimChangeGroupBase
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimMotionGroupBase import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.EditorLine import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.IndentConfig import com.maddyhome.idea.vim.common.IndentConfig
import com.maddyhome.idea.vim.common.OperatedRange import com.maddyhome.idea.vim.common.OperatedRange
@ -99,7 +99,6 @@ fun changeRange(
vimCaret.moveToOffset(deletedInfo.leftOffset.point) vimCaret.moveToOffset(deletedInfo.leftOffset.point)
} }
is OperatedRange.Block -> TODO() is OperatedRange.Block -> TODO()
else -> TODO()
} }
if (type == SelectionType.BLOCK_WISE) { if (type == SelectionType.BLOCK_WISE) {
VimPlugin.getChange().setInsertRepeat(lines, col, false) VimPlugin.getChange().setInsertRepeat(lines, col, false)
@ -180,7 +179,7 @@ fun insertLineAround(editor: VimEditor, context: ExecutionContext, shift: Int) {
} }
val position = EditorLine.Offset.init(editor.offsetToLogicalPosition(lineEndOffset).line + shift, editor) val position = EditorLine.Offset.init(editor.offsetToLogicalPosition(lineEndOffset).line + shift, editor)
val insertedLine = editor.addLine(position) val insertedLine = editor.addLine(position) ?: continue
VimPlugin.getChange().saveStrokes("\n") VimPlugin.getChange().saveStrokes("\n")
var lineStart = editor.getLineRange(insertedLine).first var lineStart = editor.getLineRange(insertedLine).first

View File

@ -49,7 +49,6 @@ class IjClipboardManager : VimClipboardManager {
return Pair(res, transferableData) return Pair(res, transferableData)
} }
@Suppress("UNCHECKED_CAST")
override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Any? { override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Any? {
val transferableData1 = (transferableData as List<TextBlockTransferableData>).toMutableList() val transferableData1 = (transferableData as List<TextBlockTransferableData>).toMutableList()
try { try {
@ -98,7 +97,6 @@ class IjClipboardManager : VimClipboardManager {
return transferableData return transferableData
} }
@Suppress("UNCHECKED_CAST")
override fun preprocessText( override fun preprocessText(
vimEditor: VimEditor, vimEditor: VimEditor,
textRange: TextRange, textRange: TextRange,

View File

@ -33,11 +33,11 @@ class IjExecutionContextManager : ExecutionContextManagerBase() {
} }
override fun onCaret(caret: VimCaret, prevContext: ExecutionContext): ExecutionContext { override fun onCaret(caret: VimCaret, prevContext: ExecutionContext): ExecutionContext {
return IjExecutionContext(CaretSpecificDataContext.create(prevContext.ij, caret.ij)) return IjExecutionContext(CaretSpecificDataContext(prevContext.ij, caret.ij))
} }
override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext { override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext {
return IjExecutionContext(CaretSpecificDataContext.create(context.ij, caret.ij)) return IjExecutionContext(CaretSpecificDataContext(context.ij, caret.ij))
} }
override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext { override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext {

View File

@ -22,10 +22,7 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.LogicalPosition import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.CaretRegisterStorage
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
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.VimLogicalPosition import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimVisualPosition import com.maddyhome.idea.vim.api.VimVisualPosition
@ -41,23 +38,13 @@ import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection
import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.registerStorage
import com.maddyhome.idea.vim.helper.vimInsertStart import com.maddyhome.idea.vim.helper.vimInsertStart
import com.maddyhome.idea.vim.helper.vimLastColumn import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange 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
class IjVimCaret(val caret: Caret) : VimCaretBase() { class IjVimCaret(val caret: Caret) : VimCaret {
override val registerStorage: CaretRegisterStorage
get() {
var storage = this.caret.registerStorage
if (storage == null) {
storage = CaretRegisterStorageBase()
this.caret.registerStorage = storage
}
return storage
}
override val editor: VimEditor override val editor: VimEditor
get() = IjVimEditor(caret.editor) get() = IjVimEditor(caret.editor)
override val offset: Offset override val offset: Offset
@ -87,8 +74,6 @@ class IjVimCaret(val caret: Caret) : VimCaretBase() {
} }
override val vimLine: Int override val vimLine: Int
get() = this.caret.vimLine get() = this.caret.vimLine
override val isPrimary: Boolean
get() = editor.primaryCaret().ij == this.caret
override fun moveToOffset(offset: Int) { override fun moveToOffset(offset: Int) {
// TODO: 17.12.2021 Unpack internal actions // TODO: 17.12.2021 Unpack internal actions

View File

@ -38,9 +38,9 @@ import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimSelectionModel import com.maddyhome.idea.vim.api.VimSelectionModel
import com.maddyhome.idea.vim.api.VimVisualPosition import com.maddyhome.idea.vim.api.VimVisualPosition
import com.maddyhome.idea.vim.api.VirtualFile import com.maddyhome.idea.vim.api.VirtualFile
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.EditorLine import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.LiveRange import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset import com.maddyhome.idea.vim.common.Offset
@ -62,9 +62,7 @@ import com.maddyhome.idea.vim.helper.updateCaretsVisualPosition
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
import com.maddyhome.idea.vim.helper.vimKeepingVisualOperatorAction import com.maddyhome.idea.vim.helper.vimKeepingVisualOperatorAction
import com.maddyhome.idea.vim.helper.vimLastSelectionType import com.maddyhome.idea.vim.helper.vimLastSelectionType
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class IjVimEditor(editor: Editor) : MutableLinearEditor() { class IjVimEditor(editor: Editor) : MutableLinearEditor() {
// All the editor actions should be performed with top level editor!!! // All the editor actions should be performed with top level editor!!!

View File

@ -68,15 +68,15 @@ import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.history.VimHistory import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.put.VimPut import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.ui.VimRcFileState import com.maddyhome.idea.vim.ui.VimRcFileState
import com.maddyhome.idea.vim.undo.VimUndoRedo import com.maddyhome.idea.vim.undo.VimUndoRedo
import com.maddyhome.idea.vim.vimscript.Executor import com.maddyhome.idea.vim.vimscript.Executor
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.OptionService
import com.maddyhome.idea.vim.vimscript.services.PatternService import com.maddyhome.idea.vim.vimscript.services.PatternService
import com.maddyhome.idea.vim.vimscript.services.VariableService import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.yank.VimYankGroup import com.maddyhome.idea.vim.yank.VimYankGroup
class IjVimInjector : VimInjectorBase() { class IjVimInjector : VimInjectorBase() {
@ -161,7 +161,7 @@ class IjVimInjector : VimInjectorBase() {
override val functionService: VimscriptFunctionService override val functionService: VimscriptFunctionService
get() = FunctionStorage get() = FunctionStorage
override val variableService: VariableService override val variableService: VimVariableService
get() = service() get() = service()
override val vimrcFileState: VimrcFileState override val vimrcFileState: VimrcFileState
get() = VimRcFileState get() = VimRcFileState

View File

@ -37,19 +37,19 @@ class IjVimMessages : VimMessagesBase() {
private var error = false private var error = false
private var lastBeepTimeMillis = 0L private var lastBeepTimeMillis = 0L
override fun showStatusBarMessage(message: String?) { override fun showStatusBarMessage(msg: String?) {
if (ApplicationManager.getApplication().isUnitTestMode) { if (ApplicationManager.getApplication().isUnitTestMode) {
this.message = message message = msg
} }
val pm = ProjectManager.getInstance() val pm = ProjectManager.getInstance()
val projects = pm.openProjects val projects = pm.openProjects
for (project in projects) { for (project in projects) {
val bar = WindowManager.getInstance().getStatusBar(project) val bar = WindowManager.getInstance().getStatusBar(project)
if (bar != null) { if (bar != null) {
if (message.isNullOrEmpty()) { if (msg.isNullOrEmpty()) {
bar.info = "" bar.info = ""
} else { } else {
bar.info = "VIM - $message" bar.info = "VIM - $msg"
} }
} }
} }

View File

@ -3,14 +3,14 @@ package com.maddyhome.idea.vim.newapi
import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimSearchHelperBase import com.maddyhome.idea.vim.api.VimSearchHelper
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.SearchHelper import com.maddyhome.idea.vim.helper.SearchHelper
import com.maddyhome.idea.vim.helper.SearchOptions import com.maddyhome.idea.vim.helper.SearchOptions
import java.util.* import java.util.*
@Service @Service
class IjVimSearchHelper : VimSearchHelperBase() { class IjVimSearchHelper : VimSearchHelper {
override fun findNextParagraph(editor: VimEditor, caret: VimCaret, count: Int, allowBlanks: Boolean): Int { override fun findNextParagraph(editor: VimEditor, caret: VimCaret, count: Int, allowBlanks: Boolean): Int {
return SearchHelper.findNextParagraph( return SearchHelper.findNextParagraph(
(editor as IjVimEditor).editor, (editor as IjVimEditor).editor,
@ -121,6 +121,15 @@ class IjVimSearchHelper : VimSearchHelperBase() {
return SearchHelper.findNextWordEnd(chars, pos, size, count, bigWord, spaceWords) return SearchHelper.findNextWordEnd(chars, pos, size, count, bigWord, spaceWords)
} }
override fun findNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Int {
return SearchHelper.findNextWord(
(editor as IjVimEditor).editor,
searchFrom,
count,
bigWord
)
}
override fun findPattern( override fun findPattern(
editor: VimEditor, editor: VimEditor,
pattern: String?, pattern: String?,

View File

@ -22,25 +22,18 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.smartcaseName import com.maddyhome.idea.vim.options.OptionConstants.Companion.smartcaseName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutlenName
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
/** /**
* COMPATIBILITY-LAYER: Added a class and package * COMPATIBILITY-LAYER: Added a class and package
* Please see: https://jb.gg/zo8n0r
*/ */
object OptionsManager { object OptionsManager {
val ignorecase: ToggleOption val ignorecase: ToggleOption
get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(ignorecaseName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getRawOption(ignorecaseName) as ToggleOption
val smartcase: ToggleOption val smartcase: ToggleOption
get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(smartcaseName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getRawOption(smartcaseName) as ToggleOption
val timeout: ToggleOption
get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(timeoutName) as ToggleOption
val timeoutlen: NumberOption
get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(timeoutlenName) as NumberOption
val iskeyword: KeywordOption val iskeyword: KeywordOption
get() = KeywordOption(KeywordOptionHelper) get() = KeywordOption(KeywordOptionHelper)
} }

View File

@ -18,7 +18,6 @@
package com.maddyhome.idea.vim.statistic package com.maddyhome.idea.vim.statistic
import com.intellij.internal.statistic.collectors.fus.actions.persistence.ActionRuleValidator
import com.intellij.internal.statistic.eventLog.EventLogGroup import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.events.EventFields import com.intellij.internal.statistic.eventLog.events.EventFields
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
@ -26,14 +25,8 @@ import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesColle
internal class ActionTracker : CounterUsagesCollector() { internal class ActionTracker : CounterUsagesCollector() {
companion object { companion object {
private val GROUP = EventLogGroup("vim.actions", 1) private val GROUP = EventLogGroup("vim.actions", 1)
private val TRACKED_ACTIONS = GROUP.registerEvent( private val TRACKED_ACTIONS = GROUP.registerEvent("tracked", EventFields.StringValidatedByCustomRule("action_id", "action"))
"tracked", private val COPIED_ACTIONS = GROUP.registerEvent("copied", EventFields.StringValidatedByCustomRule("action_id", "action"))
EventFields.StringValidatedByCustomRule("action_id", ActionRuleValidator::class.java)
)
private val COPIED_ACTIONS = GROUP.registerEvent(
"copied",
EventFields.StringValidatedByCustomRule("action_id", ActionRuleValidator::class.java)
)
fun logTrackedAction(actionId: String) { fun logTrackedAction(actionId: String) {
TRACKED_ACTIONS.log(actionId) TRACKED_ACTIONS.log(actionId)

View File

@ -21,14 +21,15 @@ package com.maddyhome.idea.vim.statistic
import com.intellij.internal.statistic.beans.MetricEvent import com.intellij.internal.statistic.beans.MetricEvent
import com.intellij.internal.statistic.eventLog.EventLogGroup import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.events.EventFields import com.intellij.internal.statistic.eventLog.events.EventFields
import com.intellij.internal.statistic.eventLog.events.EventPair
import com.intellij.internal.statistic.eventLog.events.StringListEventField
import com.intellij.internal.statistic.eventLog.events.VarargEventId
import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.key.ShortcutOwner import com.maddyhome.idea.vim.key.ShortcutOwner
import com.maddyhome.idea.vim.key.ShortcutOwnerInfo import com.maddyhome.idea.vim.key.ShortcutOwnerInfo
import java.awt.event.InputEvent
import java.awt.event.InputEvent.CTRL_DOWN_MASK import java.awt.event.InputEvent.CTRL_DOWN_MASK
import java.awt.event.InputEvent.SHIFT_DOWN_MASK import java.awt.event.InputEvent.SHIFT_DOWN_MASK
import java.awt.event.KeyEvent
import javax.swing.KeyStroke import javax.swing.KeyStroke
internal class ShortcutConflictState : ApplicationUsagesCollector() { internal class ShortcutConflictState : ApplicationUsagesCollector() {
@ -36,15 +37,93 @@ internal class ShortcutConflictState : ApplicationUsagesCollector() {
override fun getGroup(): EventLogGroup = GROUP override fun getGroup(): EventLogGroup = GROUP
override fun getMetrics(): Set<MetricEvent> { override fun getMetrics(): Set<MetricEvent> {
val metrics = mutableSetOf<MetricEvent>() return setOf(
keyStrokes.forEach { keystroke -> HANDLERS.metric(
getHandlersForShortcut(keystroke) CTRL_1 withKeyStroke KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK),
.filter { !setOf(HandledModes.INSERT_UNDEFINED, HandledModes.NORMAL_UNDEFINED, HandledModes.VISUAL_AND_SELECT_UNDEFINED).contains(it) } CTRL_2 withKeyStroke KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK),
.forEach { mode -> CTRL_3 withKeyStroke KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK),
metrics += HANDLER.metric(keystroke.toReadableString(), mode) CTRL_4 withKeyStroke KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK),
} CTRL_5 withKeyStroke KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK),
} CTRL_6 withKeyStroke KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK),
return metrics CTRL_7 withKeyStroke KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK),
CTRL_8 withKeyStroke KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK),
CTRL_9 withKeyStroke KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK),
CTRL_0 withKeyStroke KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK),
CTRL_SHIFT_1 withKeyStroke KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_2 withKeyStroke KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_3 withKeyStroke KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_4 withKeyStroke KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_5 withKeyStroke KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_6 withKeyStroke KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_7 withKeyStroke KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_8 withKeyStroke KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_9 withKeyStroke KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_0 withKeyStroke KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_A withKeyStroke KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK),
CTRL_B withKeyStroke KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK),
CTRL_C withKeyStroke KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK),
CTRL_D withKeyStroke KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK),
CTRL_E withKeyStroke KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK),
CTRL_F withKeyStroke KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK),
CTRL_G withKeyStroke KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK),
CTRL_H withKeyStroke KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK),
CTRL_I withKeyStroke KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK),
CTRL_J withKeyStroke KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK),
CTRL_K withKeyStroke KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK),
CTRL_L withKeyStroke KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK),
CTRL_M withKeyStroke KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK),
CTRL_N withKeyStroke KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK),
CTRL_O withKeyStroke KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK),
CTRL_P withKeyStroke KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK),
CTRL_Q withKeyStroke KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK),
CTRL_R withKeyStroke KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK),
CTRL_S withKeyStroke KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK),
CTRL_T withKeyStroke KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK),
CTRL_U withKeyStroke KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK),
CTRL_V withKeyStroke KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK),
CTRL_W withKeyStroke KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK),
CTRL_X withKeyStroke KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK),
CTRL_Y withKeyStroke KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK),
CTRL_Z withKeyStroke KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK),
CTRL_BR1 withKeyStroke KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK),
CTRL_BR2 withKeyStroke KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK),
CTRL_SHIFT_A withKeyStroke KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_B withKeyStroke KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_C withKeyStroke KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_D withKeyStroke KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_E withKeyStroke KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_F withKeyStroke KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_G withKeyStroke KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_H withKeyStroke KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_I withKeyStroke KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_J withKeyStroke KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_K withKeyStroke KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_L withKeyStroke KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_M withKeyStroke KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_N withKeyStroke KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_O withKeyStroke KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_P withKeyStroke KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_Q withKeyStroke KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_R withKeyStroke KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_S withKeyStroke KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_T withKeyStroke KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_U withKeyStroke KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_V withKeyStroke KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_W withKeyStroke KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_X withKeyStroke KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_Y withKeyStroke KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_Z withKeyStroke KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_BR1 withKeyStroke KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
CTRL_SHIFT_BR2 withKeyStroke KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK),
)
)
}
private infix fun StringListEventField.withKeyStroke(ks: KeyStroke): EventPair<List<String>> {
return this.with(getHandlersForShortcut(ks).map { it.name })
} }
private fun getHandlersForShortcut(shortcut: KeyStroke): List<HandledModes> { private fun getHandlersForShortcut(shortcut: KeyStroke): List<HandledModes> {
@ -83,105 +162,173 @@ internal class ShortcutConflictState : ApplicationUsagesCollector() {
companion object { companion object {
private val GROUP = EventLogGroup("vim.handlers", 1) private val GROUP = EventLogGroup("vim.handlers", 1)
private val values = HandledModes.values().map { it.name }
private val keyStrokes = listOf( private val CTRL_1 = EventFields.StringList("Ctrl-1", values)
KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK), private val CTRL_2 = EventFields.StringList("Ctrl-2", values)
KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK), private val CTRL_3 = EventFields.StringList("Ctrl-3", values)
KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK), private val CTRL_4 = EventFields.StringList("Ctrl-4", values)
KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK), private val CTRL_5 = EventFields.StringList("Ctrl-5", values)
KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK), private val CTRL_6 = EventFields.StringList("Ctrl-6", values)
KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK), private val CTRL_7 = EventFields.StringList("Ctrl-7", values)
KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK), private val CTRL_8 = EventFields.StringList("Ctrl-8", values)
KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK), private val CTRL_9 = EventFields.StringList("Ctrl-9", values)
KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK), private val CTRL_0 = EventFields.StringList("Ctrl-0", values)
KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK),
KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_1 = EventFields.StringList("Ctrl-Shift-1", values)
KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_2 = EventFields.StringList("Ctrl-Shift-2", values)
KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_3 = EventFields.StringList("Ctrl-Shift-3", values)
KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_4 = EventFields.StringList("Ctrl-Shift-4", values)
KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_5 = EventFields.StringList("Ctrl-Shift-5", values)
KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_6 = EventFields.StringList("Ctrl-Shift-6", values)
KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_7 = EventFields.StringList("Ctrl-Shift-7", values)
KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_8 = EventFields.StringList("Ctrl-Shift-8", values)
KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_9 = EventFields.StringList("Ctrl-Shift-9", values)
KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_0 = EventFields.StringList("Ctrl-Shift-0", values)
KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK), private val CTRL_A = EventFields.StringList("Ctrl-A", values)
KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK), private val CTRL_B = EventFields.StringList("Ctrl-B", values)
KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK), private val CTRL_C = EventFields.StringList("Ctrl-C", values)
KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK), private val CTRL_D = EventFields.StringList("Ctrl-D", values)
KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK), private val CTRL_E = EventFields.StringList("Ctrl-E", values)
KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK), private val CTRL_F = EventFields.StringList("Ctrl-F", values)
KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK), private val CTRL_G = EventFields.StringList("Ctrl-G", values)
KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK), private val CTRL_H = EventFields.StringList("Ctrl-H", values)
KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK), private val CTRL_I = EventFields.StringList("Ctrl-I", values)
KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK), private val CTRL_J = EventFields.StringList("Ctrl-J", values)
KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK), private val CTRL_K = EventFields.StringList("Ctrl-K", values)
KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK), private val CTRL_L = EventFields.StringList("Ctrl-L", values)
KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK), private val CTRL_M = EventFields.StringList("Ctrl-M", values)
KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK), private val CTRL_N = EventFields.StringList("Ctrl-N", values)
KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK), private val CTRL_O = EventFields.StringList("Ctrl-O", values)
KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK), private val CTRL_P = EventFields.StringList("Ctrl-P", values)
KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK), private val CTRL_Q = EventFields.StringList("Ctrl-Q", values)
KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK), private val CTRL_R = EventFields.StringList("Ctrl-R", values)
KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK), private val CTRL_S = EventFields.StringList("Ctrl-S", values)
KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK), private val CTRL_T = EventFields.StringList("Ctrl-T", values)
KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK), private val CTRL_U = EventFields.StringList("Ctrl-U", values)
KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK), private val CTRL_V = EventFields.StringList("Ctrl-V", values)
KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK), private val CTRL_W = EventFields.StringList("Ctrl-W", values)
KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK), private val CTRL_X = EventFields.StringList("Ctrl-X", values)
KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK), private val CTRL_Y = EventFields.StringList("Ctrl-Y", values)
KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK), private val CTRL_Z = EventFields.StringList("Ctrl-Z", values)
KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK), private val CTRL_BR1 = EventFields.StringList("Ctrl-[", values)
KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK), private val CTRL_BR2 = EventFields.StringList("Ctrl-]", values)
KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_A = EventFields.StringList("Ctrl-Shift-A", values)
KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_B = EventFields.StringList("Ctrl-Shift-B", values)
KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_C = EventFields.StringList("Ctrl-Shift-C", values)
KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_D = EventFields.StringList("Ctrl-Shift-D", values)
KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_E = EventFields.StringList("Ctrl-Shift-E", values)
KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_F = EventFields.StringList("Ctrl-Shift-F", values)
KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_G = EventFields.StringList("Ctrl-Shift-G", values)
KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_H = EventFields.StringList("Ctrl-Shift-H", values)
KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_I = EventFields.StringList("Ctrl-Shift-I", values)
KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_J = EventFields.StringList("Ctrl-Shift-J", values)
KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_K = EventFields.StringList("Ctrl-Shift-K", values)
KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_L = EventFields.StringList("Ctrl-Shift-L", values)
KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_M = EventFields.StringList("Ctrl-Shift-M", values)
KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_N = EventFields.StringList("Ctrl-Shift-N", values)
KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_O = EventFields.StringList("Ctrl-Shift-O", values)
KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_P = EventFields.StringList("Ctrl-Shift-P", values)
KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_Q = EventFields.StringList("Ctrl-Shift-Q", values)
KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_R = EventFields.StringList("Ctrl-Shift-R", values)
KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_S = EventFields.StringList("Ctrl-Shift-S", values)
KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_T = EventFields.StringList("Ctrl-Shift-T", values)
KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_U = EventFields.StringList("Ctrl-Shift-U", values)
KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_V = EventFields.StringList("Ctrl-Shift-V", values)
KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_W = EventFields.StringList("Ctrl-Shift-W", values)
KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_X = EventFields.StringList("Ctrl-Shift-X", values)
KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_Y = EventFields.StringList("Ctrl-Shift-Y", values)
KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_Z = EventFields.StringList("Ctrl-Shift-Z", values)
KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_BR1 = EventFields.StringList("Ctrl-Shift-[", values)
KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), private val CTRL_SHIFT_BR2 = EventFields.StringList("Ctrl-Shift-]", values)
private val HANDLERS: VarargEventId = GROUP.registerVarargEvent(
"vim.handlers",
CTRL_1,
CTRL_2,
CTRL_3,
CTRL_4,
CTRL_5,
CTRL_6,
CTRL_7,
CTRL_8,
CTRL_9,
CTRL_0,
CTRL_SHIFT_1,
CTRL_SHIFT_2,
CTRL_SHIFT_3,
CTRL_SHIFT_4,
CTRL_SHIFT_5,
CTRL_SHIFT_6,
CTRL_SHIFT_7,
CTRL_SHIFT_8,
CTRL_SHIFT_9,
CTRL_SHIFT_0,
CTRL_A,
CTRL_B,
CTRL_C,
CTRL_D,
CTRL_E,
CTRL_F,
CTRL_G,
CTRL_H,
CTRL_I,
CTRL_J,
CTRL_K,
CTRL_L,
CTRL_M,
CTRL_N,
CTRL_O,
CTRL_P,
CTRL_Q,
CTRL_R,
CTRL_S,
CTRL_T,
CTRL_U,
CTRL_V,
CTRL_W,
CTRL_X,
CTRL_Y,
CTRL_Z,
CTRL_BR1,
CTRL_BR2,
CTRL_SHIFT_A,
CTRL_SHIFT_B,
CTRL_SHIFT_C,
CTRL_SHIFT_D,
CTRL_SHIFT_E,
CTRL_SHIFT_F,
CTRL_SHIFT_G,
CTRL_SHIFT_H,
CTRL_SHIFT_I,
CTRL_SHIFT_J,
CTRL_SHIFT_K,
CTRL_SHIFT_L,
CTRL_SHIFT_M,
CTRL_SHIFT_N,
CTRL_SHIFT_O,
CTRL_SHIFT_P,
CTRL_SHIFT_Q,
CTRL_SHIFT_R,
CTRL_SHIFT_S,
CTRL_SHIFT_T,
CTRL_SHIFT_U,
CTRL_SHIFT_V,
CTRL_SHIFT_W,
CTRL_SHIFT_X,
CTRL_SHIFT_Y,
CTRL_SHIFT_Z,
CTRL_SHIFT_BR1,
CTRL_SHIFT_BR2,
) )
private val KEY_STROKE = EventFields.String("key_stroke", keyStrokes.map { it.toReadableString() })
private val HANDLER_MODE = EventFields.Enum<HandledModes>("handler")
private val HANDLER = GROUP.registerEvent("vim.handler", KEY_STROKE, HANDLER_MODE)
} }
} }
private fun KeyStroke.toReadableString(): String {
val result = StringBuilder()
val modifiers = this.modifiers
if (modifiers > 0) {
result.append(InputEvent.getModifiersExText(modifiers))
.append("+")
}
result.append(KeyEvent.getKeyText(this.keyCode))
return result.toString()
}
private enum class HandledModes { private enum class HandledModes {
NORMAL_UNDEFINED, NORMAL_UNDEFINED,
NORMAL_IDE, NORMAL_IDE,

Some files were not shown because too many files have changed in this diff Show More