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

Compare commits

..

56 Commits

Author SHA1 Message Date
aleksei.plate
86bf723791 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-20 11:36:12 +00:00
Alex Plate
71f2e9de4a Update changelog 2022-07-20 08:20:43 +00:00
Alex Plate
33d3f270a3
Fix(VIM-2710): Show options value on set opt 2022-07-20 09:56:23 +03:00
filipp
da94edd386 Fix(VIM-2703) 2022-07-20 02:51:45 +06:00
Alex Plate
90dfaefd11 Update formatting 2022-07-17 00:17:41 +00:00
Alex Plate
8bc616cc55
New vim behaviour: ci( searches for brackets
Change in vim:
b9115da4be
https://github.com/vim/vim/pull/8670

VIM-2699
2022-07-14 12:08:26 +03:00
aleksei.plate
a9e79d62c5 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-13 11:55:31 +00:00
Alex Plate
1998221a0b
Remove useless @NotNull annotations 2022-07-13 10:26:57 +03:00
Alex Plate
a9b1625749
Update deprecated action listeners 2022-07-13 10:26:16 +03:00
Alex Plate
b411836570
Hide macos notification during UI testing 2022-07-13 09:23:35 +03:00
Alex Plate
df7e0221a8
Update qodana baseline 2022-07-11 14:10:08 +03:00
aleksei.plate
8ff8f2b685 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-11 10:00:37 +00:00
aleksei.plate
65dea7e3f7 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-11 09:45:28 +00:00
aleksei.plate
1942f86633 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim / IdeaVim releases' project: build features of 'Publish EAP Build' build configuration were updated 2022-07-11 08:29:56 +00:00
Alex Plate
ee4ce5033a
Fix tests 2022-07-11 11:09:43 +03:00
Alex Plate
040fe806c8
Update release versions of IJ 2022-07-11 09:28:39 +03:00
Alex Plate
97f5c9225e
Cleanup the sources 2022-07-08 11:24:10 +03:00
Alex Plate
09b86c15f9
Fix missing space 2022-07-08 10:59:02 +03:00
Alex Plate
8f34285d8c
Fix issues with notations 2022-07-08 10:55:21 +03:00
Alex Plate
d3c3b71e3e
Remove unnecessary libraries from the distribution 2022-07-08 10:29:51 +03:00
Alex Plate
aa6f49c9b1
Reformat code 2022-07-08 10:00:00 +03:00
Alex Plate
c011628420
Reformat code 2022-07-08 09:14:43 +03:00
Alex Plate
1c9fa9d662
Skip one test in multicaret 2022-07-07 16:32:14 +03:00
Alex Plate
7b9bc64364
Fix multicaret insert 2022-07-07 14:54:41 +03:00
Alex Plate
729062bfdd
Turn on ideadelaymacro by default 2022-07-07 14:36:04 +03:00
Alex Plate
bc6c726a45
Fix macro with count execution 2022-07-07 14:35:49 +03:00
Alex Plate
dfc3df713e
Update changelog 2022-07-07 12:22:46 +03:00
Alex Plate
42eca1d5f2
Apply TC patches 2022-07-07 11:20:10 +03:00
Alex Plate
66245e2730
Change secret for the merge PR action 2022-07-07 10:42:27 +03:00
aleksei.plate
d44b82c1d1 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Plugin verification' build configuration settings were updated 2022-07-07 07:12:38 +00:00
aleksei.plate
5440e48fa3 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Tests for IntelliJ 2021.3' build configuration was moved to 'IntelliJ IDEA plugins / IdeaVim / Old IdeaVim tests' project 2022-07-07 07:11:51 +00:00
aleksei.plate
1c513cf8aa TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'Tests for IntelliJ 2021.3' build configuration were updated 2022-07-07 07:11:26 +00:00
aleksei.plate
a17c4b8d43 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'Tests for IntelliJ 2021.3' build configuration were updated 2022-07-07 07:11:07 +00:00
aleksei.plate
15eb4ac278 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'https://github.com/JetBrains/ideavim (branch 213-221)' VCS root was created 2022-07-07 07:06:47 +00:00
Alex Plate
0d9b81eab3
Update minimal version of IJ 2022-07-07 10:02:14 +03:00
Alex Plate
f02e1a20c7
Create test update job 2022-07-06 21:23:48 +03:00
Alex Plate
a11991dad7
Create test token 2022-07-06 21:21:51 +03:00
Alex Plate
1238828bfd
Update token name 2022-07-06 21:18:27 +03:00
Alex Plate
ba409cb24c
Add some logging to update after PR job 2022-07-06 21:06:00 +03:00
Alex Plate
d597670275 Update changelog after merging PR 2022-07-06 17:58:16 +00:00
Alex Pláte
d8540e95f8 Create gradle.properties 2022-07-06 20:56:49 +03:00
Alex Plate
d35ebf00dd
Add qodana baseline to the project (I guess) 2022-07-06 20:43:40 +03:00
Alex Plate
2b32cb26b1
Set since version in config 2022-07-06 20:39:30 +03:00
aleksei.plate
ca95fcb658 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Tests with nvim' build configuration were updated 2022-07-06 17:32:40 +00:00
aleksei.plate
cc18bbd168 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Tests with nvim' build configuration settings were updated 2022-07-06 17:09:16 +00:00
Alex Plate
8c8ea800cb
Update neovim tests 2022-07-06 20:06:02 +03:00
Alex Plate
0746dcc686
Fix some neovim tests 2022-07-06 19:41:05 +03:00
Alex Plate
930650be9d Add lippfi to contributors list 2022-07-06 07:36:26 +00:00
Alex Plate
4e3a9ffa40
Add unchecked email 2022-07-06 10:34:31 +03:00
filipp
3bf68a2bb8 Update formatting 2022-07-06 13:11:11 +06:00
Alex Plate
a80f6feab0
Update changelog 2022-07-06 09:30:25 +03:00
Alex Plate
3cf8ae52ed
Add link to the docs 2022-07-06 09:30:25 +03:00
Matt Ellis
62632a4514 Improve handling of fractional width fonts 2022-07-06 09:29:36 +03:00
Alex Plate
249bd3778a
Add a note about refactoring 2022-07-06 09:14:52 +03:00
filipp
ab9e5d7a4a Fix selection issue with oldundo set 2022-07-06 12:12:55 +06:00
filipp
083b7dc952 Fix(VIM-2698) Undo causes confirmation dialog to reappear forever 2022-07-06 11:35:29 +06:00
345 changed files with 83750 additions and 3164 deletions

View File

@ -4,6 +4,7 @@
name: Update Changelog On PR name: Update Changelog On PR
on: on:
workflow_dispatch:
pull_request: pull_request:
types: [ closed ] types: [ closed ]
@ -29,7 +30,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.AUTOMATION_TOKEN }} GITHUB_OAUTH: ${{ secrets.MERGE_PR }}
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4

40
.github/workflows/mergePrTest.yml vendored Normal file
View File

@ -0,0 +1,40 @@
# 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.AUTOMATION_TOKEN }} GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4

View File

@ -13,11 +13,8 @@ object Constants {
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 = "2022.1.3" const val RELEASE = "LATEST-EAP-SNAPSHOT"
const val RELEASE_DEV = "LATEST-EAP-SNAPSHOT"
// Use LATEST-EAP-SNAPSHOT only when we'll update the minimum version of IJ to 222+ const val RELEASE_EAP = "LATEST-EAP-SNAPSHOT"
// 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,6 +1,12 @@
package _Self package _Self
import _Self.buildTypes.* import _Self.buildTypes.Compatibility
import _Self.buildTypes.LongRunning
import _Self.buildTypes.Nvim
import _Self.buildTypes.PluginVerifier
import _Self.buildTypes.PropertyBased
import _Self.buildTypes.Qodana
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
@ -10,6 +16,7 @@ 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
@ -26,11 +33,11 @@ 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(PropertyBased) buildType(PropertyBased)
@ -38,6 +45,7 @@ object Project : Project({
buildType(Nvim) buildType(Nvim)
buildType(PluginVerifier) buildType(PluginVerifier)
buildType(Compatibility)
buildType(Qodana) buildType(Qodana)
@ -47,7 +55,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-0d1a6a32faa92923e") param("amazon-id", "ami-0fa17ce8238eb8868")
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 TestsForIntelliJ20213 : ActiveTests("Tests for IntelliJ 2021.3", "2021.3.2") //object TestsForIntelliJ20213 : ActiveTests("Tests for IntelliJ 2021.3", "2021.3.2")

View File

@ -1,29 +1,23 @@
package patches.buildTypes package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType 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.buildFeatures.golang
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/* object Compatibility : BuildType({
This patch script was generated by TeamCity on settings change in UI. id("IdeaVimCompatibility")
To apply the patch, create a buildType with id = 'Build' name = "IdeaVim compatibility with external plugins"
in the root project, and delete the patch script.
*/
create(DslContext.projectId, BuildType({
id("Build")
name = "IdeaVim compatibility with external plugins"
vcs { vcs {
root(DslContext.settingsRoot) root(DslContext.settingsRoot)
} }
steps { steps {
script { script {
name = "Check" name = "Check"
scriptContent = """ 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 '${'$'}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 '${'$'}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 '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
@ -33,24 +27,23 @@ create(DslContext.projectId, BuildType({
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.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 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
""".trimIndent() """.trimIndent()
}
} }
}
triggers { triggers {
schedule { schedule {
schedulingPolicy = daily { schedulingPolicy = daily {
hour = 4 hour = 4
} }
branchFilter = "" branchFilter = ""
triggerBuild = always() triggerBuild = always()
withPendingChangesOnly = false withPendingChangesOnly = false
}
} }
}
features { features {
golang { golang {
testFormat = "json" 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.4.4/nvim-linux64.tar.gz wget https://github.com/neovim/neovim/releases/download/v0.7.2/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,6 +4,7 @@ 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
@ -46,12 +47,15 @@ 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 = false enabled = true
branchFilter = "" branchFilter = ""
} }
schedule { schedule {

View File

@ -0,0 +1,62 @@
@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,6 +11,7 @@ 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({
@ -28,4 +29,5 @@ object OldTests : Project({
buildType(TestsForIntelliJ20203) buildType(TestsForIntelliJ20203)
buildType(TestsForIntelliJ20211) buildType(TestsForIntelliJ20211)
buildType(TestsForIntelliJ20212) buildType(TestsForIntelliJ20212)
buildType(TestsForIntelliJ20213)
}) })

View File

@ -0,0 +1,12 @@
@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"
})

View File

@ -1,25 +0,0 @@
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

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

View File

@ -0,0 +1,27 @@
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
}
}
}

View File

@ -1,74 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -1,23 +0,0 @@
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

@ -416,6 +416,10 @@ 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

@ -36,6 +36,7 @@ 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-^
@ -57,6 +58,7 @@ usual beta standards.
* [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`
### 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
@ -66,6 +68,8 @@ 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
## 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/). support the new [Fleet IDE](https://www.jetbrains.com/fleet/). Please see [Fleet refactoring](#Fleet-refactoring).
## Before you begin ## Before you begin
@ -120,6 +120,17 @@ 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

@ -28,7 +28,7 @@ plugins {
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.2.1" id("org.jlleitschuh.gradle.ktlint") version "10.3.0"
} }
// Import variables from gradle.properties file // Import variables from gradle.properties file
@ -71,6 +71,8 @@ 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 {
@ -85,6 +87,8 @@ 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") {
@ -115,6 +119,8 @@ 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) {
@ -144,7 +150,7 @@ tasks {
compileKotlin { compileKotlin {
kotlinOptions { kotlinOptions {
jvmTarget = javaVersion jvmTarget = javaVersion
apiVersion = "1.5" apiVersion = "1.6"
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility") freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
// allWarningsAsErrors = true // allWarningsAsErrors = true
} }
@ -152,7 +158,7 @@ tasks {
compileTestKotlin { compileTestKotlin {
kotlinOptions { kotlinOptions {
jvmTarget = javaVersion jvmTarget = javaVersion
apiVersion = "1.5" apiVersion = "1.6"
// allWarningsAsErrors = true // allWarningsAsErrors = true
} }
} }
@ -200,7 +206,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 {
@ -231,12 +237,18 @@ 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
@ -327,7 +339,8 @@ tasks.register("updateAuthors") {
"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)
} }
@ -338,6 +351,7 @@ 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")
@ -501,7 +515,9 @@ 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

@ -5,9 +5,10 @@ downloadIdeaSources=true
instrumentPluginCode=true instrumentPluginCode=true
version=SNAPSHOT version=SNAPSHOT
javaVersion=11 javaVersion=11
remoteRobotVersion=0.11.10 remoteRobotVersion=0.11.15
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
kotlinVersion=1.6.21 kotlinVersion=1.6.21
publishToken=token publishToken=token

79982
qodana.sarif.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -101,12 +101,6 @@ public class EventFacade {
EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable);
} }
@SuppressWarnings("deprecation")
public void removeEditorFactoryListener(@NotNull EditorFactoryListener listener) {
// Listener is removed not only if application is disposed
EditorFactory.getInstance().removeEditorFactoryListener(listener);
}
public void addEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) { public void addEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) {
editor.addEditorMouseListener(listener); editor.addEditorMouseListener(listener);
} }

View File

@ -19,8 +19,6 @@ package com.maddyhome.idea.vim;
import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.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;
@ -32,9 +30,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;
@ -49,7 +47,6 @@ 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.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;
@ -60,8 +57,6 @@ 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;
@ -94,6 +89,8 @@ 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();
} }
@ -341,6 +338,8 @@ 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);
@ -376,6 +375,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
// 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;
@ -389,7 +390,9 @@ 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)) {
if (VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) { // This system property is used in IJ ui robot to hide the startup tips
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);
} }
@ -408,12 +411,6 @@ 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

@ -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)) res[0] = false if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)) 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)) res[0] = false if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) res[0] = false
}, },
true true
) )

View File

@ -57,7 +57,14 @@ 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(editor, caret, range.toVimTextRange(true).normalize(), false)) { if (!injector.changeGroup.deleteJoinRange(
editor,
caret,
range.toVimTextRange(true).normalize(),
false,
operatorArguments
)
) {
res[0] = false res[0] = false
} }
}, true }, true

View File

@ -56,7 +56,14 @@ 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(editor, caret, range.toVimTextRange(true).normalize(), true)) { if (!injector.changeGroup.deleteJoinRange(
editor,
caret,
range.toVimTextRange(true).normalize(),
true,
operatorArguments
)
) {
res[0] = false res[0] = false
} }
}, },

View File

@ -18,6 +18,7 @@
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
@ -124,7 +125,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) editor.myFractionalMetricsHintValue else RenderingHints.VALUE_FRACTIONALMETRICS_OFF if (editor is EditorImpl) UISettings.editorFractionalMetricsHint else RenderingHints.VALUE_FRACTIONALMETRICS_OFF
) )
} }

View File

@ -24,6 +24,7 @@ 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) {

View File

@ -61,6 +61,7 @@ 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

View File

@ -26,6 +26,7 @@ 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

@ -44,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.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.key.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

View File

@ -26,6 +26,7 @@ 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,8 +39,10 @@ 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
@ -171,7 +174,15 @@ class ReplaceWithRegister : VimExtension {
putToLine = -1 putToLine = -1
) )
ClipboardOptionHelper.IdeaputDisabler().use { ClipboardOptionHelper.IdeaputDisabler().use {
VimPlugin.getPut().putText(IjVimEditor(editor), IjExecutionContext(EditorDataContext.init(editor)), putData) VimPlugin.getPut().putText(
IjVimEditor(editor),
IjExecutionContext(EditorDataContext.init(editor)),
putData,
operatorArguments = OperatorArguments(
editor.vimStateMachine?.isOperatorPending ?: false,
0, editor.editorMode, editor.subMode
)
)
} }
caret.registerStorage.saveRegister(savedRegister.name, savedRegister) caret.registerStorage.saveRegister(savedRegister.name, savedRegister)

View File

@ -245,7 +245,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); final boolean res = deleteCharacter(editor, caret, 1, true, operatorArguments);
if (res) { if (res) {
editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT); editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT);
} }
@ -306,7 +306,8 @@ 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,
operatorArguments);
} }
} }
@ -425,10 +426,11 @@ 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
@ -436,7 +438,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret, @NotNull VimCaret caret,
@NotNull TextRange range, @NotNull TextRange range,
@NotNull SelectionType type, @NotNull SelectionType type,
ExecutionContext context) { @Nullable ExecutionContext context,
@NotNull OperatorArguments operatorArguments) {
int col = 0; int col = 0;
int lines = 0; int lines = 0;
if (type == SelectionType.BLOCK_WISE) { if (type == SelectionType.BLOCK_WISE) {
@ -450,7 +453,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); boolean res = deleteRange(editor, caret, range, type, true, operatorArguments);
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
@ -586,10 +589,11 @@ 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); indentRange(editor, caret, context, new TextRange(start, end), 1, dir, operatorArguments);
} }
@Override @Override
@ -602,7 +606,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); indentRange(editor, caret, context, range, 1, dir, operatorArguments);
} }
} }
@ -629,7 +633,8 @@ 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);
} }
@ -675,7 +680,7 @@ public class ChangeGroup extends VimChangeGroupBase {
} }
} }
if (pos > wsoff) { if (pos > wsoff) {
deleteText(editor, new TextRange(wsoff, pos), null, caret); deleteText(editor, new TextRange(wsoff, pos), null, caret, operatorArguments);
} }
} }
} }

View File

@ -36,6 +36,7 @@ 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?
@ -60,6 +61,7 @@ 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

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

View File

@ -411,6 +411,7 @@ 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

@ -20,26 +20,23 @@ 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.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
@ -50,7 +47,6 @@ 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
@ -115,23 +111,6 @@ 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,
@ -208,7 +187,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 ${getToolwindowName()} to see previous ids</small>") it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>")
it.addAction(StopTracking()) it.addAction(StopTracking())
@ -222,15 +201,6 @@ 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 ?: ""))

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 EditorWithProviderComposite editor = window.getSelectedEditor(); final EditorComposite editor = window.getSelectedComposite();
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,6 +34,7 @@ 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.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.isBlock import com.maddyhome.idea.vim.command.isBlock
@ -43,7 +44,9 @@ 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
@ -62,7 +65,13 @@ 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, updateVisualMarks: Boolean): Boolean {
val additionalData = collectPreModificationData(editor, data) val additionalData = collectPreModificationData(editor, data)
data.visualSelection?.let { deleteSelectedText(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) { if (editor.primaryCaret() == caret && updateVisualMarks) {
@ -93,7 +102,6 @@ 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() }
@ -113,6 +121,7 @@ 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)

View File

@ -32,7 +32,6 @@ 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
@ -211,8 +210,8 @@ class YankGroup : YankGroupBase() {
notifyListeners(editor, range) notifyListeners(editor, range)
var result = true var result = true
for ((caret, range) in caretToRange) { for ((caret, myRange) in caretToRange) {
result = caret.registerStorage.storeText(editor, range, type, false) && result result = caret.registerStorage.storeText(editor, myRange, type, false) && result
} }
return result return result
} }

View File

@ -44,6 +44,7 @@ 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,12 +60,14 @@ 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,6 +37,7 @@ 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;
@ -154,6 +155,7 @@ 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));
@ -245,12 +247,27 @@ 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 getVisibleArea(editor).width / EditorUtil.getPlainSpaceWidth(editor); return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(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(' ');
} }
/** /**
@ -802,19 +819,20 @@ public class EditorHelper {
} }
} }
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x; final int columnLeftX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn)).getX());
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 Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn)); final Point2D point = editor.visualPositionToPoint2D(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 int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor); final float standardColumnWidth = EditorHelper.getPlainSpaceWidthFloat(editor);
final int x = max(0, point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth)); final int screenMidColumn = (int) (screenWidth / standardColumnWidth / 2);
final int x = max(0, (int) Math.round(point.getX() - (screenMidColumn * standardColumnWidth)));
scrollHorizontally(editor, x); scrollHorizontally(editor, x);
} }
@ -839,7 +857,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 = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x; final int targetColumnRightX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn + 1)).getX());
final int screenWidth = getVisibleArea(editor).width; final int screenWidth = getVisibleArea(editor).width;
scrollHorizontally(editor, targetColumnRightX - screenWidth); scrollHorizontally(editor, targetColumnRightX - screenWidth);
} }
@ -1001,18 +1019,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 closest character. The // Make sure we get the character that contains this XY, not the editor's decision about the closest character. The
// editor will give us the next character if X is over half way through the character grid. // editor will give us the next character if X is over halfway through the character grid. Take into account that
int xActualLeft = editor.visualPositionToXY(closestVisualPosition).x; // the font size might be fractional, but the editor's area is integer. Use floating point values and round.
long xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX());
if (xActualLeft > x) { if (xActualLeft > x) {
closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition); closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition);
xActualLeft = editor.visualPositionToXY(closestVisualPosition).x; xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX());
} }
if (xActualLeft >= leftBound) { if (xActualLeft >= leftBound) {
final int xActualRight = final VisualPosition nextVisualPosition = new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1);
editor.visualPositionToXY(new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1)).x - final long xActualRight = Math.round(editor.visualPositionToPoint2D(nextVisualPosition).getX()) - 1;
1;
if (xActualRight <= rightBound) { if (xActualRight <= rightBound) {
return closestVisualPosition.column; return closestVisualPosition.column;
} }

View File

@ -22,6 +22,7 @@ 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
@ -30,6 +31,7 @@ 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).
@ -83,10 +85,9 @@ 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 EditorFactory.getInstance().allEditors.filter { editor -> editor.editorClientId.let { it == null || it == ClientId.currentOrNull } } return ClientEditorManager.getCurrentInstance().editors().toList()
} }
fun localEditors(doc: Document): List<Editor> { fun localEditors(doc: Document): List<Editor> {

View File

@ -24,11 +24,8 @@ 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
@ -86,7 +83,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 && !canBePerformed(event, ijAction, context.ij)) { if (ijAction is ActionGroup && !event.presentation.isPerformGroup) {
// 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)
@ -118,10 +115,9 @@ 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 { ignore -> SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use {
performRunnable.run() performRunnable.run()
result = AnActionResult.PERFORMED result = AnActionResult.PERFORMED
} }
@ -143,17 +139,6 @@ 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

@ -529,6 +529,9 @@ 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);
@ -542,6 +545,9 @@ 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);
} }

View File

@ -24,6 +24,7 @@ import javax.swing.KeyStroke
/** /**
* COMPATIBILITY-LAYER: Created a helper class * COMPATIBILITY-LAYER: Created a helper class
* Please see: https://jb.gg/zo8n0r
*/ */
object StringHelper { object StringHelper {
@JvmStatic @JvmStatic
@ -41,4 +42,4 @@ object StringHelper {
fun isCloseKeyStroke(stroke: KeyStroke): Boolean { fun isCloseKeyStroke(stroke: KeyStroke): Boolean {
return stroke.isCloseKeyStroke() return stroke.isCloseKeyStroke()
} }
} }

View File

@ -21,6 +21,8 @@ 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.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
@ -39,22 +41,29 @@ 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 fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext) val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
if (fileEditor != null && undoManager.isUndoAvailable(fileEditor)) { if (fileEditor != null && undoManager.isUndoAvailable(fileEditor)) {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
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 {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) })
editor?.carets()?.forEach { }
val ijCaret = it.ij
val hasSelection = ijCaret.hasSelection() editor?.carets()?.forEach {
if (hasSelection) { val ijCaret = it.ij
val selectionStart = ijCaret.selectionStart val hasSelection = ijCaret.hasSelection()
if (hasSelection) {
val selectionStart = ijCaret.selectionStart
CommandProcessor.getInstance().runUndoTransparentAction {
it.ij.removeSelection() it.ij.removeSelection()
it.ij.moveToOffset(selectionStart) it.ij.moveToOffset(selectionStart)
} }
@ -70,12 +79,14 @@ class UndoRedoHelper : UndoRedoBase() {
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext) val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
if (fileEditor != null && 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 {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) })
}
CommandProcessor.getInstance().runUndoTransparentAction {
editor?.carets()?.forEach { it.ij.removeSelection() } editor?.carets()?.forEach { it.ij.removeSelection() }
} }
return true return true
@ -95,10 +106,15 @@ class UndoRedoHelper : UndoRedoBase() {
} }
} }
val oldPath = editor.getPath()
vimDocument.addChangeListener(changeListener) vimDocument.addChangeListener(changeListener)
while (check() && !changeListener.hasChanged) { while (check() && !changeListener.hasChanged && !ifFilePathChanged(editor, oldPath)) {
action.run() action.run()
} }
vimDocument.removeChangeListener(changeListener) vimDocument.removeChangeListener(changeListener)
} }
private fun ifFilePathChanged(editor: IjVimEditor, oldPath: String?): Boolean {
return editor.getPath() != oldPath
}
} }

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,7 +35,6 @@ 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
@ -50,16 +49,16 @@ object AppCodeTemplates {
private var editor: Editor? = null private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
} }
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
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) {
@ -77,8 +76,8 @@ object AppCodeTemplates {
@JvmStatic @JvmStatic
fun onMovement( fun onMovement(
editor: @NotNull Editor, editor: Editor,
caret: @NotNull Caret, caret: Caret,
toRight: Boolean, toRight: Boolean,
) { ) {
val offset = caret.offset val offset = caret.offset

View File

@ -29,8 +29,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
@ -60,10 +60,10 @@ object IdeaSpecifics {
private val surrounderAction = private val surrounderAction =
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction" "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
@ -72,13 +72,13 @@ object IdeaSpecifics {
if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) { if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) {
if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) { if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) {
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
} }
} }
//endregion //endregion
} }
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
//region Enter insert mode after surround with if //region Enter insert mode after surround with if
@ -93,7 +93,7 @@ object IdeaSpecifics {
while (commandState.mode != VimStateMachine.Mode.COMMAND) { while (commandState.mode != VimStateMachine.Mode.COMMAND) {
commandState.popModes() commandState.popModes()
} }
VimPlugin.getChange().insertBeforeCursor(it.vim, dataContext.vim) VimPlugin.getChange().insertBeforeCursor(it.vim, event.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, dataContext: DataContext, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) { if (hostEditor != null) {
editor = hostEditor editor = hostEditor
} }
} }
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
//region Extend Selection for Rider //region Extend Selection for Rider

View File

@ -122,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()) EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance()) EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance().onOffDisposable)
} }
fun disable() { fun disable() {
@ -136,10 +136,6 @@ 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)
} }
} }

View File

@ -99,6 +99,7 @@ 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)
@ -179,7 +180,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) ?: continue val insertedLine = editor.addLine(position)
VimPlugin.getChange().saveStrokes("\n") VimPlugin.getChange().saveStrokes("\n")
var lineStart = editor.getLineRange(insertedLine).first var lineStart = editor.getLineRange(insertedLine).first

View File

@ -49,6 +49,7 @@ 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 {
@ -97,6 +98,7 @@ 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(prevContext.ij, caret.ij)) return IjExecutionContext(CaretSpecificDataContext.create(prevContext.ij, caret.ij))
} }
override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext { override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext {
return IjExecutionContext(CaretSpecificDataContext(context.ij, caret.ij)) return IjExecutionContext(CaretSpecificDataContext.create(context.ij, caret.ij))
} }
override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext { override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext {

View File

@ -62,7 +62,9 @@ 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,13 +68,13 @@ 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.vimscript.services.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.VariableService
import com.maddyhome.idea.vim.yank.VimYankGroup import com.maddyhome.idea.vim.yank.VimYankGroup

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(msg: String?) { override fun showStatusBarMessage(message: String?) {
if (ApplicationManager.getApplication().isUnitTestMode) { if (ApplicationManager.getApplication().isUnitTestMode) {
message = msg this.message = message
} }
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 (msg.isNullOrEmpty()) { if (message.isNullOrEmpty()) {
bar.info = "" bar.info = ""
} else { } else {
bar.info = "VIM - $msg" bar.info = "VIM - $message"
} }
} }
} }

View File

@ -30,16 +30,17 @@ 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).getRawOption(ignorecaseName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(ignorecaseName) as ToggleOption
val smartcase: ToggleOption val smartcase: ToggleOption
get() = (injector.optionService as IjVimOptionService).getRawOption(smartcaseName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(smartcaseName) as ToggleOption
val timeout: ToggleOption val timeout: ToggleOption
get() = (injector.optionService as IjVimOptionService).getRawOption(timeoutName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(timeoutName) as ToggleOption
val timeoutlen: NumberOption val timeoutlen: NumberOption
get() = (injector.optionService as IjVimOptionService).getRawOption(timeoutlenName) as 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,6 +18,7 @@
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
@ -25,8 +26,14 @@ 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("tracked", EventFields.StringValidatedByCustomRule("action_id", "action")) private val TRACKED_ACTIONS = GROUP.registerEvent(
private val COPIED_ACTIONS = GROUP.registerEvent("copied", EventFields.StringValidatedByCustomRule("action_id", "action")) "tracked",
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

@ -48,13 +48,13 @@ class Executor : VimScriptExecutorBase() {
override var executingVimscript = false override var executingVimscript = false
@Throws(ExException::class) @Throws(ExException::class)
override fun execute(scriptString: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult { override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
var finalResult: ExecutionResult = ExecutionResult.Success var finalResult: ExecutionResult = ExecutionResult.Success
val script = VimscriptParser.parse(scriptString) val myScript = VimscriptParser.parse(script)
script.units.forEach { it.vimContext = vimContext ?: script } myScript.units.forEach { it.vimContext = vimContext ?: myScript }
for (unit in script.units) { for (unit in myScript.units) {
try { try {
val result = unit.execute(editor, context) val result = unit.execute(editor, context)
if (result is ExecutionResult.Error) { if (result is ExecutionResult.Error) {
@ -89,18 +89,18 @@ class Executor : VimScriptExecutorBase() {
} }
if (!skipHistory) { if (!skipHistory) {
VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, scriptString) VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
if (script.units.size == 1 && script.units[0] is Command && script.units[0] !is RepeatCommand) { if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, scriptString) VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, script)
} }
} }
return finalResult return finalResult
} }
override fun execute(scriptString: String, skipHistory: Boolean) { override fun execute(script: String, skipHistory: Boolean) {
val editor = TextComponentEditorImpl(null, JTextArea()).vim val editor = TextComponentEditorImpl(null, JTextArea()).vim
val context = DataContext.EMPTY_CONTEXT.vim val context = DataContext.EMPTY_CONTEXT.vim
execute(scriptString, editor, context, skipHistory, indicateErrors = true, CommandLineVimLContext) execute(script, editor, context, skipHistory, indicateErrors = true, CommandLineVimLContext)
} }
override fun executeFile(file: File, indicateErrors: Boolean) { override fun executeFile(file: File, indicateErrors: Boolean) {

View File

@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
@ -36,7 +37,7 @@ import java.util.*
data class ActionListCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { data class ActionListCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) {
override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY)
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
val lineSeparator = "\n" val lineSeparator = "\n"
val searchPattern = argument.trim().lowercase(Locale.getDefault()).split("*") val searchPattern = argument.trim().lowercase(Locale.getDefault()).split("*")
val actionManager = ActionManager.getInstance() val actionManager = ActionManager.getInstance()

View File

@ -23,6 +23,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
@ -38,7 +39,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
data class BufferCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { data class BufferCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) {
override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY)
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
val arg = argument.trim() val arg = argument.trim()
val overrideModified = arg.startsWith('!') val overrideModified = arg.startsWith('!')
val buffer = if (overrideModified) arg.replace(Regex("^!\\s*"), "") else arg val buffer = if (overrideModified) arg.replace(Regex("^!\\s*"), "") else arg

View File

@ -26,6 +26,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
@ -48,7 +49,7 @@ data class BufferListCommand(val ranges: Ranges, val argument: String) : Command
val SUPPORTED_FILTERS = setOf('+', '=', 'a', '%', '#') val SUPPORTED_FILTERS = setOf('+', '=', 'a', '%', '#')
} }
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
val arg = argument.trim() val arg = argument.trim()
val filter = pruneUnsupportedFilters(arg) val filter = pruneUnsupportedFilters(arg)
val bufferList = getBufferList(context, filter) val bufferList = getBufferList(context, filter)

View File

@ -24,6 +24,7 @@ import com.intellij.openapi.progress.ProcessCanceledException
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
@ -38,7 +39,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
data class CmdFilterCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { data class CmdFilterCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) {
override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED)
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
logger.debug("execute") logger.debug("execute")
val command = buildString { val command = buildString {
var inBackslash = false var inBackslash = false

View File

@ -23,6 +23,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ranges.LineRange import com.maddyhome.idea.vim.ex.ranges.LineRange
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.group.SearchGroup.RE_BOTH import com.maddyhome.idea.vim.group.SearchGroup.RE_BOTH
@ -42,7 +43,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: Boolean) : Command.SingleExecution(ranges, argument) { data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: Boolean) : Command.SingleExecution(ranges, argument) {
override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED)
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
var result: ExecutionResult = ExecutionResult.Success var result: ExecutionResult = ExecutionResult.Success
editor.removeSecondaryCarets() editor.removeSecondaryCarets()
val caret = editor.currentCaret() val caret = editor.currentCaret()

View File

@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.vimscript.model.commands
import com.intellij.ide.BrowserUtil import com.intellij.ide.BrowserUtil
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.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
@ -33,7 +34,7 @@ import java.net.URLEncoder
*/ */
data class HelpCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { data class HelpCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) {
override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY)
override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
BrowserUtil.browse(helpTopicUrl(argument)) BrowserUtil.browse(helpTopicUrl(argument))
return ExecutionResult.Success return ExecutionResult.Success
} }

View File

@ -27,7 +27,7 @@ import com.maddyhome.idea.vim.options.StringOption
internal class IjVimOptionService : VimOptionServiceBase() { internal class IjVimOptionService : VimOptionServiceBase() {
private val customOptions = setOf( private val customOptions = setOf(
ToggleOption(oldUndo, oldUndo, false), ToggleOption(oldUndo, oldUndo, true),
ToggleOption(ideajoinName, ideajoinAlias, false), ToggleOption(ideajoinName, ideajoinAlias, false),
ToggleOption(ideamarksName, ideamarksAlias, true), ToggleOption(ideamarksName, ideamarksAlias, true),
StringOption(ideName, ideAlias, ApplicationNamesInfo.getInstance().fullProductNameWithEdition), StringOption(ideName, ideAlias, ApplicationNamesInfo.getInstance().fullProductNameWithEdition),

View File

@ -2,55 +2,7 @@
<name>IdeaVim</name> <name>IdeaVim</name>
<id>IdeaVIM</id> <id>IdeaVIM</id>
<change-notes><![CDATA[ <change-notes><![CDATA[
<h3>Features:</h3> <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">Changes</a>
<ul>
<li>Add register support to let command | <a href="https://youtrack.jetbrains.com/issue/VIM-749">VIM-749</a>, <a
href="https://youtrack.jetbrains.com/issue/VIM-1783">VIM-1783</a></li>
<li>Add tabmove command | <a href="https://youtrack.jetbrains.com/issue/VIM-1164">VIM-1164</a></li>
</ul>
<h3>Fixes:</h3>
<ul>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2502">VIM-2502</a> Fix the shape of new carets</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2499">VIM-2499</a> Fix mapping to esc</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2500">VIM-2500</a> Fix esc for normal mode</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2523">VIM-2523</a> <code>i</code> command for the folder in the
project tree
</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2471">VIM-2471</a> Multiple [{ and ]} actions</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2504">VIM-2504</a> Fix esc with using python notebooks</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2540">VIM-2540</a> Fix option listeners</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2548">VIM-2548</a> Fix paste</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2470">VIM-2470</a> Fix incorrect reset of cursor shape</li>
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2223">VIM-2223</a>, <a
href="https://youtrack.jetbrains.com/issue/VIM-1684">VIM-1684</a>, <a
href="https://youtrack.jetbrains.com/issue/VIM-2491">VIM-2491</a> Fix <code>gv</code></li>
</ul>
<h3>Merged PRs:</h3>
<ul>
<li><a href="https://github.com/JetBrains/ideavim/pull/441">441</a> by <a href="https://github.com/DanEEStar">DanEEStar</a>:
Add Matchit support for Vue.js files
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/440">440</a> by <a href="https://github.com/ksrb">Kevin
Suen</a>: Add matchit support for handlebars
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/448">448</a> by <a href="https://github.com/cravay">Michael
Schertenleib</a>: Support custom element names in vim-surround
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/435">435</a> by <a href="https://github.com/pmnoxx">Piotr
Mikulski</a>: Print stderr when running a command just like vim does
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/449">449</a> by <a href="https://github.com/lonre">Lonre
Wang</a>: Typo fix
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/453">453</a> by <a href="https://github.com/citizenmatt">Matt
Ellis</a>: fix(VIM-2470): Fix incorrect reset of cursor shape
</li>
<li><a href="https://github.com/JetBrains/ideavim/pull/461">461</a> by <a href="https://github.com/ddadon10">David
Dadon</a>: Add shortcut to ideajoin example
</li>
</ul>
]]> ]]>
</change-notes> </change-notes>
<description><![CDATA[ <description><![CDATA[
@ -70,8 +22,8 @@
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version --> <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
<!-- Check for [Version Update] tag in YouTrack as well --> <!-- Check for [Version Update] tag in YouTrack as well -->
<!-- Also, please update the value in gradle.build file--> <!-- Also, please update the value in build.gradle.kts file-->
<idea-version since-build="213"/> <idea-version since-build="222"/>
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) --> <!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
<depends>com.intellij.modules.platform</depends> <depends>com.intellij.modules.platform</depends>

View File

@ -112,7 +112,10 @@ internal object NeovimTesting {
when { when {
keys.equals("<esc>", ignoreCase = true) -> neovimApi.input(escapeCommand).get() keys.equals("<esc>", ignoreCase = true) -> neovimApi.input(escapeCommand).get()
keys.equals("<C-C>", ignoreCase = true) -> neovimApi.input(ctrlcCommand).get() keys.equals("<C-C>", ignoreCase = true) -> neovimApi.input(ctrlcCommand).get()
else -> neovimApi.input(neovimApi.replaceTermcodes(keys, true, false, true).get()).get() else -> {
val replacedCodes = neovimApi.replaceTermcodes(keys, true, false, true).get()
neovimApi.input(replacedCodes).get()
}
} }
} }
@ -228,6 +231,7 @@ enum class SkipNeovimReason {
VIM_SCRIPT, VIM_SCRIPT,
GUARDED_BLOCKS, GUARDED_BLOCKS,
CTRL_CODES,
} }
fun LogicalPosition.toVimCoords(): VimCoords { fun LogicalPosition.toVimCoords(): VimCoords {

View File

@ -23,9 +23,9 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode 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.handler.ActionBeanClass
import com.maddyhome.idea.vim.key.CommandNode import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.handler.ActionBeanClass
import junit.framework.TestCase import junit.framework.TestCase
import javax.swing.KeyStroke import javax.swing.KeyStroke
@ -38,14 +38,18 @@ class RegisterActionsTest : VimTestCase() {
@TestWithoutNeovim(reason = SkipNeovimReason.EDITOR_MODIFICATION) @TestWithoutNeovim(reason = SkipNeovimReason.EDITOR_MODIFICATION)
fun `test action in disabled plugin`() { fun `test action in disabled plugin`() {
setupChecks { try {
caretShape = false setupChecks {
} caretShape = false
val keys = injector.parser.parseKeys("jklwB") // just random keys }
val before = "I ${c}found it in a legendary land" val keys = injector.parser.parseKeys("jklwB") // just random keys
val after = "I jklwB${c}found it in a legendary land" val before = "I ${c}found it in a legendary land"
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) { val after = "I jklwB${c}found it in a legendary land"
VimPlugin.setEnabled(false) doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) {
VimPlugin.setEnabled(false)
}
} finally {
VimPlugin.setEnabled(true)
} }
} }

View File

@ -34,7 +34,6 @@ import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.VisualPosition
import com.intellij.openapi.editor.colors.EditorColors import com.intellij.openapi.editor.colors.EditorColors
import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.PlainTextFileType import com.intellij.openapi.fileTypes.PlainTextFileType
@ -82,6 +81,7 @@ import org.junit.Assert
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import java.util.* import java.util.*
import javax.swing.KeyStroke import javax.swing.KeyStroke
import kotlin.math.roundToInt
/** /**
* @author vlan * @author vlan
@ -169,7 +169,9 @@ abstract class VimTestCase : UsefulTestCase() {
get() = 35 get() = 35
protected fun setEditorVisibleSize(width: Int, height: Int) { protected fun setEditorVisibleSize(width: Int, height: Int) {
EditorTestUtil.setEditorVisibleSize(myFixture.editor, width, height) val w = (width * EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
val h = height * myFixture.editor.lineHeight
EditorTestUtil.setEditorVisibleSizeInPixels(myFixture.editor, w, h)
} }
protected fun setEditorVirtualSpace() { protected fun setEditorVirtualSpace() {
@ -609,7 +611,7 @@ abstract class VimTestCase : UsefulTestCase() {
// per platform (e.g. Windows is 7, Mac is 8) so we can't guarantee correct positioning for tests if we use hard coded // per platform (e.g. Windows is 7, Mac is 8) so we can't guarantee correct positioning for tests if we use hard coded
// pixel widths // pixel widths
protected fun addInlay(offset: Int, relatesToPrecedingText: Boolean, widthInColumns: Int): Inlay<*> { protected fun addInlay(offset: Int, relatesToPrecedingText: Boolean, widthInColumns: Int): Inlay<*> {
val widthInPixels = EditorUtil.getPlainSpaceWidth(myFixture.editor) * widthInColumns val widthInPixels = (EditorHelper.getPlainSpaceWidthFloat(myFixture.editor) * widthInColumns).roundToInt()
return EditorTestUtil.addInlay(myFixture.editor, offset, relatesToPrecedingText, widthInPixels) return EditorTestUtil.addInlay(myFixture.editor, offset, relatesToPrecedingText, widthInPixels)
} }
@ -619,7 +621,7 @@ abstract class VimTestCase : UsefulTestCase() {
// float if necessary. We'd still be working scaled to the line height, so fractional values should still work. // float if necessary. We'd still be working scaled to the line height, so fractional values should still work.
protected fun addBlockInlay(offset: Int, showAbove: Boolean, heightInRows: Int): Inlay<*> { protected fun addBlockInlay(offset: Int, showAbove: Boolean, heightInRows: Int): Inlay<*> {
val widthInColumns = 10 // Arbitrary width. We don't care. val widthInColumns = 10 // Arbitrary width. We don't care.
val widthInPixels = EditorUtil.getPlainSpaceWidth(myFixture.editor) * widthInColumns val widthInPixels = (EditorHelper.getPlainSpaceWidthFloat(myFixture.editor) * widthInColumns).roundToInt()
val heightInPixels = myFixture.editor.lineHeight * heightInRows val heightInPixels = myFixture.editor.lineHeight * heightInRows
return EditorTestUtil.addBlockInlay(myFixture.editor, offset, false, showAbove, widthInPixels, heightInPixels) return EditorTestUtil.addBlockInlay(myFixture.editor, offset, false, showAbove, widthInPixels, heightInPixels)
} }

View File

@ -71,6 +71,7 @@ class ChangeActionTest : VimTestCase() {
} }
// VIM-620 |i_CTRL-O| // VIM-620 |i_CTRL-O|
@TestWithoutNeovim(SkipNeovimReason.SELECT_MODE)
fun testInsertSingleCommandAndNewLineInserting5() { fun testInsertSingleCommandAndNewLineInserting5() {
doTest( doTest(
listOf("i", "<C-O>", "v", "<C-G>"), listOf("i", "<C-O>", "v", "<C-G>"),
@ -79,6 +80,7 @@ class ChangeActionTest : VimTestCase() {
} }
// VIM-620 |i_CTRL-O| // VIM-620 |i_CTRL-O|
@TestWithoutNeovim(SkipNeovimReason.SELECT_MODE)
fun testInsertSingleCommandAndNewLineInserting6() { fun testInsertSingleCommandAndNewLineInserting6() {
doTest( doTest(
listOf("i", "<C-O>", "gh"), listOf("i", "<C-O>", "gh"),
@ -87,6 +89,7 @@ class ChangeActionTest : VimTestCase() {
} }
// VIM-620 |i_CTRL-O| // VIM-620 |i_CTRL-O|
@TestWithoutNeovim(SkipNeovimReason.SELECT_MODE)
fun testInsertSingleCommandAndNewLineInserting7() { fun testInsertSingleCommandAndNewLineInserting7() {
doTest( doTest(
listOf("i", "<C-O>", "gh", "<esc>"), listOf("i", "<C-O>", "gh", "<esc>"),
@ -443,14 +446,15 @@ quux
) )
} }
@VimBehaviorDiffers(originalVimAfter = "foo bar")
fun testDeleteJoinLinesWithTrailingSpaceThenEmptyLine() { fun testDeleteJoinLinesWithTrailingSpaceThenEmptyLine() {
doTest( doTest(
"3J", "3J",
""" """
foo foo.
bar bar
""".trimIndent(), """.dotToSpace().trimIndent(),
"foo bar", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE "foo bar", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE
) )
} }
@ -459,9 +463,9 @@ quux
doTest( doTest(
"J", "J",
""" """
foo foo..
bar bar
""".trimIndent(), """.dotToSpace().trimIndent(),
"foo bar", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE "foo bar", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE
) )
} }

View File

@ -2846,4 +2846,30 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
assertState(after) assertState(after)
} }
// VIM-2703
@TestWithoutNeovim(reason = SkipNeovimReason.MULTICARET)
fun `test multicaret with unnamed clipboard`() {
injector.optionService.appendValue(OptionScope.GLOBAL, OptionConstants.clipboardName, OptionConstants.clipboard_unnamed)
val before = """
attach${c}Download(null)
attach${c}Download(null)
attach${c}Download(null)
attach${c}Download(null)
attach${c}Download(null)
""".trimIndent()
configureByText(before)
typeText(injector.parser.parseKeys("diw"))
val after = """
${c}(null)
${c}(null)
${c}(null)
${c}(null)
${c}(null)
""".trimIndent()
assertState(after)
injector.optionService.resetDefault(OptionScope.GLOBAL, OptionConstants.clipboardName)
}
} }

View File

@ -111,6 +111,7 @@ class ResetModeActionTest : VimTestCase() {
TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection()) TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection())
} }
@TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
fun `test delete command after resetting operator-pending mode with ctrl open bracket`() { fun `test delete command after resetting operator-pending mode with ctrl open bracket`() {
val keys = listOf("d", "<C-[>", "dw") val keys = listOf("d", "<C-[>", "dw")
val before = "A Discovery" val before = "A Discovery"

View File

@ -140,7 +140,7 @@ public class SpecialRegistersTest extends VimTestCase {
// Small deletes (less than a line) with register specified go to that register and to numbered registers // Small deletes (less than a line) with register specified go to that register and to numbered registers
assertRegisterChanged('a'); assertRegisterChanged('a');
assertRegisterChanged('1'); assertRegisterNotChanged('1');
assertRegisterNotChanged(SMALL_DELETION_REGISTER); assertRegisterNotChanged(SMALL_DELETION_REGISTER);
} }
@ -155,7 +155,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(VimInjectorKt.getInjector().getParser().parseKeys("\"add"), "one <caret>two three\n"); typeTextInFile(VimInjectorKt.getInjector().getParser().parseKeys("\"add"), "one <caret>two three\n");
assertRegisterChanged('a'); assertRegisterChanged('a');
assertRegisterChanged('1'); assertRegisterNotChanged('1');
} }
public void testNumberedRegistersShifting() { public void testNumberedRegistersShifting() {

View File

@ -317,6 +317,14 @@ class RepeatChangeActionTest : VimTestCase() {
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
} }
@VimBehaviorDiffers(
originalVimAfter = """
Three
Two
One
"""
)
fun `test redo register feature`() { fun `test redo register feature`() {
doTest( doTest(
listOf("dd", "dd", "dd", "\"1p", ".", "."), listOf("dd", "dd", "dd", "\"1p", ".", "."),

View File

@ -18,7 +18,10 @@
package org.jetbrains.plugins.ideavim.action.change package org.jetbrains.plugins.ideavim.action.change
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
class UndoActionTest : VimTestCase() { class UndoActionTest : VimTestCase() {
@ -76,25 +79,27 @@ class UndoActionTest : VimTestCase() {
} }
fun `test cursor movements do not require additional undo`() { fun `test cursor movements do not require additional undo`() {
val keys = listOf("a1<Esc>ea2<Esc>ea3<Esc>", "uu") if (!injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) {
val before = """ val keys = listOf("a1<Esc>ea2<Esc>ea3<Esc>", "uu")
val before = """
A Discovery A Discovery
${c}I found it in a legendary land ${c}I found it in a legendary land
all rocks and lavender and tufted grass, all rocks and lavender and tufted grass,
where it was settled on some sodden sand where it was settled on some sodden sand
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val after = """ val after = """
A Discovery A Discovery
I1 found$c it in a legendary land I1 found$c it in a legendary land
all rocks and lavender and tufted grass, all rocks and lavender and tufted grass,
where it was settled on some sodden sand where it was settled on some sodden sand
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
assertFalse(hasSelection()) assertFalse(hasSelection())
}
} }
private fun hasSelection(): Boolean { private fun hasSelection(): Boolean {

View File

@ -20,9 +20,11 @@
package org.jetbrains.plugins.ideavim.action.change.delete package org.jetbrains.plugins.ideavim.action.change.delete
import com.intellij.notification.ActionCenter
import com.intellij.notification.EventLog import com.intellij.notification.EventLog
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
import org.jetbrains.plugins.ideavim.OptionValueType import org.jetbrains.plugins.ideavim.OptionValueType
import org.jetbrains.plugins.ideavim.VimOptionTestCase import org.jetbrains.plugins.ideavim.VimOptionTestCase
@ -33,8 +35,6 @@ import org.jetbrains.plugins.ideavim.VimTestOption
* @author Alex Plate * @author Alex Plate
*/ */
class JoinNotificationTest : VimOptionTestCase(IjVimOptionService.ideajoinName) { class JoinNotificationTest : VimOptionTestCase(IjVimOptionService.ideajoinName) {
// [VERSION UPDATE] 221+: Uncomment
/*
@VimOptionTestConfiguration(VimTestOption(IjVimOptionService.ideajoinName, OptionValueType.NUMBER, "0")) @VimOptionTestConfiguration(VimTestOption(IjVimOptionService.ideajoinName, OptionValueType.NUMBER, "0"))
fun `test notification shown for no ideajoin`() { fun `test notification shown for no ideajoin`() {
val before = "I found${c} it\n in a legendary land" val before = "I found${c} it\n in a legendary land"
@ -45,17 +45,14 @@ class JoinNotificationTest : VimOptionTestCase(IjVimOptionService.ideajoinName)
val notification = ActionCenter.getNotifications(myFixture.project, true).last() val notification = ActionCenter.getNotifications(myFixture.project, true).last()
try { try {
assertEquals(NotificationService.IDEAVIM_NOTIFICATION_TITLE, notification.title) assertEquals(NotificationService.IDEAVIM_NOTIFICATION_TITLE, notification.title)
assertTrue(OptionConstants.ideajoinName in notification.content) assertTrue(IjVimOptionService.ideajoinName in notification.content)
assertEquals(3, notification.actions.size) assertEquals(3, notification.actions.size)
} finally { } finally {
notification.expire() notification.expire()
} }
} }
*/
// [VERSION UPDATE] 221+: Uncomment @VimOptionTestConfiguration(VimTestOption(IjVimOptionService.ideajoinName, OptionValueType.NUMBER, "1"))
/*
@VimOptionTestConfiguration(VimTestOption(OptionConstants.ideajoinName, OptionValueType.NUMBER, "1"))
fun `test notification not shown for ideajoin`() { fun `test notification not shown for ideajoin`() {
val before = "I found${c} it\n in a legendary land" val before = "I found${c} it\n in a legendary land"
configureByText(before) configureByText(before)
@ -63,9 +60,8 @@ class JoinNotificationTest : VimOptionTestCase(IjVimOptionService.ideajoinName)
typeText(injector.parser.parseKeys("J")) typeText(injector.parser.parseKeys("J"))
val notifications = ActionCenter.getNotifications(myFixture.project, true) val notifications = ActionCenter.getNotifications(myFixture.project, true)
assertTrue(notifications.isEmpty() || notifications.last().isExpired || OptionConstants.ideajoinName !in notifications.last().content) assertTrue(notifications.isEmpty() || notifications.last().isExpired || IjVimOptionService.ideajoinName !in notifications.last().content)
} }
*/
@VimOptionTestConfiguration(VimTestOption(IjVimOptionService.ideajoinName, OptionValueType.NUMBER, "0")) @VimOptionTestConfiguration(VimTestOption(IjVimOptionService.ideajoinName, OptionValueType.NUMBER, "0"))
fun `test notification not shown if was shown already`() { fun `test notification not shown if was shown already`() {

View File

@ -42,6 +42,7 @@ class InsertEnterActionTest : VimTestCase() {
doTest(listOf("i", "<Enter>"), before, after, VimStateMachine.Mode.INSERT, VimStateMachine.SubMode.NONE) doTest(listOf("i", "<Enter>"), before, after, VimStateMachine.Mode.INSERT, VimStateMachine.SubMode.NONE)
} }
@TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
fun `test insert enter with C-M`() { fun `test insert enter with C-M`() {
val before = """I found it in a legendary land val before = """I found it in a legendary land
|${c}all rocks and lavender and tufted grass, |${c}all rocks and lavender and tufted grass,

View File

@ -18,10 +18,12 @@
package org.jetbrains.plugins.ideavim.action.copy package org.jetbrains.plugins.ideavim.action.copy
import com.intellij.notification.ActionCenter
import com.intellij.notification.EventLog import com.intellij.notification.EventLog
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.group.NotificationService
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 org.jetbrains.plugins.ideavim.OptionValueType import org.jetbrains.plugins.ideavim.OptionValueType
@ -34,14 +36,12 @@ import org.jetbrains.plugins.ideavim.rangeOf
* @author Alex Plate * @author Alex Plate
*/ */
class IdeaPutNotificationsTest : VimOptionTestCase(OptionConstants.clipboardName) { class IdeaPutNotificationsTest : VimOptionTestCase(OptionConstants.clipboardName) {
// [VERSION UPDATE] 221+: Uncomment
/*
@VimOptionTestConfiguration(VimTestOption(OptionConstants.clipboardName, OptionValueType.STRING, "")) @VimOptionTestConfiguration(VimTestOption(OptionConstants.clipboardName, OptionValueType.STRING, ""))
fun `test notification exists if no ideaput`() { fun `test notification exists if no ideaput`() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
configureByText(before) configureByText(before)
appReadySetup(false) appReadySetup(false)
VimPlugin.getRegister().storeText(myFixture.editor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false) VimPlugin.getRegister().storeText(myFixture.editor.vim, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val notification = ActionCenter.getNotifications(myFixture.project, true).last() val notification = ActionCenter.getNotifications(myFixture.project, true).last()
@ -53,10 +53,7 @@ class IdeaPutNotificationsTest : VimOptionTestCase(OptionConstants.clipboardName
notification.expire() notification.expire()
} }
} }
*/
// [VERSION UPDATE] 221+: Uncomment
/*
@VimOptionTestConfiguration( @VimOptionTestConfiguration(
VimTestOption( VimTestOption(
OptionConstants.clipboardName, OptionConstants.clipboardName,
@ -68,13 +65,12 @@ class IdeaPutNotificationsTest : VimOptionTestCase(OptionConstants.clipboardName
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
configureByText(before) configureByText(before)
appReadySetup(false) appReadySetup(false)
VimPlugin.getRegister().storeText(myFixture.editor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false) VimPlugin.getRegister().storeText(myFixture.editor.vim, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val notifications = ActionCenter.getNotifications(myFixture.project, true) val notifications = ActionCenter.getNotifications(myFixture.project, true)
assertTrue(notifications.isEmpty() || notifications.last().isExpired || OptionConstants.clipboard_ideaput !in notifications.last().content) assertTrue(notifications.isEmpty() || notifications.last().isExpired || OptionConstants.clipboard_ideaput !in notifications.last().content)
} }
*/
@VimOptionTestConfiguration(VimTestOption(OptionConstants.clipboardName, OptionValueType.STRING, "")) @VimOptionTestConfiguration(VimTestOption(OptionConstants.clipboardName, OptionValueType.STRING, ""))
fun `test no notification if already was`() { fun `test no notification if already was`() {

View File

@ -24,6 +24,8 @@ 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.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.rangeOf import org.jetbrains.plugins.ideavim.rangeOf
import org.junit.Test import org.junit.Test
@ -31,7 +33,13 @@ import org.junit.Test
class PutTestAfterCursorActionTest : VimTestCase() { class PutTestAfterCursorActionTest : VimTestCase() {
fun `test put from number register`() { fun `test put from number register`() {
setRegister('4', "XXX ") setRegister('4', "XXX ")
doTest("\"4p", "This is my$c text", "This is my XXX$c text", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) doTest(
"\"4p",
"This is my$c text",
"This is my XXX$c text",
VimStateMachine.Mode.COMMAND,
VimStateMachine.SubMode.NONE
)
} }
@VimBehaviorDiffers( @VimBehaviorDiffers(
@ -69,4 +77,29 @@ class PutTestAfterCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
assertState(after) assertState(after)
} }
@TestWithoutNeovim(SkipNeovimReason.MULTICARET)
@Test
fun `test inserting same content to multiple carets`() {
val before = """
A Discovery
${c}I found it in a legendary land
${c}all rocks and lavender and tufted grass,
${c}where it was settled on some sodden sand
${c}hard by the torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("vep"))
val after = """
A Discovery
Discovery it in a legendary land
Discovery rocks and lavender and tufted grass,
Discovery it was settled on some sodden sand
Discovery by the torrent of a mountain pass.
""".trimIndent()
assertState(after)
}
} }

View File

@ -171,6 +171,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
assertState(after) assertState(after)
} }
@TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
fun `test Put line in block selection`() { fun `test Put line in block selection`() {
val file = """ val file = """
${c}A Discovery ${c}A Discovery

View File

@ -22,6 +22,8 @@ package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
class MotionLastColumnActionTest : VimTestCase() { class MotionLastColumnActionTest : VimTestCase() {
@ -140,6 +142,7 @@ class MotionLastColumnActionTest : VimTestCase() {
doTest(keys, before, after, VimStateMachine.Mode.INSERT, VimStateMachine.SubMode.NONE) doTest(keys, before, after, VimStateMachine.Mode.INSERT, VimStateMachine.SubMode.NONE)
} }
@TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
fun `test dollar motion from insert mode with deletion`() { fun `test dollar motion from insert mode with deletion`() {
val keys = "i<C-O>d$" val keys = "i<C-O>d$"
val before = """ val before = """

View File

@ -0,0 +1,28 @@
/*
* 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 org.jetbrains.plugins.ideavim.action.motion.`object`
import com.maddyhome.idea.vim.command.VimStateMachine
import org.jetbrains.plugins.ideavim.VimTestCase
class MotionInnerBlockDoubleQuoteActionTest : VimTestCase() {
fun `test change outside quotes`() {
doTest("di\"", "${c}print(\"hello\")", "print(\"$c\")", VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
}
}

View File

@ -198,4 +198,28 @@ class MotionInnerBlockParenActionTest : VimTestCase() {
) )
assertState("foo()\n") assertState("foo()\n")
} }
fun testOutside() {
typeTextInFile(
injector.parser.parseKeys("di)"),
"${c}foo(bar)\n"
)
assertState("foo()\n")
}
fun testOutsideInString() {
typeTextInFile(
injector.parser.parseKeys("di)"),
"\"1${c}23\"foo(bar)\n"
)
assertState("\"123\"foo()\n")
}
fun testOutsideInString2() {
typeTextInFile(
injector.parser.parseKeys("di)"),
"\"1${c}23(dsa)d\"foo(bar)\n"
)
assertState("\"123()d\"foo(bar)\n")
}
} }

View File

@ -0,0 +1,48 @@
/*
* 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 org.jetbrains.plugins.ideavim.action.motion.`object`
import com.maddyhome.idea.vim.api.injector
import org.jetbrains.plugins.ideavim.VimTestCase
class MotionOuterBlockBraceActionTest : VimTestCase() {
fun testOutside() {
typeTextInFile(
injector.parser.parseKeys("di}"),
"${c}foo{bar}\n"
)
assertState("foo{}\n")
}
fun testOutsideInString() {
typeTextInFile(
injector.parser.parseKeys("di}"),
"\"1${c}23\"foo{bar}\n"
)
assertState("\"123\"foo{}\n")
}
fun testOutsideInString2() {
typeTextInFile(
injector.parser.parseKeys("di}"),
"\"1${c}23{dsa}d\"foo{bar}\n"
)
assertState("\"123{}d\"foo{bar}\n")
}
}

View File

@ -84,6 +84,7 @@ class MotionPercentOrMatchActionTest : VimTestCase() {
assertOffset(7) assertOffset(7)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN, description = "Matchit plugin affects neovim")
fun `test percent match parens in string`() { fun `test percent match parens in string`() {
typeTextInFile( typeTextInFile(
injector.parser.parseKeys("%"), injector.parser.parseKeys("%"),
@ -113,6 +114,7 @@ class MotionPercentOrMatchActionTest : VimTestCase() {
assertState("$c<!-- foo -->") assertState("$c<!-- foo -->")
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN, description = "Matchit plugin affects neovim")
fun `test percent match java comment start`() { fun `test percent match java comment start`() {
configureByJavaText("/$c* foo */") configureByJavaText("/$c* foo */")
typeText(injector.parser.parseKeys("%")) typeText(injector.parser.parseKeys("%"))
@ -144,12 +146,14 @@ class MotionPercentOrMatchActionTest : VimTestCase() {
assertState("$c/** foo */") assertState("$c/** foo */")
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN, description = "Matchit plugin affects neovim")
fun `test percent doesnt match after comment start`() { fun `test percent doesnt match after comment start`() {
configureByJavaText("/*$c foo */") configureByJavaText("/*$c foo */")
typeText(injector.parser.parseKeys("%")) typeText(injector.parser.parseKeys("%"))
assertState("/*$c foo */") assertState("/*$c foo */")
} }
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR)
fun `test percent doesnt match before comment end`() { fun `test percent doesnt match before comment end`() {
configureByJavaText("/* foo $c */") configureByJavaText("/* foo $c */")
typeText(injector.parser.parseKeys("%")) typeText(injector.parser.parseKeys("%"))
@ -232,10 +236,12 @@ class MotionPercentOrMatchActionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN, description = "Matchit plugin affects neovim")
fun `test deleting with percent motion backward`() { fun `test deleting with percent motion backward`() {
doTest("d%", "(foo bar$c)", c, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) doTest("d%", "(foo bar$c)", c, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN, description = "Matchit plugin affects neovim")
fun `test deleting with percent motion`() { fun `test deleting with percent motion`() {
doTest("d%", "$c(foo bar)", c, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) doTest("d%", "$c(foo bar)", c, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
} }

View File

@ -19,15 +19,16 @@
package org.jetbrains.plugins.ideavim.action.scroll package org.jetbrains.plugins.ideavim.action.scroll
import com.intellij.openapi.editor.Inlay import com.intellij.openapi.editor.Inlay
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
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 com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.Assert import org.junit.Assert
import kotlin.math.roundToInt
/* /*
*zs* *zs*
@ -77,7 +78,7 @@ class ScrollFirstScreenColumnActionTest : VimTestCase() {
typeText(injector.parser.parseKeys("100|" + "zs")) typeText(injector.parser.parseKeys("100|" + "zs"))
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val textWidth = visibleArea.width - inlay.widthInPixels val textWidth = visibleArea.width - inlay.widthInPixels
val availableColumns = textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) val availableColumns = (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
// The first visible text column will be 99, with the inlay positioned to the left of it // The first visible text column will be 99, with the inlay positioned to the left of it
assertVisibleLineBounds(0, 99, 99 + availableColumns - 1) assertVisibleLineBounds(0, 99, 99 + availableColumns - 1)
@ -112,6 +113,6 @@ class ScrollFirstScreenColumnActionTest : VimTestCase() {
private fun getAvailableColumns(inlay: Inlay<*>): Int { private fun getAvailableColumns(inlay: Inlay<*>): Int {
val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels
return textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) return (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
} }
} }

View File

@ -19,14 +19,15 @@
package org.jetbrains.plugins.ideavim.action.scroll package org.jetbrains.plugins.ideavim.action.scroll
import com.intellij.openapi.editor.Inlay import com.intellij.openapi.editor.Inlay
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.EditorHelper
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 com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.Assert import org.junit.Assert
import kotlin.math.roundToInt
/* /*
*ze* *ze*
@ -109,14 +110,15 @@ class ScrollLastScreenColumnActionTest : VimTestCase() {
typeText(injector.parser.parseKeys("100|" + "ze")) typeText(injector.parser.parseKeys("100|" + "ze"))
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val textWidth = visibleArea.width - inlay.widthInPixels val textWidth = visibleArea.width - inlay.widthInPixels
val availableColumns = textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) val availableColumns = (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
// The last visible text column will be 99, but it will be positioned before the inlay // The last visible text column will be 99, but it will be positioned before the inlay
assertVisibleLineBounds(0, 99 - availableColumns + 1, 99) assertVisibleLineBounds(0, 99 - availableColumns + 1, 99)
// We have to assert the location of the inlay // We have to assert the location of the inlay
Assert.assertEquals(visibleArea.x + textWidth, inlay.bounds!!.x) val inlayX = myFixture.editor.visualPositionToPoint2D(inlay.visualPosition).x.roundToInt()
Assert.assertEquals(visibleArea.x + visibleArea.width, inlay.bounds!!.x + inlay.bounds!!.width) Assert.assertEquals(visibleArea.x + textWidth, inlayX)
Assert.assertEquals(visibleArea.x + visibleArea.width, inlayX + inlay.widthInPixels)
} }
fun `test last screen column does not include subsequent inline inlay associated with following text`() { fun `test last screen column does not include subsequent inline inlay associated with following text`() {
@ -130,6 +132,6 @@ class ScrollLastScreenColumnActionTest : VimTestCase() {
private fun getAvailableColumns(inlay: Inlay<*>): Int { private fun getAvailableColumns(inlay: Inlay<*>): Int {
val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels
return textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) return (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
} }
} }

View File

@ -134,4 +134,18 @@ class SetCommandTest : VimTestCase() {
typeText(commandToKeys("set selection?")) typeText(commandToKeys("set selection?"))
assertExOutput("selection=exclusive \n") assertExOutput("selection=exclusive \n")
} }
@TestWithoutNeovim(reason = SkipNeovimReason.OPTION)
fun `test show numbered value`() {
configureByText("\n")
typeText(commandToKeys("set so"))
assertExOutput("scrolloff=0 \n")
}
@TestWithoutNeovim(reason = SkipNeovimReason.OPTION)
fun `test show numbered value with questionmark`() {
configureByText("\n")
typeText(commandToKeys("set so?"))
assertExOutput("scrolloff=0 \n")
}
} }

View File

@ -22,17 +22,21 @@ import com.intellij.ide.highlighter.HtmlFileType
import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.highlighter.JavaFileType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.yaml.YAMLFileType import org.jetbrains.yaml.YAMLFileType
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
class CommentaryExtensionTest : VimTestCase() { class CommentaryExtensionTest : VimTestCase() {
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
enableExtensions("commentary") enableExtensions("commentary")
} }
// |gc| |l| + move caret // |gc| |l| + move caret
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testBlockCommentSingle() { fun testBlockCommentSingle() {
doTest( doTest(
"gcll", "gcll",
@ -44,6 +48,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |iw| // |gc| |iw|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testBlockCommentInnerWord() { fun testBlockCommentInnerWord() {
doTest( doTest(
"gciw", "gciw",
@ -55,6 +60,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |iw| // |gc| |iw|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testBlockCommentTillForward() { fun testBlockCommentTillForward() {
doTest( doTest(
"gct{", "gct{",
@ -65,6 +71,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |ab| // |gc| |ab|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testBlockCommentOuterParens() { fun testBlockCommentOuterParens() {
doTest( doTest(
"gcab", "gcab",
@ -79,6 +86,7 @@ class CommentaryExtensionTest : VimTestCase() {
* otherwise, they are incredibly difficult to undo * otherwise, they are incredibly difficult to undo
*/ */
// |gc| |j| // |gc| |j|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentDown() { fun testLineCommentDown() {
doTest( doTest(
"gcj", "gcj",
@ -89,6 +97,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentDownPreservesAbsoluteCaretLocation() { fun testLineCommentDownPreservesAbsoluteCaretLocation() {
doTest( doTest(
"gcj", "gcj",
@ -100,6 +109,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |ip| // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentInnerParagraph() { fun testLineCommentInnerParagraph() {
doTest( doTest(
"gcip", "gcip",
@ -111,6 +121,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |ip| // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentSingleLineInnerParagraph() { fun testLineCommentSingleLineInnerParagraph() {
doTest( doTest(
"gcip", "gcip",
@ -121,6 +132,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
/* Ensure uncommenting works as well */ // |gc| |ip| /* Ensure uncommenting works as well */ // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineUncommentInnerParagraph() { fun testLineUncommentInnerParagraph() {
doTest( doTest(
"gcip", "gcip",
@ -133,6 +145,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |ip| // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineUncommentSingleLineInnerParagraph() { fun testLineUncommentSingleLineInnerParagraph() {
doTest( doTest(
"gcip", "gcip",
@ -143,6 +156,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
/* Visual mode */ // |gc| |ip| /* Visual mode */ // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentVisualInnerParagraph() { fun testLineCommentVisualInnerParagraph() {
doTest( doTest(
"vipgc", "vipgc",
@ -154,6 +168,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gc| |ip| // |gc| |ip|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineUncommentVisualInnerParagraph() { fun testLineUncommentVisualInnerParagraph() {
doTest( doTest(
"vipgc", "vipgc",
@ -165,6 +180,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
/* Special shortcut gcc is always linewise */ // |gcc| /* Special shortcut gcc is always linewise */ // |gcc|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentShortcut() { fun testLineCommentShortcut() {
doTest( doTest(
"gccj", "gccj",
@ -177,6 +193,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gcc| // |gcc|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineCommentShortcutSetsCaretToMotionLocation() { fun testLineCommentShortcutSetsCaretToMotionLocation() {
doTest( doTest(
"gcc", "gcc",
@ -188,6 +205,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gcc| // |gcc|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testLineUncommentShortcut() { fun testLineUncommentShortcut() {
doTest( doTest(
"gcc", "gcc",
@ -200,6 +218,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
// |gcc| // |gcc|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun testHTMLCommentShortcut() { fun testHTMLCommentShortcut() {
doTest( doTest(
"gcc", "gcc",
@ -212,6 +231,7 @@ class CommentaryExtensionTest : VimTestCase() {
assertSelection(null) assertSelection(null)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test comment motion repeat`() { fun `test comment motion repeat`() {
doTest( doTest(
"gcj" + "jj.", "gcj" + "jj.",
@ -231,6 +251,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test comment motion right repeat`() { fun `test comment motion right repeat`() {
doTest( doTest(
"gciw" + "jj.", "gciw" + "jj.",
@ -250,6 +271,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test comment line repeat`() { fun `test comment line repeat`() {
doTest( doTest(
"gcc" + "j.", "gcc" + "j.",
@ -266,6 +288,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
@VimBehaviorDiffers(description = "IntelliJ's uncomment leaves the leading whitespace") @VimBehaviorDiffers(description = "IntelliJ's uncomment leaves the leading whitespace")
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test uncomment with gcgc`() { fun `test uncomment with gcgc`() {
doTest( doTest(
"gcgc", "gcgc",
@ -286,6 +309,7 @@ class CommentaryExtensionTest : VimTestCase() {
} }
@VimBehaviorDiffers(description = "IntelliJ's uncomment leaves the leading whitespace") @VimBehaviorDiffers(description = "IntelliJ's uncomment leaves the leading whitespace")
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test uncomment with gcu`() { fun `test uncomment with gcu`() {
doTest( doTest(
"gcu", "gcu",
@ -305,6 +329,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test comment line with count`() { fun `test comment line with count`() {
// Caret position is kept as the position *before* the commenting. This is how Vim works // Caret position is kept as the position *before* the commenting. This is how Vim works
doTest( doTest(
@ -329,6 +354,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment`() { fun `test text object deletes single line comment`() {
doTest( doTest(
"dgc", "dgc",
@ -343,6 +369,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes multiple line comments`() { fun `test text object deletes multiple line comments`() {
doTest( doTest(
"dgc", "dgc",
@ -361,6 +388,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes multiple line comments 2`() { fun `test text object deletes multiple line comments 2`() {
doTest( doTest(
"dgc", "dgc",
@ -379,6 +407,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from leading whitespace`() { fun `test text object deletes single line comment from leading whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -393,6 +422,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from leading whitespace 2`() { fun `test text object deletes single line comment from leading whitespace 2`() {
doTest( doTest(
"dgc", "dgc",
@ -409,6 +439,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from leading whitespace 3`() { fun `test text object deletes single line comment from leading whitespace 3`() {
doTest( doTest(
"dgc", "dgc",
@ -427,6 +458,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from trailing whitespace`() { fun `test text object deletes single line comment from trailing whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -444,6 +476,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comments separated by whitespace`() { fun `test text object deletes single line comments separated by whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -460,6 +493,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes disjointed single line comments from whitespace`() { fun `test text object deletes disjointed single line comments from whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -481,6 +515,7 @@ class CommentaryExtensionTest : VimTestCase() {
final Int value = 42; final Int value = 42;
""" """
) )
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from current line`() { fun `test text object deletes single line comment from current line`() {
doTest( doTest(
"dgc", "dgc",
@ -496,6 +531,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes single line comment from current line 2`() { fun `test text object deletes single line comment from current line 2`() {
doTest( doTest(
"dgc", "dgc",
@ -512,6 +548,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object does not delete line with comment and text`() { fun `test text object does not delete line with comment and text`() {
doTest( doTest(
"dgc", "dgc",
@ -525,6 +562,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes block comment`() { fun `test text object deletes block comment`() {
doTest( doTest(
"dgc", "dgc",
@ -539,6 +577,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes multi-line block comment`() { fun `test text object deletes multi-line block comment`() {
doTest( doTest(
"dgc", "dgc",
@ -555,6 +594,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes adjoining multi-line block comments`() { fun `test text object deletes adjoining multi-line block comments`() {
doTest( doTest(
"dgc", "dgc",
@ -574,6 +614,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes adjoining multi-line block comments 2`() { fun `test text object deletes adjoining multi-line block comments 2`() {
doTest( doTest(
"dgc", "dgc",
@ -594,6 +635,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object does not delete line with text and block comment`() { fun `test text object does not delete line with text and block comment`() {
doTest( doTest(
"dgc", "dgc",
@ -607,6 +649,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes JavaDoc comment`() { fun `test text object deletes JavaDoc comment`() {
doTest( doTest(
"dgc", "dgc",
@ -627,6 +670,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes JavaDoc comment from leading whitespace`() { fun `test text object deletes JavaDoc comment from leading whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -648,6 +692,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes JavaDoc comment and adjoining comments`() { fun `test text object deletes JavaDoc comment and adjoining comments`() {
doTest( doTest(
"dgc", "dgc",
@ -669,6 +714,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test text object deletes JavaDoc comment and adjoining comments separated by whitespace`() { fun `test text object deletes JavaDoc comment and adjoining comments separated by whitespace`() {
doTest( doTest(
"dgc", "dgc",
@ -693,6 +739,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test Commentary command comments current line`() { fun `test Commentary command comments current line`() {
doTest( doTest(
":Commentary<CR>", ":Commentary<CR>",
@ -710,6 +757,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test Commentary command comments simple line range`() { fun `test Commentary command comments simple line range`() {
doTest( doTest(
":2Commentary<CR>", ":2Commentary<CR>",
@ -727,6 +775,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test Commentary command comments line range`() { fun `test Commentary command comments line range`() {
doTest( doTest(
":1,3Commentary<CR>", ":1,3Commentary<CR>",
@ -755,6 +804,7 @@ class CommentaryExtensionTest : VimTestCase() {
"Note that Escape exits Visual mode, but leaves the caret where it is", "Note that Escape exits Visual mode, but leaves the caret where it is",
shouldBeFixed = true shouldBeFixed = true
) )
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test Commentary command comments visual range`() { fun `test Commentary command comments visual range`() {
doTest( doTest(
"Vjj" + ":Commentary<CR>", "Vjj" + ":Commentary<CR>",
@ -772,6 +822,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test Commentary command comments search range`() { fun `test Commentary command comments search range`() {
doTest( doTest(
":g/value2/Commentary<CR>", ":g/value2/Commentary<CR>",
@ -793,6 +844,7 @@ class CommentaryExtensionTest : VimTestCase() {
) )
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test block comment falls back to line comment when not available`() { fun `test block comment falls back to line comment when not available`() {
doTest( doTest(
"gcw", "gcw",

View File

@ -18,15 +18,16 @@
package org.jetbrains.plugins.ideavim.group.motion package org.jetbrains.plugins.ideavim.group.motion
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.EditorHelper
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 com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import kotlin.math.roundToInt
@Suppress("ClassName") @Suppress("ClassName")
class MotionGroup_ScrollCaretIntoViewHorizontally_Test : VimTestCase() { class MotionGroup_ScrollCaretIntoViewHorizontally_Test : VimTestCase() {
@ -110,7 +111,7 @@ class MotionGroup_ScrollCaretIntoViewHorizontally_Test : VimTestCase() {
// These columns are hard to calculate, because the visible offset depends on the rendered width of the inlay // These columns are hard to calculate, because the visible offset depends on the rendered width of the inlay
// Also, because we're scrolling right (adding columns to the right) we make the right most column line up // Also, because we're scrolling right (adding columns to the right) we make the right most column line up
val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels
val availableColumns = textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) val availableColumns = (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
assertVisibleLineBounds(0, 119 - availableColumns + 1, 119) assertVisibleLineBounds(0, 119 - availableColumns + 1, 119)
} }
@ -185,7 +186,7 @@ class MotionGroup_ScrollCaretIntoViewHorizontally_Test : VimTestCase() {
typeText(injector.parser.parseKeys("120|zs" + "20h")) typeText(injector.parser.parseKeys("120|zs" + "20h"))
// These columns are hard to calculate, because the visible offset depends on the rendered width of the inlay // These columns are hard to calculate, because the visible offset depends on the rendered width of the inlay
val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels val textWidth = myFixture.editor.scrollingModel.visibleArea.width - inlay.widthInPixels
val availableColumns = textWidth / EditorUtil.getPlainSpaceWidth(myFixture.editor) val availableColumns = (textWidth / EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)).roundToInt()
assertVisibleLineBounds(0, 99, 99 + availableColumns - 1) assertVisibleLineBounds(0, 99, 99 + availableColumns - 1)
} }

View File

@ -23,6 +23,7 @@ import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.Assert import org.junit.Assert
import kotlin.math.roundToInt
class EditorHelperTest : VimTestCase() { class EditorHelperTest : VimTestCase() {
@TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING) @TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING)
@ -30,8 +31,8 @@ class EditorHelperTest : VimTestCase() {
configureByColumns(100) configureByColumns(100)
EditorHelper.scrollColumnToLeftOfScreen(myFixture.editor, 0, 2) EditorHelper.scrollColumnToLeftOfScreen(myFixture.editor, 0, 2)
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val columnWidth = visibleArea.width / screenWidth val columnWidth = EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)
Assert.assertEquals(2 * columnWidth, visibleArea.x) Assert.assertEquals((2 * columnWidth).roundToInt(), visibleArea.x)
} }
@TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING) @TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING)
@ -40,8 +41,8 @@ class EditorHelperTest : VimTestCase() {
val column = screenWidth + 2 val column = screenWidth + 2
EditorHelper.scrollColumnToRightOfScreen(myFixture.editor, 0, column) EditorHelper.scrollColumnToRightOfScreen(myFixture.editor, 0, column)
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val columnWidth = visibleArea.width / screenWidth val columnWidth = EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)
Assert.assertEquals((column - screenWidth + 1) * columnWidth, visibleArea.x) Assert.assertEquals(((column - screenWidth + 1) * columnWidth).roundToInt(), visibleArea.x)
} }
@TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING) @TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING)
@ -52,8 +53,8 @@ class EditorHelperTest : VimTestCase() {
// Put column 100 into position 41 -> offset is 59 columns // Put column 100 into position 41 -> offset is 59 columns
EditorHelper.scrollColumnToMiddleOfScreen(myFixture.editor, 0, 99) EditorHelper.scrollColumnToMiddleOfScreen(myFixture.editor, 0, 99)
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val columnWidth = visibleArea.width / screenWidth val columnWidth = EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)
Assert.assertEquals(59 * columnWidth, visibleArea.x) Assert.assertEquals((59 * columnWidth).roundToInt(), visibleArea.x)
} }
@TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING) @TestWithoutNeovim(SkipNeovimReason.NOT_VIM_TESTING)
@ -65,7 +66,7 @@ class EditorHelperTest : VimTestCase() {
// Put column 100 into position 41 -> offset is 59 columns // Put column 100 into position 41 -> offset is 59 columns
EditorHelper.scrollColumnToMiddleOfScreen(myFixture.editor, 0, 99) EditorHelper.scrollColumnToMiddleOfScreen(myFixture.editor, 0, 99)
val visibleArea = myFixture.editor.scrollingModel.visibleArea val visibleArea = myFixture.editor.scrollingModel.visibleArea
val columnWidth = visibleArea.width / screenWidth val columnWidth = EditorHelper.getPlainSpaceWidthFloat(myFixture.editor)
Assert.assertEquals(59 * columnWidth, visibleArea.x) Assert.assertEquals((59 * columnWidth).roundToInt(), visibleArea.x)
} }
} }

View File

@ -20,11 +20,14 @@ package org.jetbrains.plugins.ideavim.longrunning
import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.PlatformTestUtil
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
class MacroTest : VimTestCase() { class MacroTest : VimTestCase() {
// was a problem on revision affec9bb61ea5e1e635673a0041d61f7af3722b2 // was a problem on revision affec9bb61ea5e1e635673a0041d61f7af3722b2
@TestWithoutNeovim(reason = SkipNeovimReason.NOT_VIM_TESTING)
fun `test no StackOverflowException`() { fun `test no StackOverflowException`() {
configureByText("abc de${c}fg") configureByText("abc de${c}fg")
typeText(injector.parser.parseKeys("qahlq")) typeText(injector.parser.parseKeys("qahlq"))

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