1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-01-31 05:45:59 +01:00

Compare commits

..

22 Commits

Author SHA1 Message Date
822dad52f3
Set plugin version to chylex-41 2024-09-05 07:40:10 +02:00
bf12c98880
Exit insert mode after refactoring 2024-09-05 07:40:10 +02:00
c02bd15e4f
Add action to run last macro in all opened files 2024-09-05 07:27:53 +02:00
5957d5d681
Stop macro execution after a failed search 2024-09-05 07:27:53 +02:00
9445afb555
Revert per-caret registers 2024-09-05 07:27:53 +02:00
6e115bdf64
Revert "Factor disposable objects on editor opening"
This reverts commit 1fa78935
2024-09-05 07:27:53 +02:00
6305c412b5
Fix(VIM-3364): Exception with mapped Generate action 2024-09-05 07:27:53 +02:00
be2eabe3b9
Apply scrolloff after executing native IDEA actions 2024-09-05 07:27:53 +02:00
de13e4348a
Stay on same line after reindenting 2024-09-05 07:12:09 +02:00
1c154fdc8a
Update search register when using f/t 2024-09-05 07:12:09 +02:00
9b75931736
Automatically add unambiguous imports after running a macro 2024-09-05 07:12:09 +02:00
3fe97aa767
Fix(VIM-3179): Respect virtual space below editor (imperfectly) 2024-09-05 07:12:09 +02:00
8eb2dbebcf
Fix(VIM-3178): Workaround to support "Jump to Source" action mapping 2024-09-05 07:12:09 +02:00
cb781f9a0d
Add support for count for visual and line motion surround 2024-09-05 07:12:09 +02:00
6693755823
Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2024-09-05 07:12:09 +02:00
9a9bd335d3
Fix(VIM-696) Restore visual mode after undo/redo, and disable incompatible actions 2024-09-05 07:12:09 +02:00
91e22482c6
Respect count with <Action> mappings 2024-09-05 07:08:52 +02:00
06dc2ed75c
Change matchit plugin to use HTML patterns in unrecognized files 2024-09-05 07:02:47 +02:00
12da1ac969
Reset insert mode when switching active editor 2024-09-05 07:02:47 +02:00
5747ac0ebf
Disable switching to insert mode for some editors 2024-09-05 07:02:44 +02:00
8a47bc1840
Remove update checker 2024-09-05 07:02:36 +02:00
da4deaf698
Set custom plugin version 2024-09-05 07:02:36 +02:00
329 changed files with 3789 additions and 8145 deletions

View File

@ -8,9 +8,6 @@ on:
push: push:
branches: [ master ] branches: [ master ]
permissions:
contents: write
jobs: jobs:
build: build:

View File

@ -20,11 +20,6 @@ on:
schedule: schedule:
- cron: '44 12 * * 4' - cron: '44 12 * * 4'
permissions:
actions: read
contents: read
security-events: write
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze

View File

@ -10,9 +10,6 @@ on:
push: push:
branches: [ master ] branches: [ master ]
permissions:
contents: write
jobs: jobs:
build: build:
@ -37,17 +34,6 @@ jobs:
id: update_authors id: update_authors
run: cp -a origin/doc/. docs run: cp -a origin/doc/. docs
# The Wiki for github should have no `.md` in references
# Otherwise, such links will lead to the raw text.
# However, the `.md` should exist to have a navigation in GitHub code.
- name: Replace `.md)` with `)`
run: |
# Define the directory you want to process
DIRECTORY="docs"
# Find all files in the directory and perform the replacement
find $DIRECTORY -type f -exec sed -i 's/\.md)/)/g' {} +
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4
with: with:

View File

@ -5,12 +5,13 @@ object Constants {
const val EAP_CHANNEL = "eap" const val EAP_CHANNEL = "eap"
const val DEV_CHANNEL = "Dev" const val DEV_CHANNEL = "Dev"
const val NVIM_TESTS = "2024.2.1" const val GITHUB_TESTS = "2024.1.1"
const val PROPERTY_TESTS = "2024.2.1" const val NVIM_TESTS = "2024.1.1"
const val LONG_RUNNING_TESTS = "2024.2.1" const val PROPERTY_TESTS = "2024.1.1"
const val QODANA_TESTS = "2024.2.1" const val LONG_RUNNING_TESTS = "2024.1.1"
const val RELEASE = "2024.2.1" const val QODANA_TESTS = "2024.1.1"
const val RELEASE = "2024.1.1"
const val RELEASE_DEV = "2024.2.1" const val RELEASE_DEV = "2024.1.1"
const val RELEASE_EAP = "2024.2.1" const val RELEASE_EAP = "2024.1.1"
} }

View File

@ -8,6 +8,7 @@ import _Self.buildTypes.PropertyBased
import _Self.buildTypes.Qodana import _Self.buildTypes.Qodana
import _Self.buildTypes.TestingBuildType import _Self.buildTypes.TestingBuildType
import _Self.subprojects.GitHub import _Self.subprojects.GitHub
import _Self.subprojects.OldTests
import _Self.subprojects.Releases import _Self.subprojects.Releases
import _Self.vcsRoots.GitHubPullRequest import _Self.vcsRoots.GitHubPullRequest
import _Self.vcsRoots.ReleasesVcsRoot import _Self.vcsRoots.ReleasesVcsRoot
@ -17,7 +18,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.Project
object Project : Project({ object Project : Project({
description = "Vim engine for JetBrains IDEs" description = "Vim engine for JetBrains IDEs"
subProjects(Releases, GitHub) subProjects(Releases, OldTests, GitHub)
// VCS roots // VCS roots
vcsRoot(GitHubPullRequest) vcsRoot(GitHubPullRequest)
@ -25,7 +26,8 @@ object Project : Project({
// Active tests // Active tests
buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT")) buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
buildType(TestingBuildType("2024.2.1", "<default>")) buildType(TestingBuildType("2024.1.1", "<default>"))
buildType(TestingBuildType("2024.2", "<default>"))
buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT")) buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
buildType(PropertyBased) buildType(PropertyBased)
@ -42,9 +44,6 @@ object Project : Project({
abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({ abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
artifactRules = """ artifactRules = """
+:build/reports => build/reports +:build/reports => build/reports
+:tests/java-tests/build/reports => java-tests/build/reports
+:tests/long-running-tests/build/reports => long-running-tests/build/reports
+:tests/property-tests/build/reports => property-tests/build/reports
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/ +:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
""".trimIndent() """.trimIndent()
@ -54,7 +53,7 @@ abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
// These requirements define Linux-Medium configuration. // These requirements define Linux-Medium configuration.
// Unfortunately, requirement by name (teamcity.agent.name) doesn't work // Unfortunately, requirement by name (teamcity.agent.name) doesn't work
// IDK the reason for it, but on our agents this property is empty // IDK the reason for it, but on our agents this property is empty
equals("teamcity.agent.hardware.cpuCount", "16") equals("teamcity.agent.hardware.cpuCount", "4")
equals("teamcity.agent.os.family", "Linux") equals("teamcity.agent.os.family", "Linux")
} }

View File

@ -40,9 +40,6 @@ object Compatibility : IdeaVimBuildType({
# java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city # java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.peekaboo' [latest-IU] -team-city
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.switch' [latest-IU] -team-city
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.functiontextobj' [latest-IU] -team-city
""".trimIndent() """.trimIndent()
} }
} }

View File

@ -41,7 +41,7 @@ object ReleaseEapFromBranch : IdeaVimBuildType({
vcs { vcs {
root(ReleasesVcsRoot) root(ReleasesVcsRoot)
branchFilter = """ branchFilter = """
+:heads/releases/* +:heads/(releases/*)
""".trimIndent() """.trimIndent()
checkoutMode = CheckoutMode.AUTO checkoutMode = CheckoutMode.AUTO

View File

@ -39,11 +39,9 @@ open class TestingBuildType(
steps { steps {
gradle { gradle {
clearConditions()
tasks = "clean test" tasks = "clean test"
buildFile = "" buildFile = ""
enableStacktrace = true enableStacktrace = true
jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
} }
} }

View File

@ -1,5 +1,6 @@
package _Self.subprojects package _Self.subprojects
import _Self.Constants
import _Self.IdeaVimBuildType import _Self.IdeaVimBuildType
import _Self.vcsRoots.GitHubPullRequest import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
@ -24,6 +25,7 @@ class GithubBuildType(command: String, desc: String) : IdeaVimBuildType({
params { params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", Constants.GITHUB_TESTS)
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
} }

25
.teamcity/_Self/subprojects/OldTests.kt vendored Normal file
View File

@ -0,0 +1,25 @@
package _Self.subprojects
import _Self.buildTypes.TestingBuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
object OldTests : Project({
name = "Old IdeaVim tests"
description = "Tests for older versions of IJ"
buildType(TestingBuildType("IC-2018.1", "181-182", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2018.2", "181-182", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2018.3", "183", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2019.1", "191-193", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2019.2", "191-193", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2019.3", "191-193", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2020.1", "201", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2020.2", "202", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2020.3", "203-212", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2021.1", "203-212", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2021.2.2", "203-212", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2021.3.2", "213-221", javaVersion = "1.8", javaPlugin = false))
buildType(TestingBuildType("IC-2022.2.3", branch = "222", javaPlugin = false))
buildType(TestingBuildType("IC-2023.1", "231-232", javaPlugin = false))
buildType(TestingBuildType("IC-2023.2", "231-232", javaPlugin = false))
})

View File

@ -0,0 +1,39 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.GradleBuildStep
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with id = 'IdeaVimTests_Latest_EAP'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("IdeaVimTests_Latest_EAP")) {
check(artifactRules == """
+:build/reports => build/reports
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
""".trimIndent()) {
"Unexpected option value: artifactRules = $artifactRules"
}
artifactRules = """
+:build/reports => build/reports
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
+:tests/java-tests/build/reports => tests/java-tests/build/reports
""".trimIndent()
expectSteps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
}
}
steps {
update<GradleBuildStep>(0) {
clearConditions()
jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
}
}
}

View File

@ -0,0 +1,19 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with id = 'ReleaseEapFromBranch'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("ReleaseEapFromBranch")) {
vcs {
check(branchFilter == "+:heads/(releases/*)") {
"Unexpected option value: branchFilter = $branchFilter"
}
branchFilter = "heads/releases/*"
}
}

View File

@ -539,30 +539,6 @@ Contributors:
[![icon][github]](https://github.com/felixwiemuth) [![icon][github]](https://github.com/felixwiemuth)
&nbsp; &nbsp;
Felix Wiemuth Felix Wiemuth
* [![icon][mail]](mailto:kirill.karnaukhov@jetbrains.com)
[![icon][github]](https://github.com/kkarnauk)
&nbsp;
Kirill Karnaukhov,
* [![icon][mail]](mailto:sander.hestvik@gmail.com)
[![icon][github]](https://github.com/SanderHestvik)
&nbsp;
SanderHestvik
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
[![icon][github]](https://github.com/gregsh)
&nbsp;
Greg Shrago
* [![icon][mail]](mailto:jphalip@gmail.com)
[![icon][github]](https://github.com/jphalip)
&nbsp;
Julien Phalip
* [![icon][mail]](mailto:j.trimailovas@gmail.com)
[![icon][github]](https://github.com/trimailov)
&nbsp;
Justas Trimailovas,
* [![icon][mail]](mailto:justast@wix.com)
[![icon][github]](https://github.com/justast-wix)
&nbsp;
Justas Trimailovas
Previous contributors: Previous contributors:
@ -574,10 +550,6 @@ Previous contributors:
[![icon][github]](https://github.com/kevin70) [![icon][github]](https://github.com/kevin70)
&nbsp; &nbsp;
kk kk
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
[![icon][github]](https://github.com/gregsh)
&nbsp;
Greg Shrago
If you are a contributor and your name is not listed here, feel free to If you are a contributor and your name is not listed here, feel free to

View File

@ -21,7 +21,7 @@ repositories {
} }
dependencies { dependencies {
compileOnly("com.google.devtools.ksp:symbol-processing-api:2.1.0-1.0.29") compileOnly("com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.24")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") {
// kotlin stdlib is provided by IJ, so there is no need to include it into the distribution // kotlin stdlib is provided by IJ, so there is no need to include it into the distribution
exclude("org.jetbrains.kotlin", "kotlin-stdlib") exclude("org.jetbrains.kotlin", "kotlin-stdlib")

View File

@ -50,14 +50,14 @@ buildscript {
classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r") classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
// This is needed for jgit to connect to ssh // This is needed for jgit to connect to ssh
classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r") classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
classpath("org.kohsuke:github-api:1.305") classpath("org.kohsuke:github-api:1.305")
classpath("io.ktor:ktor-client-core:3.0.2") classpath("io.ktor:ktor-client-core:2.3.12")
classpath("io.ktor:ktor-client-cio:3.0.2") classpath("io.ktor:ktor-client-cio:2.3.10")
classpath("io.ktor:ktor-client-auth:3.0.2") classpath("io.ktor:ktor-client-auth:2.3.12")
classpath("io.ktor:ktor-client-content-negotiation:3.0.2") classpath("io.ktor:ktor-client-content-negotiation:2.3.10")
classpath("io.ktor:ktor-serialization-kotlinx-json:3.0.2") classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
// This comes from the changelog plugin // This comes from the changelog plugin
// classpath("org.jetbrains:markdown:0.3.1") // classpath("org.jetbrains:markdown:0.3.1")
@ -69,7 +69,7 @@ plugins {
kotlin("jvm") version "2.0.0" kotlin("jvm") version "2.0.0"
application application
id("java-test-fixtures") id("java-test-fixtures")
id("org.jetbrains.intellij.platform") version "2.2.0" id("org.jetbrains.intellij.platform") version "2.0.0-rc2"
id("org.jetbrains.changelog") version "2.2.1" id("org.jetbrains.changelog") version "2.2.1"
id("org.jetbrains.kotlinx.kover") version "0.6.1" id("org.jetbrains.kotlinx.kover") version "0.6.1"
id("com.dorongold.task-tree") version "4.0.0" id("com.dorongold.task-tree") version "4.0.0"
@ -85,6 +85,7 @@ val ideaVersion: String by project
val ideaType: String by project val ideaType: String by project
val instrumentPluginCode: String by project val instrumentPluginCode: String by project
val remoteRobotVersion: String by project val remoteRobotVersion: String by project
val splitModeVersion: String by project
val publishChannels: String by project val publishChannels: String by project
val publishToken: String by project val publishToken: String by project
@ -107,17 +108,13 @@ dependencies {
compileOnly(project(":annotation-processors")) compileOnly(project(":annotation-processors"))
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
compileOnly("org.jetbrains:annotations:26.0.1") compileOnly("org.jetbrains:annotations:24.1.0")
intellijPlatform { intellijPlatform {
// Snapshots don't use installers
// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html#target-versions-installers
val useInstaller = "EAP-SNAPSHOT" !in ideaVersion
// Note that it is also possible to use local("...") to compile against a locally installed IDE // Note that it is also possible to use local("...") to compile against a locally installed IDE
// E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app") // E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
// Or something like: intellijIdeaUltimate(ideaVersion) // Or something like: intellijIdeaUltimate(ideaVersion)
create(ideaType, ideaVersion, useInstaller) create(ideaType, ideaVersion)
pluginVerifier() pluginVerifier()
zipSigner() zipSigner()
@ -150,17 +147,17 @@ dependencies {
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin // https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0") testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5") testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5") testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5") testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5") testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
// Temp workaround suggested in https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4 // Temp workaround suggested in https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4
// Can be removed when IJPL-159134 is fixed // Can be removed when IJPL-159134 is fixed
// testRuntimeOnly("junit:junit:4.13.2") // testRuntimeOnly("junit:junit:4.13.2")
testImplementation("org.junit.vintage:junit-vintage-engine:5.10.5") testImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
// testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3") // testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
} }
@ -235,7 +232,6 @@ tasks {
// Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies // Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
// Note that the version must be greater than the plugin's target version, for obvious reasons // Note that the version must be greater than the plugin's target version, for obvious reasons
// You can also set splitMode and splitModeTarget here to test split mode in a custom IDE
// val runIdeCustom by intellijPlatformTesting.runIde.registering { // val runIdeCustom by intellijPlatformTesting.runIde.registering {
// type = IntelliJPlatformType.Rider // type = IntelliJPlatformType.Rider
// version = "2024.1.2" // version = "2024.1.2"
@ -268,6 +264,10 @@ tasks {
val runIdeSplitMode by intellijPlatformTesting.runIde.registering { val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
splitMode = true splitMode = true
splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
// Frontend split mode support requires 242+
// TODO: Remove this once IdeaVim targets 242, as the task will naturally use the target version to run
version.set(splitModeVersion)
} }
// Add plugin open API sources to the plugin ZIP // Add plugin open API sources to the plugin ZIP

View File

@ -1,6 +1,6 @@
Welcome to the IdeaVim wiki! Welcome to the IdeaVim wiki!
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins.md) - List of IdeaVim plugins: [plugins](IdeaVim%20Plugins)
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples.md) - Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples)
- List of "set" commands: ["set" commands](set-commands.md) - List of "set" commands: ["set" commands](set-commands)
- Docs about "select" mode in vim: [select mode](Select-mode.md) - Docs about "select" mode in vim: [select mode](Select-mode)

View File

@ -82,7 +82,7 @@ Original plugin: [NERDTree](https://github.com/preservim/nerdtree).
### Instructions ### Instructions
[See here](NERDTree-support.md). [See here](NERDTree-support).
</details> </details>
@ -322,9 +322,6 @@ If you want to optimize highlight duration, assign a time in milliseconds:
If you want to change background color of highlight you can provide the rgba of the color you want e.g. If you want to change background color of highlight you can provide the rgba of the color you want e.g.
`let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"` `let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"`
If you want to change text color of highlight you can provide the rgba of the color you want e.g.
`let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"`
https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt
</details> </details>
@ -438,50 +435,3 @@ Original plugin: [vim-which-key](https://github.com/liuchengxu/vim-which-key).
https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation
</details> </details>
<details>
<summary><h2>Vim Peekaboo</h2></summary>
By Julien Phalip
Original plugin: [vim-peekaboo](https://github.com/junegunn/vim-peekaboo).
### Setup
Add `set peekaboo` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
or restart the IDE.
### Instructions
https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
</details>
<details>
<summary><h2>FunctionTextObj</h2></summary>
By Julien Phalip
### Setup
Add `set functiontextobj` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
or restart the IDE.
### Instructions
https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
</details>
<details>
<summary><h2>Switch</h2></summary>
By Julien Phalip
Original plugin: [switch.vim](https://github.com/AndrewRadev/switch.vim).
### Setup
Add `set switch` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
or restart the IDE.
### Instructions
https://plugins.jetbrains.com/plugin/25899-vim-switch
</details>

View File

@ -25,7 +25,7 @@ It's not intended to be read by the users as it brings no value to them.
IdeaVim has multiple YouTrack statuses, main are: IdeaVim has multiple YouTrack statuses, main are:
- Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets. - Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets.
- Open: issues is processed by our team, what means that the issues is reproduced and accepted - Open: issues is processed by out team, what means that the issues is reproduced and accepted
- Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the - Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the
user doesn't reply in 30 days. user doesn't reply in 30 days.
- Ready To Release: Bug is fixed, but not yet released - Ready To Release: Bug is fixed, but not yet released

View File

@ -20,11 +20,17 @@ ideaVersion=2024.2
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type # Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
ideaType=IC ideaType=IC
instrumentPluginCode=true instrumentPluginCode=true
version=chylex-42 version=chylex-41
javaVersion=17 javaVersion=17
remoteRobotVersion=0.11.23 remoteRobotVersion=0.11.23
antlrVersion=4.10.1 antlrVersion=4.10.1
# [VERSION UPDATE] 2024.2 - remove when IdeaVim targets 2024.2
# Running IdeaVim in split mode requires 242. Update this version once 242 has been released, and remove it completely
# when IdeaVim targets 242, at which point runIdeSplitMode will run correctly with the target version.
# See also runIdeSplitMode
splitModeVersion=242-EAP-SNAPSHOT
# Please don't forget to update kotlin version in buildscript section # Please don't forget to update kotlin version in buildscript section
# Also update kotlinxSerializationVersion version # Also update kotlinxSerializationVersion version

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

22
gradlew vendored
View File

@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -57,7 +55,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -85,9 +83,7 @@ done
# This is normally unused # This is normally unused
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -148,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045 # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@ -156,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045 # shellcheck disable=SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -205,11 +201,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command: # Collect all arguments for the java command;
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# and any embedded shellness will be escaped. # shell script including quotes and variable substitutions, so put them in
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # double quotes to make sure that they get re-expanded; and
# treated as '${Hostname}' itself on the command line. # * put everything else in single quotes, so that it's not re-expanded.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

22
gradlew.bat vendored
View File

@ -13,8 +13,6 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@ -45,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail
@ -59,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail

View File

@ -20,17 +20,17 @@ repositories {
} }
dependencies { dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0") compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.25")
implementation("io.ktor:ktor-client-core:3.0.2") implementation("io.ktor:ktor-client-core:2.3.12")
implementation("io.ktor:ktor-client-cio:3.0.2") implementation("io.ktor:ktor-client-cio:2.3.10")
implementation("io.ktor:ktor-client-content-negotiation:3.0.2") implementation("io.ktor:ktor-client-content-negotiation:2.3.10")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.2") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
implementation("io.ktor:ktor-client-auth:3.0.2") implementation("io.ktor:ktor-client-auth:2.3.12")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r") implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
// This is needed for jgit to connect to ssh // This is needed for jgit to connect to ssh
implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r") implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
implementation("com.vdurmont:semver4j:3.1.0") implementation("com.vdurmont:semver4j:3.1.0")
} }

View File

@ -40,9 +40,6 @@ val knownPlugins = setOf(
"com.protoseo.input-source-auto-converter", "com.protoseo.input-source-auto-converter",
// "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for // "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
"com.julienphalip.ideavim.peekaboo", // https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
"com.julienphalip.ideavim.switch", // https://plugins.jetbrains.com/plugin/25899-vim-switch
"com.julienphalip.ideavim.functiontextobj", // https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
) )
suspend fun main() { suspend fun main() {

View File

@ -33,9 +33,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
private var firstInitializationOccurred = false private var firstInitializationOccurred = false
// TODO
// We should migrate to some solution from https://plugins.jetbrains.com/docs/intellij/plugin-components.html#application-startup
// If you'd like to add a new code here, please consider using one of the things described there.
override suspend fun execute(project: Project) { override suspend fun execute(project: Project) {
if (firstInitializationOccurred) return if (firstInitializationOccurred) return
firstInitializationOccurred = true firstInitializationOccurred = true

View File

@ -10,7 +10,6 @@ package com.maddyhome.idea.vim;
import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.Application; import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.PersistentStateComponent;
@ -25,8 +24,10 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.SlowOperations; import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.*; import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.api.VimKeyGroup;
import com.maddyhome.idea.vim.api.VimOptionGroup;
import com.maddyhome.idea.vim.config.VimState; import com.maddyhome.idea.vim.config.VimState;
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator; import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar; import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
@ -35,6 +36,7 @@ import com.maddyhome.idea.vim.group.copy.PutGroup;
import com.maddyhome.idea.vim.group.visual.VisualMotionGroup; import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
import com.maddyhome.idea.vim.helper.MacKeyRepeat; import com.maddyhome.idea.vim.helper.MacKeyRepeat;
import com.maddyhome.idea.vim.listener.VimListenerManager; import com.maddyhome.idea.vim.listener.VimListenerManager;
import com.maddyhome.idea.vim.newapi.IjVimInjector;
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt; import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup; import com.maddyhome.idea.vim.newapi.IjVimSearchGroup;
import com.maddyhome.idea.vim.ui.StatusBarIconFactory; import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
@ -139,8 +141,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
return (MacroGroup)VimInjectorKt.getInjector().getMacro(); return (MacroGroup)VimInjectorKt.getInjector().getMacro();
} }
public static @NotNull VimDigraphGroup getDigraph() { public static @NotNull DigraphGroup getDigraph() {
return VimInjectorKt.getInjector().getDigraphGroup(); return (DigraphGroup)VimInjectorKt.getInjector().getDigraphGroup();
} }
public static @NotNull HistoryGroup getHistory() { public static @NotNull HistoryGroup getHistory() {
@ -337,9 +339,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
// 4) ~/.ideavimrc execution // 4) ~/.ideavimrc execution
// Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window // Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
try (AccessToken ignore = SlowOperations.knownIssue("VIM-3661")) {
registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow()); registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
}
// Turing on should be performed after all commands registration // Turing on should be performed after all commands registration
getSearch().turnOn(); getSearch().turnOn();

View File

@ -298,10 +298,26 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
.addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK))
.addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0)) .addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0))
.addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK))
.addAll(getKeyStrokes(KeyEvent.VK_UP, 0)) .addAll(getKeyStrokes(KeyEvent.VK_UP, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
.addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0)) .addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
.addAll(getKeyStrokes(KeyEvent.VK_LEFT, 0)) .addAll(
.addAll(getKeyStrokes(KeyEvent.VK_RIGHT, 0)) getKeyStrokes(
KeyEvent.VK_LEFT,
0,
InputEvent.CTRL_DOWN_MASK,
InputEvent.SHIFT_DOWN_MASK,
InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
),
)
.addAll(
getKeyStrokes(
KeyEvent.VK_RIGHT,
0,
InputEvent.CTRL_DOWN_MASK,
InputEvent.SHIFT_DOWN_MASK,
InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
),
)
.addAll( .addAll(
getKeyStrokes( getKeyStrokes(
KeyEvent.VK_HOME, KeyEvent.VK_HOME,

View File

@ -40,7 +40,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecuti
): Boolean { ): Boolean {
injector.editorGroup.notifyIdeaJoin(editor) injector.editorGroup.notifyIdeaJoin(editor)
return injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, false) return injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false)
} }
override fun execute( override fun execute(

View File

@ -35,7 +35,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
injector.editorGroup.notifyIdeaJoin(editor) injector.editorGroup.notifyIdeaJoin(editor)
var res = true var res = true
editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret -> editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
if (!injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, true)) { if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true)) {
res = false res = false
} }
} }

View File

@ -44,7 +44,6 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution(
val range = caretsAndSelections[caret] ?: return@forEach val range = caretsAndSelections[caret] ?: return@forEach
if (!injector.changeGroup.deleteJoinRange( if (!injector.changeGroup.deleteJoinRange(
editor, editor,
context,
caret, caret,
range.toVimTextRange(true).normalize(), range.toVimTextRange(true).normalize(),
false, false,

View File

@ -44,7 +44,6 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec
val range = caretsAndSelections[caret] ?: return@forEach val range = caretsAndSelections[caret] ?: return@forEach
if (!injector.changeGroup.deleteJoinRange( if (!injector.changeGroup.deleteJoinRange(
editor, editor,
context,
caret, caret,
range.toVimTextRange(true).normalize(), range.toVimTextRange(true).normalize(),
true, true,

View File

@ -20,8 +20,6 @@ import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.IdeActionHandler import com.maddyhome.idea.vim.handler.IdeActionHandler
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
import java.util.* import java.util.*
@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT]) @CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
@ -41,13 +39,8 @@ internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CA
operatorArguments: OperatorArguments operatorArguments: OperatorArguments
): Boolean { ): Boolean {
val undo = injector.undo val undo = injector.undo
when (undo) {
is VimKeyBasedUndoService -> undo.setMergeUndoKey()
is VimTimestampBasedUndoService -> {
val nanoTime = System.nanoTime() val nanoTime = System.nanoTime()
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) } editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
}
}
return super.execute(editor, context, cmd, operatorArguments) return super.execute(editor, context, cmd, operatorArguments)
} }
} }
@ -70,13 +63,8 @@ internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARE
operatorArguments: OperatorArguments operatorArguments: OperatorArguments
): Boolean { ): Boolean {
val undo = injector.undo val undo = injector.undo
when (undo) {
is VimKeyBasedUndoService -> undo.setMergeUndoKey()
is VimTimestampBasedUndoService -> {
val nanoTime = System.nanoTime() val nanoTime = System.nanoTime()
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) } editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
}
}
return super.execute(editor, context, cmd, operatorArguments) return super.execute(editor, context, cmd, operatorArguments)
} }
} }

View File

@ -27,30 +27,6 @@ public interface VimExtension {
return MappingOwner.Plugin.Companion.get(getName()); return MappingOwner.Plugin.Companion.get(getName());
} }
/**
* This method is always called AFTER the full execution of the `.ideavimrc` file.
* <p>
* During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
* This practically means that the .vimrc file is initialized first; then the plugins are loaded.
* See `:h initialization`
* <p>
* Why does this matter? Because this affects the order of commands are executed. For example,
* ```
* plug 'tommcdo/vim-exchange'
* let g:exchange_no_mappings=1
* ```
* Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
* immediately, this variable won't be initialized at the moment of plugin initialization.
* <p>
* There is also a tricky case for mappings override:
* ```
* plug 'tommcdo/vim-exchange'
* map X <Plug>(ExchangeLine)
* ```
* For this case, a plugin with a good implementation detects that there is already a defined mapping for
* `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
* to be defined before the plugin initialization.
*/
void init(); void init();
default void dispose() { default void dispose() {

View File

@ -69,7 +69,8 @@ object VimExtensionFacade {
@JvmStatic @JvmStatic
@Deprecated("Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)", @Deprecated(
"Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
ReplaceWith( ReplaceWith(
"VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)", "VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
"com.maddyhome.idea.vim.VimPlugin" "com.maddyhome.idea.vim.VimPlugin"
@ -188,22 +189,14 @@ object VimExtensionFacade {
/** Get the current contents of the given register similar to 'getreg()'. */ /** Get the current contents of the given register similar to 'getreg()'. */
@JvmStatic @JvmStatic
@Deprecated("Please use com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister(com.maddyhome.idea.vim.api.VimEditor, char)")
fun getRegister(register: Char): List<KeyStroke>? { fun getRegister(register: Char): List<KeyStroke>? {
val reg = VimPlugin.getRegister().getRegister(register) ?: return null val reg = VimPlugin.getRegister().getRegister(register) ?: return null
return reg.keys return reg.keys
} }
/** Get the current contents of the given register similar to 'getreg()'. */
@JvmStatic
fun getRegister(editor: VimEditor, register: Char): List<KeyStroke>? {
val reg = VimPlugin.getRegister().getRegister(editor, injector.executionContextManager.getEditorExecutionContext(editor), register) ?: return null
return reg.keys
}
@JvmStatic @JvmStatic
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? { fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
val reg = caret.registerStorage.getRegister(register) ?: return null val reg = injector.registerGroup.getRegister(register) ?: return null
return reg.keys return reg.keys
} }
@ -216,7 +209,7 @@ object VimExtensionFacade {
/** Set the current contents of the given register */ /** Set the current contents of the given register */
@JvmStatic @JvmStatic
fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) { fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
caret.registerStorage.setKeys(register, keys?.filterNotNull() ?: emptyList()) injector.registerGroup.setKeys(register, keys?.filterNotNull() ?: emptyList())
} }
/** Set the current contents of the given register */ /** Set the current contents of the given register */

View File

@ -88,10 +88,29 @@ internal object VimExtensionRegistrar : VimExtensionRegistrator {
} }
/** /**
* See the docs for [VimExtension.init] * During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
* This practically means that the .vimrc file is initialized first, then the plugins are loaded.
* See `:h initialization`
* *
* In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect * In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
* the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished. * the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
*
* Why this matters? Because this affects the order of commands are executed. For example:
* ```
* plug 'tommcdo/vim-exchange'
* let g:exchange_no_mappings=1
* ```
* Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
* immediately, this variable won't be initialized at the moment of plugin initialization.
*
* There is also a tricky case for mappings override:
* ```
* plug 'tommcdo/vim-exchange'
* map X <Plug>(ExchangeLine)
* ```
* For this case, a plugin with a good implementation detects that there is already a defined mapping for
* `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
* to be defined before the plugin initialization.
*/ */
@JvmStatic @JvmStatic
fun enableDelayedExtensions() { fun enableDelayedExtensions() {

View File

@ -222,10 +222,10 @@ internal class VimExchangeExtension : VimExtension {
} }
} }
val zRegText = getRegister(editor.vim, 'z') val zRegText = getRegister('z')
val unnRegText = getRegister(editor.vim, '"') val unnRegText = getRegister('"')
val startRegText = getRegister(editor.vim, '*') val startRegText = getRegister('*')
val plusRegText = getRegister(editor.vim, '+') val plusRegText = getRegister('+')
runWriteAction { runWriteAction {
// TODO handle: // TODO handle:
// " Compare using =~ because "'==' != 0" returns 0 // " Compare using =~ because "'==' != 0" returns 0
@ -299,7 +299,7 @@ internal class VimExchangeExtension : VimExtension {
private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange { private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange {
// TODO: improve KeyStroke list to sting conversion // TODO: improve KeyStroke list to sting conversion
fun getRegisterText(reg: Char): String = getRegister(editor.vim, reg)?.map { it.keyChar }?.joinToString("") ?: "" fun getRegisterText(reg: Char): String = getRegister(reg)?.map { it.keyChar }?.joinToString("") ?: ""
fun getMarks(isVisual: Boolean): Pair<Mark, Mark> { fun getMarks(isVisual: Boolean): Pair<Mark, Mark> {
val (startMark, endMark) = val (startMark, endMark) =
if (isVisual) { if (isVisual) {
@ -313,9 +313,9 @@ internal class VimExchangeExtension : VimExtension {
return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!) return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!)
} }
val unnRegText = getRegister(editor.vim, '"') val unnRegText = getRegister('"')
val starRegText = getRegister(editor.vim, '*') val starRegText = getRegister('*')
val plusRegText = getRegister(editor.vim, '+') val plusRegText = getRegister('+')
val (selectionStart, selectionEnd) = getMarks(isVisual) val (selectionStart, selectionEnd) = getMarks(isVisual)
if (isVisual) { if (isVisual) {

View File

@ -45,10 +45,6 @@ private val HIGHLIGHT_DURATION_VARIABLE_NAME = "highlightedyank_highlight_durati
@NonNls @NonNls
private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color" private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color"
@NonNls
private val HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME = "highlightedyank_highlight_foreground_color"
private var defaultHighlightTextColor: Color? = null private var defaultHighlightTextColor: Color? = null
private fun getDefaultHighlightTextColor(): Color { private fun getDefaultHighlightTextColor(): Color {
@ -79,9 +75,6 @@ internal class HighlightColorResetter : LafManagerListener {
* if you want to change background color of highlight you can provide the rgba of the color you want e.g. * if you want to change background color of highlight you can provide the rgba of the color you want e.g.
* let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)" * let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"
* *
* if you want to change text color of highlight you can provide the rgba of the color you want e.g.
* let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"
*
* When a new text is yanked or user starts editing, the old highlighting would be deleted. * When a new text is yanked or user starts editing, the old highlighting would be deleted.
*/ */
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener { internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
@ -188,15 +181,13 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
highlighters.clear() highlighters.clear()
} }
private fun getHighlightTextAttributes(editor: Editor): TextAttributes { private fun getHighlightTextAttributes(editor: Editor) = TextAttributes(
return TextAttributes( null,
extractUserHighlightForegroundColor(),
extractUsersHighlightColor(), extractUsersHighlightColor(),
editor.colorsScheme.getColor(EditorColors.CARET_COLOR), editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
EffectType.SEARCH_MATCH, EffectType.SEARCH_MATCH,
Font.PLAIN, Font.PLAIN,
) )
}
private fun extractUsersHighlightDuration(): Int { private fun extractUsersHighlightDuration(): Int {
return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) { return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) {
@ -209,52 +200,15 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
} }
private fun extractUsersHighlightColor(): Color { private fun extractUsersHighlightColor(): Color {
val value = VimPlugin.getVariableService().getGlobalVariableValue(HIGHLIGHT_COLOR_VARIABLE_NAME) return extractVariable(HIGHLIGHT_COLOR_VARIABLE_NAME, getDefaultHighlightTextColor()) { value ->
if (value != null) { val rgba = value.asString()
return try {
parseRgbaColor(value.asString())
} catch (e: Exception) {
@VimNlsSafe val message = MessageHelper.message(
"highlightedyank.invalid.value.of.0.1",
"g:$HIGHLIGHT_COLOR_VARIABLE_NAME",
e.message ?: "",
)
VimPlugin.showMessage(message)
getDefaultHighlightTextColor()
}
}
return getDefaultHighlightTextColor()
}
private fun extractUserHighlightForegroundColor(): Color? {
val value = VimPlugin.getVariableService().getGlobalVariableValue(HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME)
?: return null
return try {
parseRgbaColor(value.asString())
} catch (e: Exception) {
@VimNlsSafe val message = MessageHelper.message(
"highlightedyank.invalid.value.of.0.1",
"g:$HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME",
e.message ?: "",
)
VimPlugin.showMessage(message)
null
}
}
private fun parseRgbaColor(colorString: String): Color {
val rgba = colorString
.substring(4) .substring(4)
.filter { it != '(' && it != ')' && !it.isWhitespace() } .filter { it != '(' && it != ')' && !it.isWhitespace() }
.split(',') .split(',')
.map { it.toInt() } .map { it.toInt() }
if (rgba.size != 4 || rgba.any { it < 0 || it > 255 }) { Color(rgba[0], rgba[1], rgba[2], rgba[3])
throw IllegalArgumentException("Invalid RGBA values. Each component must be between 0 and 255")
} }
return Color(rgba[0], rgba[1], rgba[2], rgba[3])
} }
private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T { private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T {

View File

@ -42,10 +42,13 @@ import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.group.KeyGroup import com.maddyhome.idea.vim.group.KeyGroup
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.runAfterGotFocus import com.maddyhome.idea.vim.helper.runAfterGotFocus
import com.maddyhome.idea.vim.key.KeyStrokeTrie import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.key.MappingOwner import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.key.RequiredShortcut import com.maddyhome.idea.vim.key.RequiredShortcut
import com.maddyhome.idea.vim.key.add import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.key.addLeafs
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@ -195,8 +198,6 @@ internal class NerdTree : VimExtension {
internal var waitForSearch = false internal var waitForSearch = false
internal var speedSearchListenerInstalled = false internal var speedSearchListenerInstalled = false
private val keys = mutableListOf<KeyStroke>()
override fun actionPerformed(e: AnActionEvent) { override fun actionPerformed(e: AnActionEvent) {
var keyStroke = getKeyStroke(e) ?: return var keyStroke = getKeyStroke(e) ?: return
val keyChar = keyStroke.keyChar val keyChar = keyStroke.keyChar
@ -204,14 +205,20 @@ internal class NerdTree : VimExtension {
keyStroke = KeyStroke.getKeyStroke(keyChar) keyStroke = KeyStroke.getKeyStroke(keyChar)
} }
keys.add(keyStroke) val nextNode = currentNode[keyStroke]
actionsRoot.getData(keys)?.let { action ->
when (nextNode) {
null -> currentNode = actionsRoot
is CommandNode<NerdAction> -> {
currentNode = actionsRoot
val action = nextNode.actionHolder
when (action) { when (action) {
is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim) is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim)
is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) } is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) }
} }
}
keys.clear() is CommandPartNode<NerdAction> -> currentNode = nextNode
} }
} }
@ -533,29 +540,38 @@ private fun addCommand(alias: String, handler: CommandAliasHandler) {
VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler)) VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler))
} }
private fun registerCommand(variable: String, defaultMapping: String, action: NerdAction) { private fun registerCommand(variable: String, default: String, action: NerdAction) {
val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable) val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable)
val mapping = if (variableValue is VimString) { val mappings = if (variableValue is VimString) {
variableValue.value variableValue.value
} else { } else {
defaultMapping default
} }
registerCommand(mapping, action) actionsRoot.addLeafs(mappings, action)
} }
private fun registerCommand(mapping: String, action: NerdAction) { private fun registerCommand(default: String, action: NerdAction) {
actionsRoot.add(mapping, action) actionsRoot.addLeafs(default, action)
injector.parser.parseKeys(mapping).forEach {
distinctShortcuts.add(it)
}
} }
private val actionsRoot: KeyStrokeTrie<NerdAction> = KeyStrokeTrie<NerdAction>("NERDTree")
private val distinctShortcuts = mutableSetOf<KeyStroke>() private val actionsRoot: RootNode<NerdAction> = RootNode("NERDTree")
private var currentNode: CommandPartNode<NerdAction> = actionsRoot
private fun collectShortcuts(node: Node<NerdAction>): Set<KeyStroke> {
return if (node is CommandPartNode<NerdAction>) {
val res = node.children.keys.toMutableSet()
res += node.children.values.map { collectShortcuts(it) }.flatten()
res
} else {
emptySet()
}
}
private fun installDispatcher(project: Project) { private fun installDispatcher(project: Project) {
val dispatcher = NerdTree.NerdDispatcher.getInstance(project) val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
val shortcuts = distinctShortcuts.map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) } val shortcuts =
collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
dispatcher.registerCustomShortcutSet( dispatcher.registerCustomShortcutSet(
KeyGroup.toShortcutSet(shortcuts), KeyGroup.toShortcutSet(shortcuts),
(ProjectView.getInstance(project) as ProjectViewImpl).component, (ProjectView.getInstance(project) as ProjectViewImpl).component,

View File

@ -62,7 +62,7 @@ internal class ParagraphMotion : VimExtension {
toKeys: List<KeyStroke>, toKeys: List<KeyStroke>,
recursive: Boolean, recursive: Boolean,
) { ) {
val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().getKeyMapping(it).getLayer(fromKeys) != null } val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().hasmapfrom(it, fromKeys) }
putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive) putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive)
} }
} }

View File

@ -143,7 +143,7 @@ internal class ReplaceWithRegister : VimExtension {
private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) { private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
val registerGroup = injector.registerGroup val registerGroup = injector.registerGroup
val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret() val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
val savedRegister = caret.registerStorage.getRegister(lastRegisterChar) ?: return val savedRegister = registerGroup.getRegister(lastRegisterChar) ?: return
var usedType = savedRegister.type var usedType = savedRegister.type
var usedText = savedRegister.text var usedText = savedRegister.text

View File

@ -34,7 +34,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionHandler import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.helper.StrictMode import com.maddyhome.idea.vim.helper.StrictMode
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import org.jetbrains.annotations.TestOnly
import java.awt.Font import java.awt.Font
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import java.util.* import java.util.*
@ -46,26 +45,15 @@ private const val DEFAULT_HIGHLIGHT_DURATION_SNEAK = 300
// By [Mikhail Levchenko](https://github.com/Mishkun) // By [Mikhail Levchenko](https://github.com/Mishkun)
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak // Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
internal class IdeaVimSneakExtension : VimExtension { internal class IdeaVimSneakExtension : VimExtension {
@Suppress("CompanionObjectInExtension")
companion object {
private var highlightHandler: HighlightHandler? = null
@TestOnly
internal fun stopTimer() {
highlightHandler?.stopExistingTimer()
}
}
override fun getName(): String = "sneak" override fun getName(): String = "sneak"
override fun init() { override fun init() {
val _highlightHandler = HighlightHandler() val highlightHandler = HighlightHandler()
highlightHandler = _highlightHandler mapToFunctionAndProvideKeys("s", SneakHandler(highlightHandler, Direction.FORWARD), MappingMode.NXO)
mapToFunctionAndProvideKeys("s", SneakHandler(_highlightHandler, Direction.FORWARD), MappingMode.NXO)
// vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330 // vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330
mapToFunctionAndProvideKeys("S", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.NO) mapToFunctionAndProvideKeys("S", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.NO)
mapToFunctionAndProvideKeys("Z", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.X) mapToFunctionAndProvideKeys("Z", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.X)
// workaround to support ; and , commands // workaround to support ; and , commands
mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO) mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO)
@ -73,8 +61,8 @@ internal class IdeaVimSneakExtension : VimExtension {
mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO) mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO)
mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO) mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO)
mapToFunctionAndProvideKeys(";", SneakRepeatHandler(_highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO) mapToFunctionAndProvideKeys(";", SneakRepeatHandler(highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO)
mapToFunctionAndProvideKeys(",", SneakRepeatHandler(_highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO) mapToFunctionAndProvideKeys(",", SneakRepeatHandler(highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO)
} }
private class SneakHandler( private class SneakHandler(
@ -221,7 +209,6 @@ internal class IdeaVimSneakExtension : VimExtension {
private class HighlightHandler { private class HighlightHandler {
private var editor: Editor? = null private var editor: Editor? = null
private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf() private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf()
private var timer: Timer? = null
fun highlightSneakRange(editor: Editor, range: TextRange) { fun highlightSneakRange(editor: Editor, range: TextRange) {
clearAllSneakHighlighters() clearAllSneakHighlighters()
@ -267,19 +254,13 @@ internal class IdeaVimSneakExtension : VimExtension {
} }
private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) { private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
stopExistingTimer() val timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
if (editor?.isDisposed != true) { if (editor?.isDisposed != true) {
editor?.markupModel?.removeHighlighter(highlighter) editor?.markupModel?.removeHighlighter(highlighter)
} }
} }
timer?.isRepeats = false timer.isRepeats = false
timer?.start() timer.start()
}
fun stopExistingTimer() {
timer?.stop()
timer?.actionListeners?.forEach { it.actionPerformed(null) }
} }
private fun getHighlightTextAttributes() = TextAttributes( private fun getHighlightTextAttributes() = TextAttributes(
@ -326,7 +307,7 @@ private fun VimExtension.mapToFunctionAndProvideKeys(
VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys))) VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
} }
val filteredFromModes = mappingModes.filterNotTo(HashSet()) { val filteredFromModes = mappingModes.filterNotTo(HashSet()) {
injector.keyGroup.getKeyMapping(it).getLayer(fromKeys) != null injector.keyGroup.hasmapfrom(it, fromKeys)
} }
val doubleFiltered = mappingModes val doubleFiltered = mappingModes

View File

@ -47,11 +47,11 @@ import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
import com.maddyhome.idea.vim.put.PutData import com.maddyhome.idea.vim.put.PutData
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.returnTo
import com.maddyhome.idea.vim.state.mode.selectionType import com.maddyhome.idea.vim.state.mode.selectionType
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import javax.swing.KeyStroke import javax.swing.KeyStroke
import com.maddyhome.idea.vim.state.mode.returnTo
/** /**
* Port of vim-surround. * Port of vim-surround.
@ -161,17 +161,17 @@ internal class VimSurroundExtension : VimExtension {
} }
companion object { companion object {
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) { fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) } editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
} }
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) { fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets // Save old register values for carets
val surroundings = editor.sortedCarets() val surroundings = editor.sortedCarets()
.map { .map {
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it) val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
setRegisterForCaret(REGISTER, it, null) setRegisterForCaret(REGISTER, it, null)
SurroundingInfo(it, null, oldValue, false) SurroundingInfo(it, null, oldValue)
} }
// Delete surrounding's content // Delete surrounding's content
@ -187,25 +187,21 @@ internal class VimSurroundExtension : VimExtension {
} }
val registerValue = getRegisterForCaret(REGISTER, it.caret) val registerValue = getRegisterForCaret(REGISTER, it.caret)
val innerValue = if (registerValue.isNullOrEmpty()) emptyList() else registerValue val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue
it.innerText = innerValue it.innerText = innerValue
}
// Valid surroundings are only those that: surroundings.forEach {
// - are validly wrapping with surround characters (i.e. parenthesis, brackets, tags, quotes, etc.); if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
// - or have non-empty inner text (e.g. when we are surrounding words: `csw"`) it.innerText = emptyList()
if (currentSurrounding != null || innerValue.isNotEmpty()) {
it.isValidSurrounding = true
} }
} }
surroundings surroundings
.filter { it.isValidSurrounding } // we do nothing with carets that are not inside the surrounding .filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
.map { surrounding -> .map { surrounding ->
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!) val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
val text = newSurround?.let { val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
val trimmedValue = if (newSurround.shouldTrim) innerValue.trim() else innerValue
it.first + trimmedValue + it.second
} ?: innerValue
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null) val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false) val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
@ -258,7 +254,7 @@ internal class VimSurroundExtension : VimExtension {
} }
} }
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var isValidSurrounding: Boolean) { private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?) {
fun restoreRegister() { fun restoreRegister() {
setRegisterForCaret(REGISTER, caret, oldRegisterContent) setRegisterForCaret(REGISTER, caret, oldRegisterContent)
} }
@ -301,7 +297,7 @@ internal class VimSurroundExtension : VimExtension {
return true return true
} }
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: SurroundPair, count: Int) { private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
// XXX: Will it work with line-wise or block-wise selections? // XXX: Will it work with line-wise or block-wise selections?
val primaryCaret = editor.caretModel.primaryCaret val primaryCaret = editor.caretModel.primaryCaret
val range = getSurroundRange(primaryCaret.vim) val range = getSurroundRange(primaryCaret.vim)
@ -333,35 +329,33 @@ private const val REGISTER = '"'
private const val OPERATOR_FUNC = "SurroundOperatorFunc" private const val OPERATOR_FUNC = "SurroundOperatorFunc"
private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern() private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern()
private data class SurroundPair(val first: String, val second: String, val shouldTrim: Boolean)
private val SURROUND_PAIRS = mapOf( private val SURROUND_PAIRS = mapOf(
'b' to SurroundPair("(", ")", false), 'b' to ("(" to ")"),
'(' to SurroundPair("( ", " )", false), '(' to ("( " to " )"),
')' to SurroundPair("(", ")", true), ')' to ("(" to ")"),
'B' to SurroundPair("{", "}", false), 'B' to ("{" to "}"),
'{' to SurroundPair("{ ", " }", false), '{' to ("{ " to " }"),
'}' to SurroundPair("{", "}", true), '}' to ("{" to "}"),
'r' to SurroundPair("[", "]", false), 'r' to ("[" to "]"),
'[' to SurroundPair("[ ", " ]", false), '[' to ("[ " to " ]"),
']' to SurroundPair("[", "]", true), ']' to ("[" to "]"),
'a' to SurroundPair("<", ">", false), 'a' to ("<" to ">"),
'>' to SurroundPair("<", ">", false), '>' to ("<" to ">"),
's' to SurroundPair(" ", "", false), 's' to (" " to ""),
) )
private fun getSurroundPair(c: Char): SurroundPair? = if (c in SURROUND_PAIRS) { private fun getSurroundPair(c: Char): Pair<String, String>? = if (c in SURROUND_PAIRS) {
SURROUND_PAIRS[c] SURROUND_PAIRS[c]
} else if (!c.isLetter()) { } else if (!c.isLetter()) {
val s = c.toString() val s = c.toString()
SurroundPair(s, s, false) s to s
} else { } else {
null null
} }
private fun inputTagPair(editor: Editor, context: DataContext): SurroundPair? { private fun inputTagPair(editor: Editor, context: DataContext): Pair<String, String>? {
val tagInput = inputString(editor, context, "<", '>') val tagInput = inputString(editor, context, "<", '>')
if (editor.vim.mode is Mode.CMD_LINE) { if (editor.vim.mode is Mode.CMD_LINE) {
editor.vim.mode = editor.vim.mode.returnTo() editor.vim.mode = editor.vim.mode.returnTo()
@ -370,7 +364,7 @@ private fun inputTagPair(editor: Editor, context: DataContext): SurroundPair? {
return if (matcher.find()) { return if (matcher.find()) {
val tagName = matcher.group(1) val tagName = matcher.group(1)
val tagAttributes = matcher.group(2) val tagAttributes = matcher.group(2)
SurroundPair("<$tagName$tagAttributes>", "</$tagName>", false) "<$tagName$tagAttributes>" to "</$tagName>"
} else { } else {
null null
} }
@ -380,20 +374,16 @@ private fun inputFunctionName(
editor: Editor, editor: Editor,
context: DataContext, context: DataContext,
withInternalSpaces: Boolean, withInternalSpaces: Boolean,
): SurroundPair? { ): Pair<String, String>? {
val functionNameInput = inputString(editor, context, "function: ", null) val functionNameInput = inputString(editor, context, "function: ", null)
if (editor.vim.mode is Mode.CMD_LINE) { if (editor.vim.mode is Mode.CMD_LINE) {
editor.vim.mode = editor.vim.mode.returnTo() editor.vim.mode = editor.vim.mode.returnTo()
} }
if (functionNameInput.isEmpty()) return null if (functionNameInput.isEmpty()) return null
return if (withInternalSpaces) { return if (withInternalSpaces) "$functionNameInput( " to " )" else "$functionNameInput(" to ")"
SurroundPair("$functionNameInput( ", " )", false)
} else {
SurroundPair("$functionNameInput(", ")", false)
}
} }
private fun getOrInputPair(c: Char, editor: Editor, context: DataContext): SurroundPair? = when (c) { private fun getOrInputPair(c: Char, editor: Editor, context: DataContext): Pair<String, String>? = when (c) {
'<', 't' -> inputTagPair(editor, context) '<', 't' -> inputTagPair(editor, context)
'f' -> inputFunctionName(editor, context, false) 'f' -> inputFunctionName(editor, context, false)
'F' -> inputFunctionName(editor, context, true) 'F' -> inputFunctionName(editor, context, true)
@ -412,7 +402,7 @@ private fun getChar(editor: Editor): Char {
return res return res
} }
private fun performSurround(pair: SurroundPair, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) { private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) {
runWriteAction { runWriteAction {
val editor = caret.editor val editor = caret.editor
val change = VimPlugin.getChange() val change = VimPlugin.getChange()

View File

@ -36,12 +36,9 @@ import com.maddyhome.idea.vim.helper.inInsertMode
import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance
import com.maddyhome.idea.vim.listener.VimInsertListener import com.maddyhome.idea.vim.listener.VimInsertListener
import com.maddyhome.idea.vim.newapi.IjVimCaret import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.newapi.IjVimCopiedText
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
/** /**
* Provides all the insert/replace related functionality * Provides all the insert/replace related functionality
@ -64,15 +61,9 @@ class ChangeGroup : VimChangeGroupBase() {
val editor = (vimEditor as IjVimEditor).editor val editor = (vimEditor as IjVimEditor).editor
val ijContext = context.ij val ijContext = context.ij
val doc = vimEditor.editor.document val doc = vimEditor.editor.document
val undo = injector.undo val undo = injector.undo
when (undo) {
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
is VimTimestampBasedUndoService -> {
val nanoTime = System.nanoTime() val nanoTime = System.nanoTime()
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) } vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
}
}
CommandProcessor.getInstance().executeCommand( CommandProcessor.getInstance().executeCommand(
editor.project, { editor.project, {
ApplicationManager.getApplication() ApplicationManager.getApplication()
@ -145,10 +136,10 @@ class ChangeGroup : VimChangeGroupBase() {
// FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux // FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux
// FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method // FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method
var copiedText: IjVimCopiedText? = null var primaryTextAndTransferableData: Pair<String, List<Any>?>? = null
try { try {
if (injector.registerGroup.isPrimaryRegisterSupported()) { if (injector.registerGroup.isPrimaryRegisterSupported()) {
copiedText = injector.clipboardManager.getPrimaryContent(editor, context) as IjVimCopiedText primaryTextAndTransferableData = injector.clipboardManager.getPrimaryTextAndTransferableData()
} }
} catch (e: Exception) { } catch (e: Exception) {
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
@ -174,8 +165,12 @@ class ChangeGroup : VimChangeGroupBase() {
afterAction.invoke() afterAction.invoke()
} }
try { try {
if (copiedText != null) { if (primaryTextAndTransferableData != null) {
injector.clipboardManager.setPrimaryContent(editor, context, copiedText) injector.clipboardManager.setPrimaryText(
primaryTextAndTransferableData.first,
primaryTextAndTransferableData.first,
primaryTextAndTransferableData.second ?: emptyList()
)
} }
} catch (e: Exception) { } catch (e: Exception) {
// FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection

View File

@ -0,0 +1,83 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.group;
import com.intellij.openapi.diagnostic.Logger;
import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimOutputPanel;
import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import org.jetbrains.annotations.NotNull;
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
public class DigraphGroup extends VimDigraphGroupBase {
public void showDigraphs(@NotNull VimEditor editor) {
int width = EditorHelper.getApproximateScreenWidth(((IjVimEditor) editor).getEditor());
if (width < 10) {
width = 80;
}
int colCount = width / 12;
int height = (int)Math.ceil((double) getDigraphs().size() / (double)colCount);
if (logger.isDebugEnabled()) {
logger.debug("width=" + width);
logger.debug("colCount=" + colCount);
logger.debug("height=" + height);
}
StringBuilder res = new StringBuilder();
int cnt = 0;
for (Character code : getKeys().keySet()) {
String key = getKeys().get(code);
res.append(key);
res.append(' ');
if (code < 32) {
res.append('^');
res.append((char)(code + '@'));
}
else if (code >= 128 && code <= 159) {
res.append('~');
res.append((char)(code - 128 + '@'));
}
else {
res.append(code);
res.append(' ');
}
res.append(' ');
if (code < 0x1000) {
res.append('0');
}
if (code < 0x100) {
res.append('0');
}
if (code < 0x10) {
res.append('0');
}
res.append(Integer.toHexString(code));
res.append(" ");
cnt++;
if (cnt == colCount) {
res.append('\n');
cnt = 0;
}
}
VimOutputPanel output = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
output.addText(res.toString(), true );
output.show();
}
private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
}

View File

@ -42,6 +42,7 @@ import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.execute import com.maddyhome.idea.vim.newapi.execute
import com.maddyhome.idea.vim.newapi.globalIjOptions import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.state.VimStateMachine.Companion.getInstance
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
import java.io.File import java.io.File
import java.util.* import java.util.*

View File

@ -8,6 +8,7 @@
package com.maddyhome.idea.vim.group; package com.maddyhome.idea.vim.group;
import com.google.common.collect.ImmutableList;
import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
@ -16,16 +17,18 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State; import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.intellij.util.containers.MultiMap;
import com.maddyhome.idea.vim.EventFacade; import com.maddyhome.idea.vim.EventFacade;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction; import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.action.change.LazyVimCommand; import com.maddyhome.idea.vim.action.change.LazyVimCommand;
import com.maddyhome.idea.vim.api.*; import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.MappingMode; import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.key.*; import com.maddyhome.idea.vim.key.*;
import com.maddyhome.idea.vim.newapi.IjNativeAction; import com.maddyhome.idea.vim.newapi.IjNativeAction;
import com.maddyhome.idea.vim.newapi.IjVimEditor; import com.maddyhome.idea.vim.newapi.IjVimEditor;
@ -55,6 +58,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
private static final @NonNls String OWNER_ATTRIBUTE = "owner"; private static final @NonNls String OWNER_ATTRIBUTE = "owner";
private static final String TEXT_ELEMENT = "text"; private static final String TEXT_ELEMENT = "text";
private static final Logger logger = Logger.getInstance(KeyGroup.class);
public void registerRequiredShortcutKeys(@NotNull VimEditor editor) { public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
EventFacade.getInstance() EventFacade.getInstance()
.registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()), .registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
@ -194,7 +199,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE); registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
for (MappingMode mappingMode : command.getModes()) { for (MappingMode mappingMode : command.getModes()) {
getBuiltinCommandsTrie(mappingMode).add(keyStrokes, command); Node<LazyVimCommand> node = getKeyRoot(mappingMode);
NodesKt.addLeafs(node, keyStrokes, command);
} }
} }
} }
@ -219,79 +225,53 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0])); return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0]));
} }
private static @NotNull List<Pair<Set<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes, private static @NotNull List<Pair<EnumSet<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes) {
@NotNull List<? extends KeyStroke> prefix) { final Map<ImmutableList<KeyStroke>, EnumSet<MappingMode>> actualModes = new HashMap<>();
// Some map commands set a mapping for more than one mode (e.g. `map` sets for Normal, Visual, Select and
// Op-pending). Vim treats this as a single mapping, and when listing all maps only lists it once, with the
// appropriate mode indicator(s) in the first column (NVO is a space char). If the lhs mapping is changed or cleared
// for one of the modes, the original mapping is still a single map for the remaining modes, and the indicator
// changes. E.g. `map foo bar` followed by `sunmap foo` would result in `nox foo bar` in the output to `map`.
// Vim doesn't do automatic grouping - `nmap foo bar` followed by `omap foo bar` and `vmap foo bar` would result in
// 3 lines in the output to `map` - one for `n`, one for `o` and one for `v`.
// We store mappings separately per mode (to simplify lookup, especially when matching prefixes), but want to have
// the same behaviour as Vim in map output. So we store the original modes with the mapping and check they're still
// valid as we collect output
final List<Pair<Set<MappingMode>, MappingInfo>> rows = new ArrayList<>();
final MultiMap<List<? extends KeyStroke>, Set<MappingMode>> multiModeMappings = MultiMap.create();
final List<KeyStroke> fromKeys = new ArrayList<>();
for (MappingMode mode : modes) { for (MappingMode mode : modes) {
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode); final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
for (List<? extends KeyStroke> fromKeys : mapping) {
final Iterator<KeyMappingEntry> iterator = mapping.getAll(prefix).iterator(); final ImmutableList<KeyStroke> key = ImmutableList.copyOf(fromKeys);
while (iterator.hasNext()) { final EnumSet<MappingMode> value = actualModes.get(key);
final KeyMappingEntry entry = iterator.next(); final EnumSet<MappingMode> newValue;
final MappingInfo mappingInfo = entry.getMappingInfo(); if (value != null) {
newValue = value.clone();
final Set<@NotNull MappingMode> originalModes = mappingInfo.getOriginalModes(); newValue.add(mode);
if (originalModes.size() == 1) {
rows.add(new Pair<>(originalModes, mappingInfo));
} }
else { else {
entry.collectPath(fromKeys); newValue = EnumSet.of(mode);
if (!multiModeMappings.get(fromKeys).contains(originalModes)) { }
multiModeMappings.putValue(new ArrayList<>(fromKeys), originalModes); actualModes.put(key, newValue);
rows.add(new Pair<>(getModesForMapping(fromKeys, originalModes), mappingInfo)); }
}
final List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = new ArrayList<>();
for (Map.Entry<ImmutableList<KeyStroke>, EnumSet<MappingMode>> entry : actualModes.entrySet()) {
final ArrayList<KeyStroke> fromKeys = new ArrayList<>(entry.getKey());
final EnumSet<MappingMode> mappingModes = entry.getValue();
if (!mappingModes.isEmpty()) {
final MappingMode mode = mappingModes.iterator().next();
final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
final MappingInfo mappingInfo = mapping.get(fromKeys);
if (mappingInfo != null) {
rows.add(new Pair<>(mappingModes, mappingInfo));
} }
} }
} }
} rows.sort(Comparator.comparing(Pair<EnumSet<MappingMode>, MappingInfo>::getSecond));
rows.sort(Comparator.comparing(Pair<Set<MappingMode>, MappingInfo>::getSecond));
return rows; return rows;
} }
private static @NotNull Set<MappingMode> getModesForMapping(@NotNull List<? extends KeyStroke> keyStrokes,
@NotNull Set<MappingMode> originalMappingModes) {
final Set<MappingMode> actualModes = EnumSet.noneOf(MappingMode.class);
for (MappingMode mode : originalMappingModes) {
final MappingInfo mappingInfo = VimPlugin.getKey().getKeyMapping(mode).get(keyStrokes);
if (mappingInfo != null && mappingInfo.getOriginalModes() == originalMappingModes) {
actualModes.add(mode);
}
}
return actualModes;
}
private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) { private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
if (modes.equals(MappingMode.IC)) return "!"; if (modes.equals(MappingMode.NVO)) {
if (modes.equals(MappingMode.NVO)) return " "; return "";
if (modes.equals(MappingMode.C)) return "c";
if (modes.equals(MappingMode.I)) return "i";
//if (modes.equals(MappingMode.L)) return "l";
// The following modes are concatenated
String mode = "";
if (modes.containsAll(MappingMode.N)) mode += "n";
if (modes.containsAll(MappingMode.O)) mode += "o";
if (modes.containsAll(MappingMode.V)) {
mode += "v";
} }
else { else if (modes.contains(MappingMode.INSERT)) {
if (modes.containsAll(MappingMode.X)) mode += "x"; return "i";
if (modes.containsAll(MappingMode.S)) mode += "s";
} }
return mode; else if (modes.contains(MappingMode.NORMAL)) {
return "n";
}
// TODO: Add more codes
return "";
} }
private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) { private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
@ -355,20 +335,20 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
} }
@Override @Override
public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull List<? extends KeyStroke> prefix, @NotNull VimEditor editor) { public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
List<Pair<Set<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes, prefix); List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for (Pair<Set<MappingMode>, MappingInfo> row : rows) { for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
MappingInfo mappingInfo = row.getSecond(); MappingInfo mappingInfo = row.getSecond();
builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 3, ' ')); builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()) + " ", 12, ' ')); builder.append(" ");
builder.append(mappingInfo.isRecursive() ? " " : "*"); // Or `&` if script-local mappings being recursive builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
builder.append(" "); // Should be `@` if it's a buffer-local mapping builder.append(" ");
builder.append(mappingInfo.isRecursive() ? " " : "*");
builder.append(" ");
builder.append(mappingInfo.getPresentableString()); builder.append(mappingInfo.getPresentableString());
builder.append("\n"); builder.append("\n");
} }
VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor)); VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
outputPanel.addText(builder.toString(), true); outputPanel.addText(builder.toString(), true);
outputPanel.show(); outputPanel.show();

View File

@ -12,7 +12,6 @@ import com.intellij.application.options.CodeStyle
import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorKind import com.intellij.openapi.editor.EditorKind
import com.intellij.openapi.editor.EditorSettings.LineNumerationType import com.intellij.openapi.editor.EditorSettings.LineNumerationType
import com.intellij.openapi.editor.ScrollPositionCalculator import com.intellij.openapi.editor.ScrollPositionCalculator
@ -20,6 +19,8 @@ import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.openapi.fileEditor.impl.LoadTextUtil import com.intellij.openapi.fileEditor.impl.LoadTextUtil
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@ -157,24 +158,25 @@ internal class OptionGroup : VimOptionGroupBase(), IjVimOptionGroup, InternalOpt
} }
companion object { companion object {
fun editorReleased(editor: Editor) { fun fileEditorManagerSelectionChangedCallback(event: FileEditorManagerEvent) {
// Vim always has at least one window; it's not possible to close it. Editing a new file will open a new buffer in // Vim only has one window, and it's not possible to close it. This means that editing a new file will always
// the current window, or it's possible to split the current buffer into a new window, or open a new buffer in a // reuse an existing window (opening a new window will always open from an existing window). More importantly,
// new window. This is important for us because when Vim opens a new window, the new window's local options are // this means that any newly edited file will always get up-to-date local-to-window options. A new window is based
// copied from the current window. // on the opening window (treated as split then edit, so copy local + per-window "global" window values, then
// In detail: splitting the current window gets a complete copy of local and per-window global option values. // apply the per-window "global" values) and an edit reapplies the per-window "global" values.
// Editing a new file will split the current window and then edit the new buffer in-place. // If we close all windows, and open a new one, we can only use the per-window "global" values from the fallback
// IntelliJ does not always have an open window. It would be weird to close the last editor tab, and then open // window, but this is only initialised when we first read `~/.ideavimrc` during startup. Vim would use the values
// the next tab with different options - the user would expect the editor to look like the last one did. // from the current window, so to simulate this, we should update the fallback window with the values from the
// Therefore, we have a dummy "fallback" window that captures the options of the last closed editor. When opening // window that was selected at the time that the last window was closed.
// an editor and there are no currently open editors, we use the fallback window to initialise the new window. // Unfortunately, we can't reliably know if a closing editor is the selected editor. Instead, we rely on selection
// This callback tracks when editors are closed, and if the last editor in a project is being closed, updates the // change events. If an editor is losing selection and there is no new selection, we can assume this means that
// fallback window's options. // the last editor has been closed, and use the closed editor to update the fallback window
val project = editor.project ?: return //
if (!injector.editorGroup.getEditorsRaw() // XXX: event.oldEditor will must probably return a disposed editor. So, it should be treated with care
.any { it.ij != editor && it.ij.project === project && it.ij.editorKind == EditorKind.MAIN_EDITOR } if (event.newEditor == null) {
) { (event.oldEditor as? TextEditor)?.editor?.let {
(VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, editor.vim) (VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, it.vim)
}
} }
} }
} }

View File

@ -14,6 +14,7 @@ import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt; import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
import com.maddyhome.idea.vim.register.Register; import com.maddyhome.idea.vim.register.Register;
import com.maddyhome.idea.vim.register.VimRegisterGroupBase; import com.maddyhome.idea.vim.register.VimRegisterGroupBase;

View File

@ -7,6 +7,7 @@
*/ */
package com.maddyhome.idea.vim.group package com.maddyhome.idea.vim.group
import com.intellij.codeWithMe.ClientId
import com.intellij.ide.bookmark.Bookmark import com.intellij.ide.bookmark.Bookmark
import com.intellij.ide.bookmark.BookmarkGroup import com.intellij.ide.bookmark.BookmarkGroup
import com.intellij.ide.bookmark.BookmarksListener import com.intellij.ide.bookmark.BookmarksListener

View File

@ -51,8 +51,6 @@ import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.isBlock import com.maddyhome.idea.vim.state.mode.isBlock
import com.maddyhome.idea.vim.state.mode.isChar import com.maddyhome.idea.vim.state.mode.isChar
import com.maddyhome.idea.vim.state.mode.isLine import com.maddyhome.idea.vim.state.mode.isLine
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.DataFlavor
@Service @Service
@ -87,16 +85,10 @@ internal class PutGroup : VimPutBase() {
val context = vimContext.context as DataContext val context = vimContext.context as DataContext
val carets: MutableMap<Caret, RangeMarker> = mutableMapOf() val carets: MutableMap<Caret, RangeMarker> = mutableMapOf()
if (injector.vimState.mode is Mode.INSERT) { if (injector.vimState.mode is Mode.INSERT) {
val nanoTime = System.nanoTime()
val undo = injector.undo val undo = injector.undo
when (undo) { val nanoTime = System.nanoTime()
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
is VimTimestampBasedUndoService -> {
vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) } vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
} }
}
}
EditorHelper.getOrderedCaretsList(editor).forEach { caret -> EditorHelper.getOrderedCaretsList(editor).forEach { caret ->
val startOffset = val startOffset =
prepareDocumentAndGetStartOffsets( prepareDocumentAndGetStartOffsets(

View File

@ -8,7 +8,6 @@
package com.maddyhome.idea.vim.group.visual package com.maddyhome.idea.vim.group.visual
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.trace import com.intellij.openapi.diagnostic.trace
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@ -16,8 +15,6 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.options import com.maddyhome.idea.vim.api.options
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.controlNonVimSelectionChange
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.predictMode
import com.maddyhome.idea.vim.helper.exitSelectMode import com.maddyhome.idea.vim.helper.exitSelectMode
import com.maddyhome.idea.vim.helper.exitVisualMode import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.hasVisualSelection import com.maddyhome.idea.vim.helper.hasVisualSelection
@ -66,15 +63,12 @@ internal object IdeaSelectionControl {
// - There was no selection and now it is // - There was no selection and now it is
// - There was a selection and now it doesn't exist // - There was a selection and now it doesn't exist
// - There was a selection and now it exists as well (transforming char selection to line selection, for example) // - There was a selection and now it exists as well (transforming char selection to line selection, for example)
val hasSelection = ApplicationManager.getApplication().runReadAction<Boolean> { if (initialMode?.hasVisualSelection == false && !editor.selectionModel.hasSelection(true)) {
editor.selectionModel.hasSelection(true)
}
if (initialMode?.hasVisualSelection == false && !hasSelection) {
logger.trace { "Exiting without selection adjusting" } logger.trace { "Exiting without selection adjusting" }
return@singleTask return@singleTask
} }
if (hasSelection) { if (editor.selectionModel.hasSelection(true)) {
if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) { if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) {
logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" } logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" }
return@singleTask return@singleTask

View File

@ -9,6 +9,8 @@
package com.maddyhome.idea.vim.group.visual package com.maddyhome.idea.vim.group.visual
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.mode
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.singleTask
import com.maddyhome.idea.vim.newapi.globalIjOptions import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import java.awt.event.ActionEvent import java.awt.event.ActionEvent

View File

@ -183,7 +183,6 @@ internal abstract class OctopusHandler(private val nextHandler: EditorActionHand
* - App code - set handler after * - App code - set handler after
* - Template - doesn't intersect with enter anymore * - Template - doesn't intersect with enter anymore
* - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode * - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
* - inline.completion.enter - set handler before. Otherwise, AI completion is not invoked on enter.
* *
* This rule is disabled due to VIM-3124 * This rule is disabled due to VIM-3124
* - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122 * - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122

View File

@ -157,19 +157,6 @@ public class EditorHelper {
return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor)); return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
} }
/**
* Gets the number of characters that can be fit inside the output panel for an editor.
* <p>
* This will be greater than the approximate screen width as it also includes any gutter components in the editor.
* </p>
*
* @param editor The editor
* @return The approximate number of columns that can fit in the output panel
*/
public static int getApproximateOutputPanelWidth(final @NotNull Editor editor) {
return (int)(editor.getComponent().getWidth() / getPlainSpaceWidthFloat(editor));
}
/** /**
* Gets the width of the space character in the editor's plain font as a float. * Gets the width of the space character in the editor's plain font as a float.
* <p> * <p>
@ -286,7 +273,7 @@ public class EditorHelper {
// Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current // Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current
// virtual space at the bottom of the screen // virtual space at the bottom of the screen
final @NotNull VimEditor editor1 = new IjVimEditor(editor); @NotNull final VimEditor editor1 = new IjVimEditor(editor);
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y); final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y);
scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset)); scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset));
@ -338,7 +325,7 @@ public class EditorHelper {
final int lineHeight = editor.getLineHeight(); final int lineHeight = editor.getLineHeight();
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight); final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
final @NotNull VimEditor editor1 = new IjVimEditor(editor); @NotNull final VimEditor editor1 = new IjVimEditor(editor);
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount(); final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine); final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
@ -392,7 +379,7 @@ public class EditorHelper {
return 0; return 0;
} }
private static int getHorizontalScrollbarHeight(final @NotNull Editor editor) { private static int getHorizontalScrollbarHeight(@NotNull final Editor editor) {
// Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured // Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured
// text, or always visible, opaque and outside the content area, so we don't need to adjust for them // text, or always visible, opaque and outside the content area, so we don't need to adjust for them
// Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That // Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That
@ -475,7 +462,7 @@ public class EditorHelper {
*/ */
public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) { public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) {
final Rectangle visibleArea = getVisibleArea(editor); final Rectangle visibleArea = getVisibleArea(editor);
final @NotNull VimEditor editor2 = new IjVimEditor(editor); @NotNull final VimEditor editor2 = new IjVimEditor(editor);
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1; final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1;
int y = visibleArea.y + visibleArea.height; int y = visibleArea.y + visibleArea.height;
@ -493,7 +480,7 @@ public class EditorHelper {
caretVisualLine = lastVisualLine; caretVisualLine = lastVisualLine;
} }
else { else {
final @NotNull VimEditor editor1 = new IjVimEditor(editor); @NotNull final VimEditor editor1 = new IjVimEditor(editor);
caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
completed = false; completed = false;
} }
@ -528,7 +515,7 @@ public class EditorHelper {
public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) { public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) {
final Rectangle visibleArea = getVisibleArea(editor); final Rectangle visibleArea = getVisibleArea(editor);
final int lineHeight = editor.getLineHeight(); final int lineHeight = editor.getLineHeight();
final @NotNull VimEditor editor1 = new IjVimEditor(editor); @NotNull final VimEditor editor1 = new IjVimEditor(editor);
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
int y = visibleArea.y; int y = visibleArea.y;

View File

@ -75,7 +75,7 @@ internal class IjActionExecutor : VimActionExecutor {
val applicationEx = ApplicationManagerEx.getApplicationEx() val applicationEx = ApplicationManagerEx.getApplicationEx()
if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) { if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
// This is needed for VIM-3376 and it should turn into error at soeme moment // This is needed for VIM-3376 and it should turn into error at soeme moment
thisLogger().warn("Actions cannot be updated when write-action is running or pending") thisLogger().warn(RuntimeException("Actions cannot be updated when write-action is running or pending", ))
} }
val ijAction = (action as IjNativeAction).action val ijAction = (action as IjNativeAction).action

View File

@ -13,6 +13,7 @@ import com.intellij.openapi.editor.ReadOnlyFragmentModificationException
import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.VisualPosition
import com.intellij.openapi.editor.actionSystem.EditorActionManager import com.intellij.openapi.editor.actionSystem.EditorActionManager
import com.intellij.openapi.editor.ex.util.EditorUtil import com.intellij.openapi.editor.ex.util.EditorUtil
import com.maddyhome.idea.vim.api.EngineEditorHelper
import com.maddyhome.idea.vim.api.EngineEditorHelperBase import com.maddyhome.idea.vim.api.EngineEditorHelperBase
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimRangeMarker import com.maddyhome.idea.vim.api.VimRangeMarker
@ -41,10 +42,6 @@ internal class IjEditorHelper : EngineEditorHelperBase() {
return EditorHelper.getApproximateScreenWidth(editor.ij) return EditorHelper.getApproximateScreenWidth(editor.ij)
} }
override fun getApproximateOutputPanelWidth(editor: VimEditor): Int {
return EditorHelper.getApproximateOutputPanelWidth(editor.ij)
}
override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) { override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) {
return EditorActionManager.getInstance() return EditorActionManager.getInstance()
.getReadonlyFragmentModificationHandler(editor.ij.document) .getReadonlyFragmentModificationHandler(editor.ij.document)

View File

@ -29,6 +29,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.VimStateMachine
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt

View File

@ -102,8 +102,7 @@ private fun updateSearchHighlights(
// Update highlights in all visible editors. We update non-visible editors when they get focus. // Update highlights in all visible editors. We update non-visible editors when they get focus.
// Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles // Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles
val editors = injector.editorGroup.getEditors().filter { val editors = injector.editorGroup.getEditors().filter {
(injector.application.isUnitTest() || it.ij.component.isShowing) injector.application.isUnitTest() || it.ij.component.isShowing
&& (currentEditor == null || it.projectId == currentEditor.projectId)
} }
editors.forEach { editors.forEach {

View File

@ -14,9 +14,7 @@ import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.command.undo.UndoManager import com.intellij.openapi.command.undo.UndoManager
import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.TextEditor import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.openapi.fileEditor.TextEditorWithPreview
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.util.registry.Registry
@ -32,13 +30,13 @@ import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.inVisualMode import com.maddyhome.idea.vim.state.mode.inVisualMode
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService import com.maddyhome.idea.vim.undo.UndoRedoBase
/** /**
* @author oleg * @author oleg
*/ */
@Service @Service
internal class UndoRedoHelper : VimTimestampBasedUndoService { internal class UndoRedoHelper : UndoRedoBase() {
companion object { companion object {
private val logger = logger<UndoRedoHelper>() private val logger = logger<UndoRedoHelper>()
} }
@ -46,13 +44,13 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
override fun undo(editor: VimEditor, context: ExecutionContext): Boolean { override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
val ijContext = context.context as DataContext val ijContext = context.context as DataContext
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
val textEditor = getTextEditor(editor.ij) val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
if (undoManager.isUndoAvailable(textEditor)) { if (undoManager.isUndoAvailable(fileEditor)) {
val scrollingModel = editor.getScrollingModel() val scrollingModel = editor.getScrollingModel()
scrollingModel.accumulateViewportChanges() scrollingModel.accumulateViewportChanges()
performUndo(editor, undoManager, textEditor) performUndo(editor, undoManager, fileEditor)
scrollingModel.flushViewportChanges() scrollingModel.flushViewportChanges()
@ -61,15 +59,6 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
return false return false
} }
private fun getTextEditor(editor: Editor): TextEditor {
// If the Editor is hosted in a TextEditor with a preview, then TextEditorProvider will return a TextEditor for the
// hosted instance, not for the main editor that also contains the preview. If we pass the inner TextEditor to the
// UndoManager, it doesn't correctly restore state. Specifically, the change is undone/redone, but the caret is not
// moved. See VIM-3671.
val currentTextEditor = TextEditorProvider.getInstance().getTextEditor(editor)
return TextEditorWithPreview.getParentSplitEditor(currentTextEditor) as? TextEditor ?: currentTextEditor
}
private fun performUndo( private fun performUndo(
editor: VimEditor, editor: VimEditor,
undoManager: UndoManager, undoManager: UndoManager,
@ -117,10 +106,10 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
override fun redo(editor: VimEditor, context: ExecutionContext): Boolean { override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
val ijContext = context.context as DataContext val ijContext = context.context as DataContext
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
val textEditor = getTextEditor(editor.ij) val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
val undoManager = UndoManager.getInstance(project) val undoManager = UndoManager.getInstance(project)
if (undoManager.isRedoAvailable(textEditor)) { if (undoManager.isRedoAvailable(fileEditor)) {
performRedo(undoManager, textEditor, editor) performRedo(undoManager, fileEditor, editor)
return true return true
} }

View File

@ -21,11 +21,12 @@ import com.intellij.openapi.util.UserDataHolder
import com.maddyhome.idea.vim.api.LocalMarkStorage import com.maddyhome.idea.vim.api.LocalMarkStorage
import com.maddyhome.idea.vim.api.SelectionInfo import com.maddyhome.idea.vim.api.SelectionInfo
import com.maddyhome.idea.vim.common.InsertSequence import com.maddyhome.idea.vim.common.InsertSequence
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.visual.VisualChange import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.VimStateMachine
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.ui.ExOutputPanel import com.maddyhome.idea.vim.ui.ExOutputPanel

View File

@ -0,0 +1,15 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.key
import com.maddyhome.idea.vim.api.injector
internal fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder)
}

View File

@ -16,6 +16,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.trace import com.intellij.openapi.diagnostic.trace
import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.editor.EditorKind import com.intellij.openapi.editor.EditorKind
import com.intellij.openapi.editor.actionSystem.TypedAction import com.intellij.openapi.editor.actionSystem.TypedAction
import com.intellij.openapi.editor.event.CaretEvent import com.intellij.openapi.editor.event.CaretEvent
@ -31,10 +32,10 @@ import com.intellij.openapi.editor.event.EditorMouseMotionListener
import com.intellij.openapi.editor.event.SelectionEvent import com.intellij.openapi.editor.event.SelectionEvent
import com.intellij.openapi.editor.event.SelectionListener import com.intellij.openapi.editor.event.SelectionListener
import com.intellij.openapi.editor.ex.DocumentEx import com.intellij.openapi.editor.ex.DocumentEx
import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
import com.intellij.openapi.editor.ex.FocusChangeListener import com.intellij.openapi.editor.ex.FocusChangeListener
import com.intellij.openapi.editor.impl.EditorComponentImpl import com.intellij.openapi.editor.impl.EditorComponentImpl
import com.intellij.openapi.fileEditor.FileEditor import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.fileEditor.FileEditorManagerListener
@ -44,15 +45,15 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
import com.intellij.openapi.fileEditor.impl.EditorComposite import com.intellij.openapi.fileEditor.impl.EditorComposite
import com.intellij.openapi.fileEditor.impl.EditorWindow import com.intellij.openapi.fileEditor.impl.EditorWindow
import com.intellij.openapi.observable.util.addKeyListener
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.rd.createLifetime
import com.intellij.openapi.rd.createNestedDisposable
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.removeUserData import com.intellij.openapi.util.removeUserData
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.ExceptionUtil import com.intellij.util.ExceptionUtil
import com.intellij.util.SlowOperations import com.jetbrains.rd.util.lifetime.Lifetime
import com.maddyhome.idea.vim.EventFacade import com.maddyhome.idea.vim.EventFacade
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimKeyListener import com.maddyhome.idea.vim.VimKeyListener
@ -105,11 +106,8 @@ import com.maddyhome.idea.vim.ui.widgets.macro.MacroWidgetListener
import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
import org.jetbrains.annotations.TestOnly
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import java.lang.ref.WeakReference
import java.util.*
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
/** /**
@ -131,15 +129,23 @@ import javax.swing.SwingUtilities
* Make sure the selected editor isn't the new editor, which can happen if there are no other editors open. * Make sure the selected editor isn't the new editor, which can happen if there are no other editors open.
*/ */
private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project -> private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project ->
// We can't rely on FileEditorManager.selectedTextEditor because we're trying to retrieve the selected text editor // Some TextEditor implementations create a dummy Editor instance on demand, e.g., while downloading a file to edit
// while creating a text editor that is about to become the selected text editor. // (see BaseRemoteFileEditor). This can cause recursion if the newly opened/created TextEditor is also the currently
// This worked fine for 2024.2, but internal changes for 2024.3 broke things. It appears that the currently selected // selected TextEditor, because we will be notified of the new dummy Editor before it has finished initialisation, and
// text editor is reset to null while the soon-to-be-selected text editor is being created. We therefore track the // try to get its opening editor, causing a new dummy Editor to be created and notifications sent, and so on.
// last selected editor manually. // This was reported for 232 and 233 (see VIM-3066), but I can't recreate in 241. The callstack looks different, now
// Note that if we ever switch back to FileEditorManager.selectedTextEditor, be careful of recursion, because the // using coroutines, so it's possible the deadlock has been broken. However, it's sensible to leave the recursion
// actual editor might be created on-demand, which would notify our initialisation method, which would call us... // guard in.
VimListenerManager.VimLastSelectedEditorTracker.getLastSelectedEditor(project)?.takeUnless { it == newEditor } if (openingEditorRecursionGuard) return null
openingEditorRecursionGuard = true
try {
FileEditorManager.getInstance(project).selectedTextEditor?.takeUnless { it == newEditor }
}
finally {
openingEditorRecursionGuard = false
}
} }
private var openingEditorRecursionGuard = false
internal object VimListenerManager { internal object VimListenerManager {
@ -149,9 +155,7 @@ internal object VimListenerManager {
fun turnOn() { fun turnOn() {
GlobalListeners.enable() GlobalListeners.enable()
SlowOperations.knownIssue("VIM-3648, VIM-3649").use {
EditorListeners.addAll() EditorListeners.addAll()
}
check(correctorRequester.tryEmit(Unit)) check(correctorRequester.tryEmit(Unit))
check(keyCheckRequests.tryEmit(Unit)) check(keyCheckRequests.tryEmit(Unit))
@ -212,6 +216,16 @@ internal object VimListenerManager {
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable) EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable) val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable)
busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener) busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener)
// Listen for focus change to update various features such as mode widget
val eventMulticaster = EditorFactory.getInstance().eventMulticaster
(eventMulticaster as? EditorEventMulticasterEx)?.addFocusChangeListener(
VimFocusListener,
VimPlugin.getInstance().onOffDisposable
)
// Listen for document changes to update document state such as marks
eventMulticaster.addDocumentListener(VimDocumentListener, VimPlugin.getInstance().onOffDisposable)
} }
fun disable() { fun disable() {
@ -273,52 +287,45 @@ internal object VimListenerManager {
// TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised // TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
if (vimDisabled(editor)) return if (vimDisabled(editor)) return
val pluginLifetime = VimPlugin.getInstance().createLifetime()
val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
val disposable =
Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
// Protect against double initialisation // Protect against double initialisation
if (editor.getUserData(editorListenersDisposableKey) != null) { if (editor.getUserData(editorListenersDisposableKey) != null) {
return return
} }
// Make sure we explicitly dispose this per-editor disposable! val listenersDisposable = Disposer.newDisposable(disposable)
// Because the listeners are registered with a parent disposable, they add child disposables that have to call a editor.putUserData(editorListenersDisposableKey, listenersDisposable)
// method on the editor to remove the listener. This means the disposable contains a reference to the editor (even
// if the listener handler is a singleton that doesn't hold a reference).
// Unless the per-editor disposable is disposed, all of these disposables sit in the disposer tree until the
// parent disposable is disposed, which will mean we leak editor instances.
// The per-editor disposable is explicitly disposed when the editor is released, and disposed via its parent when
// the plugin's on/off functionality is toggled, and so also when the plugin is disabled/unloaded by the platform.
// It doesn't matter if we explicitly remove all listeners before disposing onOffDisposable, as that will remove
// the per-editor disposable from the disposer tree.
val perEditorDisposable = Disposer.newDisposable(VimPlugin.getInstance().onOffDisposable)
editor.putUserData(editorListenersDisposableKey, perEditorDisposable)
Disposer.register(perEditorDisposable) { Disposer.register(listenersDisposable) {
if (VimListenerTestObject.enabled) { if (VimListenerTestObject.enabled) {
VimListenerTestObject.disposedCounter += 1 VimListenerTestObject.disposedCounter += 1
} }
} }
// This listener and several below add a reference to the editor to the disposer tree editor.contentComponent.addKeyListener(VimKeyListener)
editor.contentComponent.addKeyListener(perEditorDisposable, VimKeyListener) Disposer.register(listenersDisposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
// Initialise the local options. We MUST do this before anything has the chance to query options // Initialise the local options. We MUST do this before anything has the chance to query options
val vimEditor = editor.vim val vimEditor = editor.vim
VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario) VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario)
val eventFacade = EventFacade.getInstance() val eventFacade = EventFacade.getInstance()
eventFacade.addEditorMouseListener(editor, EditorMouseHandler, perEditorDisposable) eventFacade.addEditorMouseListener(editor, EditorMouseHandler, listenersDisposable)
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, perEditorDisposable) eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, listenersDisposable)
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, perEditorDisposable) eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, listenersDisposable)
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, perEditorDisposable) eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, listenersDisposable)
eventFacade.addCaretListener(editor, EditorCaretHandler, perEditorDisposable) eventFacade.addCaretListener(editor, EditorCaretHandler, listenersDisposable)
VimPlugin.getEditor().editorCreated(editor) VimPlugin.getEditor().editorCreated(editor)
VimPlugin.getChange().editorCreated(editor, perEditorDisposable) VimPlugin.getChange().editorCreated(editor, listenersDisposable)
(editor as EditorEx).addFocusListener(VimFocusListener, perEditorDisposable)
injector.listenersNotifier.notifyEditorCreated(vimEditor) injector.listenersNotifier.notifyEditorCreated(vimEditor)
Disposer.register(perEditorDisposable) { Disposer.register(listenersDisposable) {
VimPlugin.getEditor().editorDeinit(editor) VimPlugin.getEditor().editorDeinit(editor)
} }
} }
@ -356,7 +363,7 @@ internal object VimListenerManager {
* open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest * open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest
* edits a file. Updating search highlights will be a no-op if there are no open local editors) * edits a file. Updating search highlights will be a no-op if there are no open local editors)
*/ */
class VimDocumentListener : DocumentListener { private object VimDocumentListener : DocumentListener {
override fun beforeDocumentChange(event: DocumentEvent) { override fun beforeDocumentChange(event: DocumentEvent) {
VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event) VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event)
IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event) IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event)
@ -370,26 +377,6 @@ internal object VimListenerManager {
} }
} }
internal object VimLastSelectedEditorTracker {
// This stores a weak reference to an editor against a weak reference to a project, which means there is nothing
// keeping the project or editor from being garbage collected at any time. Stale keys are automatically expunged
// whenever the map is used.
private val selectedEditors = WeakHashMap<Project, WeakReference<Editor>>()
fun getLastSelectedEditor(project: Project): Editor? = selectedEditors[project]?.get()
internal fun setLastSelectedEditor(fileEditor: FileEditor?) {
(fileEditor as? TextEditor)?.editor?.let { editor ->
editor.project?.let { project -> selectedEditors[project] = WeakReference(editor) }
}
}
@TestOnly
internal fun resetLastSelectedEditor(project: Project) {
selectedEditors.remove(project)
}
}
/** /**
* Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the * Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the
* last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me * last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me
@ -414,8 +401,8 @@ internal object VimListenerManager {
MotionGroup.fileEditorManagerSelectionChangedCallback(event) MotionGroup.fileEditorManagerSelectionChangedCallback(event)
FileGroup.fileEditorManagerSelectionChangedCallback(event) FileGroup.fileEditorManagerSelectionChangedCallback(event)
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event) VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
OptionGroup.fileEditorManagerSelectionChangedCallback(event)
IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event) IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor)
} }
} }
@ -487,21 +474,8 @@ internal object VimListenerManager {
override fun editorReleased(event: EditorFactoryEvent) { override fun editorReleased(event: EditorFactoryEvent) {
if (vimDisabled(event.editor)) return if (vimDisabled(event.editor)) return
val vimEditor = event.editor.vim val vimEditor = event.editor.vim
EditorListeners.remove(event.editor)
injector.listenersNotifier.notifyEditorReleased(vimEditor) injector.listenersNotifier.notifyEditorReleased(vimEditor)
injector.markService.editorReleased(vimEditor) injector.markService.editorReleased(vimEditor)
// This ticket will have a different stack trace, but it's the same problem. Originally, we tracked the last
// editor closing based on file selection (closing an editor would select the next editor - so a null selection
// was taken to mean that there were no more editors to select). This assumption broke in 242, so it's changed to
// check when the editor is released.
// However, the actions taken when the last editor closes can still be expensive/slow because we copy options, and
// some options are backed by PSI options. E.g. 'textwidth' is mapped to
// CodeStyle.getSettings(ijEditor).isWrapOnTyping(language)), and getting the document's PSI language is a slow
// operation. This underlying issue still needs to be addressed, even though the method has moved
SlowOperations.knownIssue("VIM-3658").use {
OptionGroup.editorReleased(event.editor)
}
} }
override fun fileOpenedSync( override fun fileOpenedSync(
@ -789,10 +763,6 @@ internal object VimListenerManager {
// https://youtrack.jetbrains.com/issue/IDEA-277716 // https://youtrack.jetbrains.com/issue/IDEA-277716
// https://youtrack.jetbrains.com/issue/VIM-2368 // https://youtrack.jetbrains.com/issue/VIM-2368
if (event.mouseEvent.clickCount == 1 && !SwingUtilities.isRightMouseButton(event.mouseEvent)) { if (event.mouseEvent.clickCount == 1 && !SwingUtilities.isRightMouseButton(event.mouseEvent)) {
val hasSelection = ApplicationManager.getApplication().runReadAction<Boolean> {
editor.selectionModel.hasSelection(true)
}
if (!hasSelection) {
if (editor.inVisualMode) { if (editor.inVisualMode) {
editor.vim.exitVisualMode() editor.vim.exitVisualMode()
} else if (editor.vim.inSelectMode) { } else if (editor.vim.inSelectMode) {
@ -800,7 +770,6 @@ internal object VimListenerManager {
KeyHandler.getInstance().reset(editor.vim) KeyHandler.getInstance().reset(editor.vim)
} }
} }
}
} else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA && } else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA &&
event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA && event.area != EditorMouseEventArea.FOLDING_OUTLINE_AREA &&
event.mouseEvent.button != MouseEvent.BUTTON3 event.mouseEvent.button != MouseEvent.BUTTON3

View File

@ -22,13 +22,10 @@ import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.IndexNotReadyException import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.util.ui.EmptyClipboardOwner import com.intellij.util.ui.EmptyClipboardOwner
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimClipboardManager import com.maddyhome.idea.vim.api.VimClipboardManager
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.getText
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.common.VimCopiedText
import com.maddyhome.idea.vim.diagnostic.debug import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
import java.awt.HeadlessException import java.awt.HeadlessException
@ -40,52 +37,18 @@ import java.io.IOException
@Service @Service
internal class IjClipboardManager : VimClipboardManager { internal class IjClipboardManager : VimClipboardManager {
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getPrimaryTextAndTransferableData")
override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? { override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? {
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null
val contents = clipboard.getContents(null) ?: return null val contents = clipboard.getContents(null) ?: return null
return getTextAndTransferableData(contents) return getTextAndTransferableData(contents)
} }
override fun getPrimaryContent(editor: VimEditor, context: ExecutionContext): IjVimCopiedText? {
val (text, transferableData) = getPrimaryTextAndTransferableData() ?: return null
return IjVimCopiedText(text, transferableData ?: emptyList())
}
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getClipboardTextAndTransferableData")
override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? { override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? {
val contents = getContents() ?: return null val contents = getContents() ?: return null
return getTextAndTransferableData(contents) return getTextAndTransferableData(contents)
} }
override fun getClipboardContent(editor: VimEditor, context: ExecutionContext): VimCopiedText? { private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<Any>?>? {
val (text, transferableData) = getClipboardTextAndTransferableData() ?: return null
return IjVimCopiedText(text, transferableData ?: emptyList())
}
override fun setClipboardContent(editor: VimEditor, context: ExecutionContext, textData: VimCopiedText): Boolean {
require(textData is IjVimCopiedText)
return handleTextSetting(textData.text, textData.text, textData.transferableData) { content -> setContents(content) } != null
}
// TODO prefer methods with ranges, because they collect and preprocess for us
// override fun createClipboardEntry(
// editor: VimEditor,
// context: ExecutionContext,
// text: String,
// range: TextRange,
// ): ClipboardEntry {
// val transferableData = getTransferableData(editor, range, text)
// val preprocessedText = preprocessText(editor, range, text, transferableData)
// return IJClipboardEntry(preprocessedText, text, transferableData)
// }
// override fun setClipboardText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
// require(entry is IJClipboardEntry)
// return setClipboardText(entry.text, entry.rawText, entry.transferableData) != null
// }
private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<TextBlockTransferableData>?>? {
var res: String? = null var res: String? = null
var transferableData: List<TextBlockTransferableData> = ArrayList() var transferableData: List<TextBlockTransferableData> = ArrayList()
try { try {
@ -100,29 +63,10 @@ internal class IjClipboardManager : VimClipboardManager {
return Pair(res, transferableData) return Pair(res, transferableData)
} }
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setClipboardText")
override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? { override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) } return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) }
} }
override fun setPrimaryContent(
editor: VimEditor,
context: ExecutionContext,
textData: VimCopiedText,
): Boolean {
require(textData is IjVimCopiedText)
return handleTextSetting(textData.text, textData.text, textData.transferableData) { content ->
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
clipboard.setContents(content, EmptyClipboardOwner.INSTANCE)
} != null
}
// override fun setPrimaryText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
// require(entry is IJClipboardEntry)
// return setPrimaryText(entry.text, entry.rawText, entry.transferableData) != null
// }
@Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setPrimaryText")
override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? { override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
return handleTextSetting(text, rawText, transferableData) { content -> return handleTextSetting(text, rawText, transferableData) { content ->
val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
@ -130,16 +74,6 @@ internal class IjClipboardManager : VimClipboardManager {
} }
} }
override fun collectCopiedText(editor: VimEditor, context: ExecutionContext, range: TextRange, text: String): VimCopiedText {
val transferableData = getTransferableData(editor, range)
val preprocessedText = preprocessText(editor, range, text, transferableData)
return IjVimCopiedText(preprocessedText, transferableData)
}
override fun dumbCopiedText(text: String): VimCopiedText {
return IjVimCopiedText(text, emptyList())
}
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? { private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? {
val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList() val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList()
@ -158,7 +92,7 @@ internal class IjClipboardManager : VimClipboardManager {
return null return null
} }
override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange): List<TextBlockTransferableData> { override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange, text: String): List<Any> {
val editor = (vimEditor as IjVimEditor).editor val editor = (vimEditor as IjVimEditor).editor
val transferableData: MutableList<TextBlockTransferableData> = ArrayList() val transferableData: MutableList<TextBlockTransferableData> = ArrayList()
val project = editor.project ?: return emptyList() val project = editor.project ?: return emptyList()
@ -183,7 +117,7 @@ internal class IjClipboardManager : VimClipboardManager {
} }
} }
} }
transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(textRange.endOffset - textRange.startOffset))) transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(text.length)))
// These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with // These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with
// IdeaVim and I don't see a way to fix it // IdeaVim and I don't see a way to fix it
@ -241,7 +175,3 @@ internal class IjClipboardManager : VimClipboardManager {
val logger = vimLogger<IjClipboardManager>() val logger = vimLogger<IjClipboardManager>()
} }
} }
data class IjVimCopiedText(override val text: String, val transferableData: List<Any>): VimCopiedText {
override fun updateText(newText: String): VimCopiedText = IjVimCopiedText(newText, transferableData)
}

View File

@ -19,7 +19,6 @@ import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimCaretBase import com.maddyhome.idea.vim.api.VimCaretBase
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimVisualPosition import com.maddyhome.idea.vim.api.VimVisualPosition
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.InsertSequence import com.maddyhome.idea.vim.common.InsertSequence
import com.maddyhome.idea.vim.common.LiveRange import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.group.visual.VisualChange import com.maddyhome.idea.vim.group.visual.VisualChange
@ -35,14 +34,10 @@ import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
import com.maddyhome.idea.vim.helper.vimLine import com.maddyhome.idea.vim.helper.vimLine
import com.maddyhome.idea.vim.helper.vimSelectionStart import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.helper.vimSelectionStartClear import com.maddyhome.idea.vim.helper.vimSelectionStartClear
import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
internal class IjVimCaret(val caret: Caret) : VimCaretBase() { internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
override val registerStorage: VimRegisterGroup
get() = injector.registerGroup
override val markStorage: LocalMarkStorage override val markStorage: LocalMarkStorage
get() { get() {
var storage = this.caret.markStorage var storage = this.caret.markStorage

View File

@ -60,8 +60,6 @@ import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.inBlockSelection import com.maddyhome.idea.vim.state.mode.inBlockSelection
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import java.lang.System.identityHashCode import java.lang.System.identityHashCode
@ -142,13 +140,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) { override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
if (injector.vimState.mode is Mode.INSERT) { if (injector.vimState.mode is Mode.INSERT) {
val undo = injector.undo injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
when (undo) {
is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
is VimTimestampBasedUndoService -> {
undo.startInsertSequence(caret, atPosition, System.nanoTime())
}
}
} }
editor.document.insertString(atPosition, text) editor.document.insertString(atPosition, text)
} }
@ -557,7 +549,7 @@ internal class InsertTimeRecorder: ModeChangeListener {
override fun modeChanged(editor: VimEditor, oldMode: Mode) { override fun modeChanged(editor: VimEditor, oldMode: Mode) {
editor as IjVimEditor editor as IjVimEditor
if (oldMode == Mode.INSERT) { if (oldMode == Mode.INSERT) {
val undo = injector.undo as? VimTimestampBasedUndoService ?: return val undo = injector.undo
val nanoTime = System.nanoTime() val nanoTime = System.nanoTime()
editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) } editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
} }

View File

@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.api.VimApplication
import com.maddyhome.idea.vim.api.VimChangeGroup import com.maddyhome.idea.vim.api.VimChangeGroup
import com.maddyhome.idea.vim.api.VimClipboardManager import com.maddyhome.idea.vim.api.VimClipboardManager
import com.maddyhome.idea.vim.api.VimCommandGroup import com.maddyhome.idea.vim.api.VimCommandGroup
import com.maddyhome.idea.vim.api.VimCommandLine
import com.maddyhome.idea.vim.api.VimCommandLineService import com.maddyhome.idea.vim.api.VimCommandLineService
import com.maddyhome.idea.vim.api.VimDigraphGroup import com.maddyhome.idea.vim.api.VimDigraphGroup
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor

View File

@ -18,8 +18,11 @@ import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.editor.event.DocumentListener import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.editor.markup.RangeHighlighter import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.util.Ref
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.Options import com.maddyhome.idea.vim.api.Options
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimSearchGroupBase import com.maddyhome.idea.vim.api.VimSearchGroupBase
import com.maddyhome.idea.vim.api.globalOptions import com.maddyhome.idea.vim.api.globalOptions
@ -27,16 +30,21 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Direction import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.common.Direction.Companion.fromInt import com.maddyhome.idea.vim.common.Direction.Companion.fromInt
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.TestInputModel.Companion.getInstance
import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight
import com.maddyhome.idea.vim.helper.highlightSearchResults import com.maddyhome.idea.vim.helper.highlightSearchResults
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
import com.maddyhome.idea.vim.helper.shouldIgnoreCase import com.maddyhome.idea.vim.helper.shouldIgnoreCase
import com.maddyhome.idea.vim.helper.updateSearchHighlights import com.maddyhome.idea.vim.helper.updateSearchHighlights
import com.maddyhome.idea.vim.helper.vimLastHighlighters import com.maddyhome.idea.vim.helper.vimLastHighlighters
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
import com.maddyhome.idea.vim.ui.ModalEntry
import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler
import org.jdom.Element import org.jdom.Element
import org.jetbrains.annotations.Contract import org.jetbrains.annotations.Contract
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import javax.swing.KeyStroke
@State( @State(
name = "VimSearchSettings", name = "VimSearchSettings",
@ -44,7 +52,7 @@ import org.jetbrains.annotations.TestOnly
) )
open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> { open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> {
companion object { companion object {
private val logger by lazy { vimLogger<IjVimSearchGroup>() } private val logger = vimLogger<IjVimSearchGroup>()
} }
init { init {
@ -104,25 +112,27 @@ open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Ele
return IjSearchHighlight(ijEditor, highlighter) return IjSearchHighlight(ijEditor, highlighter)
} }
override fun setLatestMatch(match: String) {
SubmatchFunctionHandler.getInstance().latestMatch = match
}
override fun replaceString(
editor: VimEditor,
startOffset: Int,
endOffset: Int,
newString: String,
) {
ApplicationManager.getApplication().runWriteAction {
(editor as IjVimEditor).editor.document.replaceString(startOffset, endOffset, newString)
}
}
@TestOnly @TestOnly
override fun resetState() { override fun resetState() {
super.resetState() super.resetState()
showSearchHighlight = injector.globalOptions().hlsearch showSearchHighlight = injector.globalOptions().hlsearch
} }
override fun isSomeTextHighlighted(): Boolean {
val vimEditors = injector.editorGroup.getEditors().filter {
(injector.application.isUnitTest() || it.ij.component.isShowing)
}
for (vimEditor in vimEditors) {
val editor = vimEditor.ij
if (editor.vimLastHighlighters != null) {
return true
}
}
return false
}
override fun setShouldShowSearchHighlights() { override fun setShouldShowSearchHighlights() {
showSearchHighlight = injector.globalOptions().hlsearch showSearchHighlight = injector.globalOptions().hlsearch
} }

View File

@ -32,9 +32,9 @@ internal class Troubleshooter {
fun findIncorrectMappings(): List<Problem> { fun findIncorrectMappings(): List<Problem> {
val problems = ArrayList<Problem>() val problems = ArrayList<Problem>()
MappingMode.entries.forEach { mode -> MappingMode.entries.forEach { mode ->
injector.keyGroup.getKeyMapping(mode).getAllByOwner(MappingOwner.IdeaVim.InitScript).forEach { entry -> injector.keyGroup.getKeyMapping(mode).getByOwner(MappingOwner.IdeaVim.InitScript).forEach { (_, to) ->
(entry.mappingInfo as? ToKeysMappingInfo)?.let { mappingInfo -> if (to is ToKeysMappingInfo) {
if (":action" in mappingInfo.toKeys.joinToString { it.keyChar.toString() }) { if (":action" in to.toKeys.joinToString { it.keyChar.toString() }) {
problems += Problem("Mappings contain `:action` call") problems += Problem("Mappings contain `:action` call")
} }
} }

View File

@ -7,6 +7,7 @@
*/ */
package com.maddyhome.idea.vim.ui.ex package com.maddyhome.idea.vim.ui.ex
import com.intellij.openapi.diagnostic.logger
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim

View File

@ -11,7 +11,6 @@ package com.maddyhome.idea.vim.ui.widgets.mode.listeners
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.RecursionManager
import com.intellij.openapi.wm.WindowManager import com.intellij.openapi.wm.WindowManager
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.common.EditorListener import com.maddyhome.idea.vim.common.EditorListener
@ -74,14 +73,7 @@ internal class ModeWidgetListener: ModeChangeListener, EditorListener, VimWidget
private fun getFocusedEditorForProject(editorProject: Project?): Editor? { private fun getFocusedEditorForProject(editorProject: Project?): Editor? {
if (editorProject == null) return null if (editorProject == null) return null
return recursionGuard.doPreventingRecursion(recursionKey, false) {
val fileEditorManager = FileEditorManager.getInstance(editorProject) val fileEditorManager = FileEditorManager.getInstance(editorProject)
fileEditorManager.selectedTextEditor return fileEditorManager.selectedTextEditor
}
}
companion object {
private val recursionGuard = RecursionManager.createGuard<Any>("IdeaVim.modeWidgetListener")
private val recursionKey = Any()
} }
} }

View File

@ -15,8 +15,10 @@ import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.ex.ranges.Range import com.maddyhome.idea.vim.ex.ranges.Range
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import java.util.* import java.util.*
@ -24,9 +26,7 @@ import java.util.*
* @author smartbomb * @author smartbomb
*/ */
@ExCommand(command = "actionl[ist]") @ExCommand(command = "actionl[ist]")
internal data class ActionListCommand(val range: Range, val modifier: CommandModifier, val argument: String) : internal data class ActionListCommand(val range: Range, val argument: String) : Command.SingleExecution(range) {
Command.SingleExecution(range, modifier) {
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, operatorArguments: OperatorArguments): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {

View File

@ -27,14 +27,13 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
* @author John Weigel * @author John Weigel
*/ */
@ExCommand(command = "b[uffer]") @ExCommand(command = "b[uffer]")
internal data class BufferCommand(val range: Range, val modifier: CommandModifier, val argument: String) : internal data class BufferCommand(val range: Range, val argument: String) : Command.SingleExecution(range) {
Command.SingleExecution(range, modifier) {
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, operatorArguments: OperatorArguments): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
val overrideModified = modifier == CommandModifier.BANG val arg = argument.trim()
val buffer = argument.trim() val overrideModified = arg.startsWith('!')
val buffer = if (overrideModified) arg.replace(Regex("^!\\s*"), "") else arg
var result = true var result = true
if (buffer.isNotEmpty()) { if (buffer.isNotEmpty()) {

View File

@ -32,9 +32,7 @@ import org.jetbrains.annotations.NonNls
* @author John Weigel * @author John Weigel
*/ */
@ExCommand(command = "ls,files,buffers") @ExCommand(command = "ls,files,buffers")
internal data class BufferListCommand(val range: Range, val modifier: CommandModifier, val argument: String) : internal data class BufferListCommand(val range: Range, val argument: String) : Command.SingleExecution(range) {
Command.SingleExecution(range, modifier) {
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)
companion object { companion object {

View File

@ -18,6 +18,7 @@ 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.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.ranges.Range import com.maddyhome.idea.vim.ex.ranges.Range
import com.maddyhome.idea.vim.ex.ranges.toTextRange import com.maddyhome.idea.vim.ex.ranges.toTextRange
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
@ -29,9 +30,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
* see "h :!" * see "h :!"
*/ */
@ExCommand(command = "!") @ExCommand(command = "!")
internal data class CmdFilterCommand(val range: Range, val modifier: CommandModifier, val argument: String) internal data class CmdFilterCommand(val range: Range, val argument: String) : Command.SingleExecution(range) {
: Command.SingleExecution(range, modifier) {
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, operatorArguments: OperatorArguments): ExecutionResult { override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
@ -100,7 +99,7 @@ internal data class CmdFilterCommand(val range: Range, val modifier: CommandModi
lastCommand = command lastCommand = command
ExecutionResult.Success ExecutionResult.Success
} }
} catch (_: ProcessCanceledException) { } catch (e: ProcessCanceledException) {
throw ExException("Command terminated") throw ExException("Command terminated")
} catch (e: Exception) { } catch (e: Exception) {
throw ExException(e.message) throw ExException(e.message)

View File

@ -24,11 +24,8 @@ import java.net.URLEncoder
* see "h :help" * see "h :help"
*/ */
@ExCommand(command = "h[elp]") @ExCommand(command = "h[elp]")
internal data class HelpCommand(val range: Range, val modifier: CommandModifier, val argument: String) : internal data class HelpCommand(val range: Range, val argument: String) : Command.SingleExecution(range, argument) {
Command.SingleExecution(range, modifier, 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, operatorArguments: OperatorArguments): 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
@ -40,7 +37,7 @@ internal data class HelpCommand(val range: Range, val modifier: CommandModifier,
return try { return try {
String.format("%s?docs=help&search=%s", HELP_QUERY_URL, URLEncoder.encode(topic, "UTF-8")) String.format("%s?docs=help&search=%s", HELP_QUERY_URL, URLEncoder.encode(topic, "UTF-8"))
} catch (_: UnsupportedEncodingException) { } catch (e: UnsupportedEncodingException) {
HELP_ROOT_URL HELP_ROOT_URL
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2024 The IdeaVim authors * Copyright 2003-2023 The IdeaVim authors
* *
* Use of this source code is governed by an MIT-style * Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at * license that can be found in the LICENSE.txt file or at
@ -15,6 +15,9 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.lineLength import com.maddyhome.idea.vim.api.lineLength
import com.maddyhome.idea.vim.api.options import com.maddyhome.idea.vim.api.options
import com.maddyhome.idea.vim.api.visualLineToBufferLine import com.maddyhome.idea.vim.api.visualLineToBufferLine
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.vimLine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.state.mode.inVisualMode import com.maddyhome.idea.vim.state.mode.inVisualMode
import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
@ -99,12 +102,12 @@ private fun variableToPosition(editor: VimEditor, variable: VimDataType, dollarF
if (name.isEmpty()) return null if (name.isEmpty()) return null
// Current caret line // Current caret line
if (name[0] == '.') return editor.currentCaret().vimLine.asVimInt() to currentCol(editor) if (name[0] == '.') return editor.ij.vimLine.asVimInt() to currentCol(editor)
// Visual start // Visual start
if (name == "v") { if (name == "v") {
if (!editor.inVisualMode) { if (!editor.inVisualMode) {
return editor.currentCaret().vimLine.asVimInt() to currentCol(editor) return editor.ij.vimLine.asVimInt() to currentCol(editor)
} }
val vimStart = editor.currentCaret().vimSelectionStart val vimStart = editor.currentCaret().vimSelectionStart
@ -127,7 +130,7 @@ private fun variableToPosition(editor: VimEditor, variable: VimDataType, dollarF
// First visual line // First visual line
if (name.length >= 2 && name[0] == 'w' && name[1] == '0') { if (name.length >= 2 && name[0] == 'w' && name[1] == '0') {
if (!dollarForLine) return null if (!dollarForLine) return null
val actualVisualTop = injector.engineEditorHelper.getVisualLineAtTopOfScreen(editor) val actualVisualTop = EditorHelper.getVisualLineAtTopOfScreen(editor.ij)
val actualLogicalTop = editor.visualLineToBufferLine(actualVisualTop) val actualLogicalTop = editor.visualLineToBufferLine(actualVisualTop)
return (actualLogicalTop + 1).asVimInt() to currentCol(editor) return (actualLogicalTop + 1).asVimInt() to currentCol(editor)
} }
@ -135,7 +138,7 @@ private fun variableToPosition(editor: VimEditor, variable: VimDataType, dollarF
// Last visual line // Last visual line
if (name.length >= 2 && name[0] == 'w' && name[1] == '$') { if (name.length >= 2 && name[0] == 'w' && name[1] == '$') {
if (!dollarForLine) return null if (!dollarForLine) return null
val actualVisualBottom = injector.engineEditorHelper.getVisualLineAtBottomOfScreen(editor) val actualVisualBottom = EditorHelper.getVisualLineAtBottomOfScreen(editor.ij)
val actualLogicalBottom = editor.visualLineToBufferLine(actualVisualBottom) val actualLogicalBottom = editor.visualLineToBufferLine(actualVisualBottom)
return (actualLogicalBottom + 1).asVimInt() to currentCol(editor) return (actualLogicalBottom + 1).asVimInt() to currentCol(editor)
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2024 The IdeaVim authors * Copyright 2003-2023 The IdeaVim authors
* *
* Use of this source code is governed by an MIT-style * Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at * license that can be found in the LICENSE.txt file or at
@ -20,7 +20,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
@VimscriptFunction(name = "submatch") @VimscriptFunction(name = "submatch")
class SubmatchFunctionHandler : FunctionHandler() { internal class SubmatchFunctionHandler : FunctionHandler() {
override val minimumNumberOfArguments = 1 override val minimumNumberOfArguments = 1
override val maximumNumberOfArguments = 2 override val maximumNumberOfArguments = 2

View File

@ -26,7 +26,7 @@
serviceInterface="com.maddyhome.idea.vim.api.VimCommandLineService"/> serviceInterface="com.maddyhome.idea.vim.api.VimCommandLineService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.ui.ex.IjOutputPanelService" <applicationService serviceImplementation="com.maddyhome.idea.vim.ui.ex.IjOutputPanelService"
serviceInterface="com.maddyhome.idea.vim.api.VimOutputPanelService"/> serviceInterface="com.maddyhome.idea.vim.api.VimOutputPanelService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.api.VimDigraphGroupBase" <applicationService serviceImplementation="com.maddyhome.idea.vim.group.DigraphGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/> serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/> <applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.KeyGroup" <applicationService serviceImplementation="com.maddyhome.idea.vim.group.KeyGroup"

View File

@ -95,7 +95,7 @@
<!-- Do not care about red handlers in order. They are necessary for proper ordering, and they'll be resolved when needed --> <!-- Do not care about red handlers in order. They are necessary for proper ordering, and they'll be resolved when needed -->
<editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.VimEnterHandler" <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.VimEnterHandler"
id="ideavim-enter" id="ideavim-enter"
order="before editorEnter, before inline.completion.enter, before rd.client.editor.enter, after smart-step-into-enter, after AceHandlerEnter, after jupyterCommandModeEnterKeyHandler, after swift.placeholder.enter"/> order="before editorEnter, before rd.client.editor.enter, after smart-step-into-enter, after AceHandlerEnter, after jupyterCommandModeEnterKeyHandler, after swift.placeholder.enter"/>
<editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.CaretShapeEnterEditorHandler" <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.CaretShapeEnterEditorHandler"
id="ideavim-enter-shape" id="ideavim-enter-shape"
order="before jupyterCommandModeEnterKeyHandler"/> order="before jupyterCommandModeEnterKeyHandler"/>
@ -118,8 +118,6 @@
implementationClass="com.maddyhome.idea.vim.handler.StartNewLineBeforeCurrentDetector" implementationClass="com.maddyhome.idea.vim.handler.StartNewLineBeforeCurrentDetector"
id="ideavim-start-new-line-before-current-detector" id="ideavim-start-new-line-before-current-detector"
order="first"/> order="first"/>
<editorFactoryDocumentListener
implementation="com.maddyhome.idea.vim.listener.VimListenerManager$VimDocumentListener"/>
</extensions> </extensions>
<xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/> <xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>

View File

@ -1,3 +1,6 @@
{ {
"has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler" "col": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ColFunctionHandler",
"has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
"line": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LineFunctionHandler",
"submatch": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler"
} }

View File

@ -28,7 +28,6 @@ E20=E20: Mark not set
e_nopresub=E33: No previous substitute regular expression e_nopresub=E33: No previous substitute regular expression
e_noprev=E34: No previous command e_noprev=E34: No previous command
e_noprevre=E35: No previous regular expression e_noprevre=E35: No previous regular expression
E39=E39: Number expected
e_re_damg=E43: Damaged match string e_re_damg=E43: Damaged match string
e_re_corr=E44: Currupted regexp program e_re_corr=E44: Currupted regexp program
E50=E50: Too many \\z( E50=E50: Too many \\z(
@ -70,7 +69,6 @@ E385=E385: Search hit BOTTOM without match for: {0}
E471=E471: Argument required E471=E471: Argument required
E474=E474: Invalid argument: {0} E474=E474: Invalid argument: {0}
E475=E475: Invalid argument: {0} E475=E475: Invalid argument: {0}
E477=E477: No ! allowed
E481=E481: No range allowed E481=E481: No range allowed
E486=E486: Pattern not found: {0} E486=E486: Pattern not found: {0}
E488=E488: Trailing characters: {0} E488=E488: Trailing characters: {0}
@ -86,7 +84,6 @@ E549=E549: Illegal percentage: {0}
E774=E774: 'operatorfunc' is empty E774=E774: 'operatorfunc' is empty
e841.reserved.name.cannot.be.used.for.user.defined.command=E841: Reserved name, cannot be used for user defined command e841.reserved.name.cannot.be.used.for.user.defined.command=E841: Reserved name, cannot be used for user defined command
E939=E939: Positive count required E939=E939: Positive count required
E1214=E1214: Digraph must be just two characters: {0}
message.search.hit.bottom=search hit BOTTOM, continuing at TOP message.search.hit.bottom=search hit BOTTOM, continuing at TOP
message.search.hit.top=search hit TOP, continuing at BOTTOM message.search.hit.top=search hit TOP, continuing at BOTTOM

View File

@ -69,7 +69,6 @@ class ChangeActionTest : VimTestCase() {
// VIM-620 |i_CTRL-O| // VIM-620 |i_CTRL-O|
@Test @Test
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR)
fun testInsertSingleCommandAndNewLineInserting4() { fun testInsertSingleCommandAndNewLineInserting4() {
doTest( doTest(
listOf("i", "<C-O>", "v", "d"), listOf("i", "<C-O>", "v", "d"),
@ -130,7 +129,6 @@ class ChangeActionTest : VimTestCase() {
// VIM-311 |i_CTRL-O| // VIM-311 |i_CTRL-O|
@Test @Test
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR)
fun testInsertSingleCommand() { fun testInsertSingleCommand() {
doTest( doTest(
listOf("i", "def", "<C-O>", "d2h", "x"), listOf("i", "def", "<C-O>", "d2h", "x"),
@ -1074,7 +1072,6 @@ foobaz
@Test @Test
@TestFor(issues = ["VIM-2074"]) @TestFor(issues = ["VIM-2074"])
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR)
fun `backspace with replace mode`() { fun `backspace with replace mode`() {
configureByText("${c}Hello world") configureByText("${c}Hello world")
typeText("R1111") typeText("R1111")

View File

@ -11,7 +11,6 @@ import com.intellij.idea.TestFor
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim import org.jetbrains.plugins.ideavim.TestWithoutNeovim
@ -251,10 +250,7 @@ class CopyActionTest : VimTestCase() {
enterCommand("set clipboard=unnamed") enterCommand("set clipboard=unnamed")
kotlin.test.assertEquals('*', VimPlugin.getRegister().defaultRegister) kotlin.test.assertEquals('*', VimPlugin.getRegister().defaultRegister)
typeText("yy") typeText("yy")
val vimEditor = fixture.editor.vim val starRegister = VimPlugin.getRegister().getRegister('*')
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val starRegister = registerService.getRegister(vimEditor, context, '*')
assertNotNull<Any>(starRegister) assertNotNull<Any>(starRegister)
kotlin.test.assertEquals("bar\n", starRegister.text) kotlin.test.assertEquals("bar\n", starRegister.text)
} }
@ -266,10 +262,7 @@ class CopyActionTest : VimTestCase() {
fun testLineWiseClipboardYankPaste() { fun testLineWiseClipboardYankPaste() {
configureByText("<caret>foo\n") configureByText("<caret>foo\n")
typeText("\"*yy" + "\"*p") typeText("\"*yy" + "\"*p")
val vimEditor = fixture.editor.vim val register = VimPlugin.getRegister().getRegister('*')
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val register = registerService.getRegister(vimEditor, context, '*')
assertNotNull<Any>(register) assertNotNull<Any>(register)
kotlin.test.assertEquals("foo\n", register.text) kotlin.test.assertEquals("foo\n", register.text)
val editor = fixture.editor val editor = fixture.editor
@ -297,10 +290,7 @@ class CopyActionTest : VimTestCase() {
""".trimIndent(), """.trimIndent(),
) )
typeText("<C-V>j" + "\"*y" + "\"*p") typeText("<C-V>j" + "\"*y" + "\"*p")
val vimEditor = fixture.editor.vim val register = VimPlugin.getRegister().getRegister('*')
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val register = registerService.getRegister(vimEditor, context, '*')
assertNotNull<Any>(register) assertNotNull<Any>(register)
kotlin.test.assertEquals( kotlin.test.assertEquals(
""" """

View File

@ -10,10 +10,10 @@ package org.jetbrains.plugins.ideavim.action
import com.intellij.idea.TestFor import com.intellij.idea.TestFor
import com.intellij.testFramework.LoggedErrorProcessor import com.intellij.testFramework.LoggedErrorProcessor
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.keys import com.maddyhome.idea.vim.api.keys
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.ExceptionHandler import org.jetbrains.plugins.ideavim.ExceptionHandler
import org.jetbrains.plugins.ideavim.OnlyThrowLoggedErrorProcessor import org.jetbrains.plugins.ideavim.OnlyThrowLoggedErrorProcessor
import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.SkipNeovimReason
@ -52,18 +52,15 @@ class MacroActionTest : VimTestCase() {
configureByText("") configureByText("")
enterCommand("imap pp hello") enterCommand("imap pp hello")
typeText(injector.parser.parseKeys("qa" + "i" + "pp<Esc>" + "q")) typeText(injector.parser.parseKeys("qa" + "i" + "pp<Esc>" + "q"))
assertRegister('a', "ipp^[") assertRegister('a', "ipp<Esc>")
} }
@Test @Test
fun testRecordMacroWithDigraph() { fun testRecordMacroWithDigraph() {
typeTextInFile(injector.parser.parseKeys("qa" + "i" + "<C-K>OK<Esc>" + "q"), "") typeTextInFile(injector.parser.parseKeys("qa" + "i" + "<C-K>OK<Esc>" + "q"), "")
val vimEditor = fixture.editor.vim val register = VimPlugin.getRegister().getRegister('a')
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val register = registerService.getRegister(vimEditor, context, 'a')
assertNotNull<Any>(register) assertNotNull<Any>(register)
assertRegister('a', "i^KOK^[") assertRegister('a', "i<C-K>OK<Esc>")
} }
@Test @Test
@ -99,10 +96,7 @@ class MacroActionTest : VimTestCase() {
configureByText(content) configureByText(content)
typeText(injector.parser.parseKeys("qa" + ":map x y<CR>" + "q")) typeText(injector.parser.parseKeys("qa" + ":map x y<CR>" + "q"))
val vimEditor = fixture.editor.vim val register = VimPlugin.getRegister().getRegister('a')
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val register = registerService.getRegister(vimEditor, context, 'a')
val registerSize = register!!.keys.size val registerSize = register!!.keys.size
assertEquals(9, registerSize) assertEquals(9, registerSize)
} }
@ -250,10 +244,8 @@ class MacroActionTest : VimTestCase() {
) )
injector.keyGroup.putKeyMapping(MappingMode.NXO, keys("abc"), exceptionMappingOwner, ExceptionHandler(), false) injector.keyGroup.putKeyMapping(MappingMode.NXO, keys("abc"), exceptionMappingOwner, ExceptionHandler(), false)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('k', "abc")
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) injector.registerGroup.storeText('q', "x@ky")
injector.registerGroup.storeText(vimEditor, context, 'k', "abc")
injector.registerGroup.storeText(vimEditor, context, 'q', "x@ky")
val exception = assertThrows<Throwable> { val exception = assertThrows<Throwable> {
LoggedErrorProcessor.executeWith<Throwable>(OnlyThrowLoggedErrorProcessor) { LoggedErrorProcessor.executeWith<Throwable>(OnlyThrowLoggedErrorProcessor) {

View File

@ -10,7 +10,6 @@ package org.jetbrains.plugins.ideavim.action
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import 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
@ -29,10 +28,8 @@ class MacroWithEditingTest : VimTestCase() {
@Test @Test
fun `test copy and perform macro`() { fun `test copy and perform macro`() {
typeTextInFile(injector.parser.parseKeys("^v\$h\"wy"), "iHello") typeTextInFile(injector.parser.parseKeys("^v\$h\"wy"), "iHello<Esc>")
val vimEditor = fixture.editor.vim kotlin.test.assertEquals("iHello<Esc>", VimPlugin.getRegister().getRegister('w')?.rawText)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
kotlin.test.assertEquals("iHello", VimPlugin.getRegister().getRegister(vimEditor, context, 'w')?.text)
setText("") setText("")
typeText(injector.parser.parseKeys("@w")) typeText(injector.parser.parseKeys("@w"))
waitAndAssert { waitAndAssert {
@ -42,10 +39,8 @@ class MacroWithEditingTest : VimTestCase() {
@Test @Test
fun `test copy and perform macro ctrl_a`() { fun `test copy and perform macro ctrl_a`() {
typeTextInFile(injector.parser.parseKeys("^v\$h\"wy"), "\u0001") typeTextInFile(injector.parser.parseKeys("^v\$h\"wy"), "<C-A>")
val vimEditor = fixture.editor.vim kotlin.test.assertEquals("<C-A>", VimPlugin.getRegister().getRegister('w')?.rawText)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
kotlin.test.assertEquals(injector.parser.parseKeys("<C-A>"), injector.registerGroup.getRegister(vimEditor, context, 'w')!!.keys)
setText("1") setText("1")
typeText(injector.parser.parseKeys("@w")) typeText(injector.parser.parseKeys("@w"))
waitAndAssert { waitAndAssert {

View File

@ -13,11 +13,9 @@ import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
@ -1817,7 +1815,6 @@ $c five six se${c}ven eight
) )
} }
@Disabled("Action execution in tests is broken for 2024.2")
@Test @Test
fun testInsertNewLineAboveAction() { fun testInsertNewLineAboveAction() {
typeTextInFile( typeTextInFile(
@ -1844,7 +1841,6 @@ $c five six se${c}ven eight
) )
} }
@Disabled("Action execution in tests is broken for 2024.2")
@VimBehaviorDiffers(originalVimAfter = "${c}\n${c}\nabcde\n${c}\n${c}\nabcde\n") @VimBehaviorDiffers(originalVimAfter = "${c}\n${c}\nabcde\n${c}\n${c}\nabcde\n")
@Test @Test
fun testInsertNewLineAboveActionWithMultipleCaretsInLine() { fun testInsertNewLineAboveActionWithMultipleCaretsInLine() {
@ -1859,7 +1855,6 @@ $c five six se${c}ven eight
assertState("${c}\nabcde\n${c}\nabcde\n") assertState("${c}\nabcde\n${c}\nabcde\n")
} }
@Disabled("Action execution in tests is broken for 2024.2")
@Test @Test
fun testInsertNewLineBelowAction() { fun testInsertNewLineBelowAction() {
typeTextInFile( typeTextInFile(
@ -2165,9 +2160,7 @@ rtyfg${c}hzxc"""
fun testPutTextBeforeCursor() { fun testPutTextBeforeCursor() {
val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn" val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("\"*P" + "3l" + "\"*P")) typeText(injector.parser.parseKeys("\"*P" + "3l" + "\"*P"))
val after = "fghqwfg${c}he asd fghzxfg${c}hc rty fghfgfg${c}hh vbn" val after = "fghqwfg${c}he asd fghzxfg${c}hc rty fghfgfg${c}hh vbn"
assertState(after) assertState(after)
@ -2177,11 +2170,9 @@ rtyfg${c}hzxc"""
fun testPutTextBeforeCursorOverlapRange() { fun testPutTextBeforeCursorOverlapRange() {
val before = "${c}q${c}we asd zxc rty ${c}fgh vbn" val before = "${c}q${c}we asd zxc rty ${c}fgh vbn"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh")
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh")
VimPlugin.getRegister() VimPlugin.getRegister()
.storeText(IjVimEditor(editor), context, editor.vim.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false) .storeText(IjVimEditor(editor), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("\"*P")) typeText(injector.parser.parseKeys("\"*P"))
val after = "fg${c}hqfg${c}hwe asd zxc rty fg${c}hfgh vbn" val after = "fg${c}hqfg${c}hwe asd zxc rty fg${c}hfgh vbn"
assertState(after) assertState(after)
@ -2191,9 +2182,7 @@ rtyfg${c}hzxc"""
fun testPutTextAfterCursor() { fun testPutTextAfterCursor() {
val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn" val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("\"*p" + "3l" + "2\"*p")) typeText(injector.parser.parseKeys("\"*p" + "3l" + "2\"*p"))
val after = "qfghwe fghfg${c}hasd zfghxc fghfg${c}hrty ffghgh fghfg${c}hvbn" val after = "qfghwe fghfg${c}hasd zfghxc fghfg${c}hrty ffghgh fghfg${c}hvbn"
assertState(after) assertState(after)
@ -2203,9 +2192,7 @@ rtyfg${c}hzxc"""
fun testPutTextAfterCursorOverlapRange() { fun testPutTextAfterCursorOverlapRange() {
val before = "${c}q${c}we asd zxc rty ${c}fgh vbn" val before = "${c}q${c}we asd zxc rty ${c}fgh vbn"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("2\"*p")) typeText(injector.parser.parseKeys("2\"*p"))
val after = "qfghfg${c}hwfghfg${c}he asd zxc rty ffghfg${c}hgh vbn" val after = "qfghfg${c}hwfghfg${c}he asd zxc rty ffghfg${c}hgh vbn"
assertState(after) assertState(after)
@ -2220,9 +2207,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "zxcvbn\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*P")) typeText(injector.parser.parseKeys("\"*P"))
val after = """ val after = """
${c}zxcvbn ${c}zxcvbn
@ -2356,9 +2341,7 @@ rtyfg${c}hzxc"""
private fun testPutOverlapLine(before: String, after: String, beforeCursor: Boolean) { private fun testPutOverlapLine(before: String, after: String, beforeCursor: Boolean) {
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "zxcvbn\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*" + if (beforeCursor) "P" else "p")) typeText(injector.parser.parseKeys("\"*" + if (beforeCursor) "P" else "p"))
assertState(after) assertState(after)
} }
@ -2372,9 +2355,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "zxcvbn", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "zxcvbn", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*p")) typeText(injector.parser.parseKeys("\"*p"))
val after = """ val after = """
qwerty qwerty
@ -2392,9 +2373,7 @@ rtyfg${c}hzxc"""
fun testPutTextBeforeCursorMoveCursor() { fun testPutTextBeforeCursorMoveCursor() {
val before = "qw${c}e asd z${c}xc rty ${c}fgh vbn" val before = "qw${c}e asd z${c}xc rty ${c}fgh vbn"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("l" + "\"*gP" + "b" + "\"*gP")) typeText(injector.parser.parseKeys("l" + "\"*gP" + "b" + "\"*gP"))
val after = "fgh${c}qwefgh asd fgh${c}zxfghc rty fgh${c}ffghgh vbn" val after = "fgh${c}qwefgh asd fgh${c}zxfghc rty fgh${c}ffghgh vbn"
assertState(after) assertState(after)
@ -2404,9 +2383,7 @@ rtyfg${c}hzxc"""
fun testPutTextAfterCursorMoveCursor() { fun testPutTextAfterCursorMoveCursor() {
val before = "qw${c}e asd z${c}xc rty ${c}fgh vbn" val before = "qw${c}e asd z${c}xc rty ${c}fgh vbn"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "fgh", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "fgh", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("l" + "\"*gp" + "b" + "\"*gp")) typeText(injector.parser.parseKeys("l" + "\"*gp" + "b" + "\"*gp"))
val after = "qwe ffgh${c}ghasd zfgh${c}xcfgh rty ffgh${c}gfghh vbn" val after = "qwe ffgh${c}ghasd zfgh${c}xcfgh rty ffgh${c}gfghh vbn"
assertState(after) assertState(after)
@ -2421,9 +2398,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "zxcvbn\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*gP")) typeText(injector.parser.parseKeys("\"*gP"))
val after = """ val after = """
zxcvbn zxcvbn
@ -2446,9 +2421,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "zxcvbn", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "zxcvbn", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*gp")) typeText(injector.parser.parseKeys("\"*gp"))
val after = """ val after = """
qwerty qwerty
@ -2468,9 +2441,7 @@ rtyfg${c}hzxc"""
* two * two
""" """
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', " *\n *\n", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', " *\n *\n", SelectionType.BLOCK_WISE)
typeText(injector.parser.parseKeys("\"*p")) typeText(injector.parser.parseKeys("\"*p"))
val after = """ * $c *one$c * val after = """ * $c *one$c *
* *two * * *two *
@ -2484,9 +2455,7 @@ rtyfg${c}hzxc"""
* two * two
""" """
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', " *\n \n", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', " *\n \n", SelectionType.BLOCK_WISE)
typeText(injector.parser.parseKeys("\"*P")) typeText(injector.parser.parseKeys("\"*P"))
val after = """ *$c * on$c *e val after = """ *$c * on$c *e
* tw o * tw o
@ -2505,9 +2474,7 @@ rtyfg${c}hzxc"""
vb${c}n vb${c}n
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "qwe\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '*', "qwe\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("\"*p")) typeText(injector.parser.parseKeys("\"*p"))
val after = """ val after = """
qwe qwe
@ -2529,10 +2496,7 @@ rtyfg${c}hzxc"""
val before = "qwe ${c}asd ${c}zxc" val before = "qwe ${c}asd ${c}zxc"
configureByText(before) configureByText(before)
typeText(injector.parser.parseKeys("ye")) typeText(injector.parser.parseKeys("ye"))
val vimEditor = fixture.editor.vim val lastRegister = VimPlugin.getRegister().lastRegister
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val lastRegister = registerService.getRegister(vimEditor, context, registerService.lastRegisterChar)
assertNotNull<Any>(lastRegister) assertNotNull<Any>(lastRegister)
val text = lastRegister.text val text = lastRegister.text
assertNotNull<Any>(text) assertNotNull<Any>(text)
@ -2554,10 +2518,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
typeText(injector.parser.parseKeys("yj")) typeText(injector.parser.parseKeys("yj"))
val vimEditor = fixture.editor.vim val lastRegister = VimPlugin.getRegister().lastRegister
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val lastRegister = registerService.getRegister(vimEditor, context, registerService.lastRegisterChar)
assertNotNull<Any>(lastRegister) assertNotNull<Any>(lastRegister)
val text = lastRegister.text val text = lastRegister.text
assertNotNull<Any>(text) assertNotNull<Any>(text)
@ -2591,10 +2552,7 @@ rtyfg${c}hzxc"""
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
typeText(injector.parser.parseKeys("2yy")) typeText(injector.parser.parseKeys("2yy"))
val vimEditor = fixture.editor.vim val lastRegister = VimPlugin.getRegister().lastRegister
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val lastRegister = registerService.getRegister(vimEditor, context, registerService.lastRegisterChar)
assertNotNull<Any>(lastRegister) assertNotNull<Any>(lastRegister)
val text = lastRegister.text val text = lastRegister.text
assertNotNull<Any>(text) assertNotNull<Any>(text)

View File

@ -9,7 +9,6 @@ package org.jetbrains.plugins.ideavim.action
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_INSERTED_TEXT_REGISTER import com.maddyhome.idea.vim.register.RegisterConstants.LAST_INSERTED_TEXT_REGISTER
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_SEARCH_REGISTER import com.maddyhome.idea.vim.register.RegisterConstants.LAST_SEARCH_REGISTER
import com.maddyhome.idea.vim.register.RegisterConstants.SMALL_DELETION_REGISTER import com.maddyhome.idea.vim.register.RegisterConstants.SMALL_DELETION_REGISTER
@ -211,9 +210,7 @@ class SpecialRegistersTest : VimTestCase() {
private fun getRegisterText(registerName: Char): String? { private fun getRegisterText(registerName: Char): String? {
val registerGroup = VimPlugin.getRegister() val registerGroup = VimPlugin.getRegister()
val vimEditor = fixture.editor.vim val register = registerGroup.getRegister(registerName)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val register = registerGroup.getRegister(vimEditor, context, registerName)
assertNotNull<Any>(register) assertNotNull<Any>(register)
return register!!.text return register!!.text
} }

View File

@ -162,16 +162,6 @@ class UndoActionTest : VimTestCase() {
configureByText("Lorem ${c}ipsum dolor sit amet") configureByText("Lorem ${c}ipsum dolor sit amet")
} }
@Test
@TestFor(issues = ["VIM-3671"])
fun `test undo scrolls caret to reset scrolloff`() {
configureByLines(200, "lorem ipsum dolor sit amet")
enterCommand("set scrolloff=10")
typeText("50G", "dd", "G", "u")
assertPosition(49, 0)
assertVisibleArea(39, 73)
}
private fun hasSelection(): Boolean { private fun hasSelection(): Boolean {
val editor = fixture.editor val editor = fixture.editor
return editor.caretModel.primaryCaret.hasSelection() return editor.caretModel.primaryCaret.hasSelection()

View File

@ -194,16 +194,4 @@ Mode.INSERT,
fun testLastSymbolInWord() { fun testLastSymbolInWord() {
doTest("cw", "fo${c}o", "fo${c}", Mode.INSERT) doTest("cw", "fo${c}o", "fo${c}", Mode.INSERT)
} }
// VIM-3729
@Test
fun `test change with count applies only to motion when repeated`() {
doTest(listOf("2c3l", "foo<Esc>", "w", "."),
"""
banana banana
""".trimIndent(),
"""
foo foo
""".trimIndent())
}
} }

View File

@ -10,8 +10,7 @@
package org.jetbrains.plugins.ideavim.action.change.delete package org.jetbrains.plugins.ideavim.action.change.delete
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.newapi.vim
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.VimBehaviorDiffers import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
@ -103,10 +102,7 @@ class DeleteMotionActionTest : VimTestCase() {
expression${c} two expression${c} two
""".trimIndent(), """.trimIndent(),
) )
val vimEditor = fixture.editor.vim val savedText = VimPlugin.getRegister().lastRegister?.text ?: ""
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
val savedText = registerService.getRegister(vimEditor, context, registerService.lastRegisterChar)?.text ?: ""
kotlin.test.assertEquals(" expression two\n", savedText) kotlin.test.assertEquals(" expression two\n", savedText)
} }

View File

@ -1,58 +0,0 @@
/*
* Copyright 2003-2024 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.action.change.insert
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test
class InsertCompletedDigraphActionTest : VimTestCase() {
@Test
fun `test insert digraph`() {
doTest(listOf("i", "<C-K>OK", "<Esc>"), "", "")
}
@Test
fun `test insert digraph with reversed characters`() {
doTest(listOf("i", "<C-K>KO", "<Esc>"), "", "")
}
@Test
fun `test insert same character with different digraphs`() {
doTest(listOf("i", "<C-K>Ct", "<C-K>c|", "<Esc>"), "", "¢¢")
}
@Test
fun `test insert custom digraph`() {
doTest(listOf("i", "<C-K>(0", "<Esc>"), "", "") {
enterCommand("digraph (0 9450")
}
}
@Test
fun `test insert custom digraph with reversed characters`() {
doTest(listOf("i", "<C-K>0(", "<Esc>"), "", "") {
enterCommand("digraph (0 9450")
}
}
@Test
fun `test insert custom digraph overriding existing custom digraph`() {
doTest(listOf("i", "<C-K>(0", "<Esc>"), "", "") {
enterCommand("digraph (0 9450")
enterCommand("digraph (0 10003")
}
}
@Test
fun `test insert custom digraph overriding existing default digraph`() {
doTest(listOf("i", "<C-K>OK", "<Esc>"), "", "") {
enterCommand("digraph OK 9450")
}
}
}

View File

@ -15,7 +15,6 @@ import com.maddyhome.idea.vim.state.mode.Mode
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 org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -85,7 +84,6 @@ class InsertNewLineAboveActionTest : VimTestCase() {
doTest("O", before, after, Mode.INSERT) doTest("O", before, after, Mode.INSERT)
} }
@Disabled("Action execution in tests is broken for 2024.2")
@Test @Test
fun `test insert new line above with multiple carets`() { fun `test insert new line above with multiple carets`() {
val before = """ I fou${c}nd it in a legendary land val before = """ I fou${c}nd it in a legendary land

View File

@ -12,7 +12,6 @@ import com.maddyhome.idea.vim.state.mode.Mode
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 org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
class InsertNewLineBelowActionTest : VimTestCase() { class InsertNewLineBelowActionTest : VimTestCase() {
@ -80,7 +79,6 @@ class InsertNewLineBelowActionTest : VimTestCase() {
doTest("o", before, after, Mode.INSERT) doTest("o", before, after, Mode.INSERT)
} }
@Disabled("Action execution in tests is broken for 2024.2")
@Test @Test
fun `test insert new line below with multiple carets`() { fun `test insert new line below with multiple carets`() {
val before = """ I fou${c}nd it in a legendary land val before = """ I fou${c}nd it in a legendary land

View File

@ -32,9 +32,8 @@ class IdeaPutNotificationsTest : VimTestCase() {
configureByText(before) configureByText(before)
appReadySetup(false) appReadySetup(false)
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val notification = notifications().last() val notification = notifications().last()
@ -53,9 +52,8 @@ class IdeaPutNotificationsTest : VimTestCase() {
configureByText(before) configureByText(before)
appReadySetup(false) appReadySetup(false)
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val notifications = notifications() val notifications = notifications()
@ -72,9 +70,8 @@ class IdeaPutNotificationsTest : VimTestCase() {
configureByText(before) configureByText(before)
appReadySetup(true) appReadySetup(true)
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val notifications = EventLog.getLogModel(fixture.project).notifications val notifications = EventLog.getLogModel(fixture.project).notifications

View File

@ -15,6 +15,7 @@ import com.intellij.openapi.editor.CaretStateTransferableData
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.testFramework.ExtensionTestUtil import com.intellij.testFramework.ExtensionTestUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.globalOptions import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
@ -86,9 +87,8 @@ class PutTestAfterCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("p")) typeText(injector.parser.parseKeys("p"))
val after = """ val after = """
A Discovery A Discovery
@ -124,13 +124,9 @@ class PutTestAfterCursorActionTest : VimTestCase() {
// Add Guard to simulate Notebook behaviour. See (VIM-2577) // Add Guard to simulate Notebook behaviour. See (VIM-2577)
val guardRange = before rangeOf "\nGUARD\n" val guardRange = before rangeOf "\nGUARD\n"
editor.document.createGuardedBlock(guardRange.startOffset, guardRange.endOffset) editor.document.createGuardedBlock(guardRange.startOffset, guardRange.endOffset)
val vimEditor = fixture.editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) injector.registerGroup.storeText(
val registerService = injector.registerGroup
registerService.storeText(
vimEditor, vimEditor,
context,
vimEditor.primaryCaret(),
before rangeOf "I found it in a legendary land\n", before rangeOf "I found it in a legendary land\n",
SelectionType.LINE_WISE, SelectionType.LINE_WISE,
false, false,
@ -159,9 +155,8 @@ class PutTestAfterCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("vep")) typeText(injector.parser.parseKeys("vep"))
val after = """ val after = """
A Discovery A Discovery

View File

@ -31,9 +31,7 @@ class PutTextBeforeCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) injector.registerGroup.storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "P")) typeText(injector.parser.parseKeys("V" + "P"))
typeText(injector.parser.parseKeys("V" + "P")) typeText(injector.parser.parseKeys("V" + "P"))
val after = """ val after = """

View File

@ -39,10 +39,7 @@ class PutViaIdeaTest : VimTestCase() {
val before = "${c}Lorem ipsum dolor sit amet," val before = "${c}Lorem ipsum dolor sit amet,"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('"', "legendary", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, '"', "legendary", SelectionType.CHARACTER_WISE)
typeText("ve", "p") typeText("ve", "p")
val after = "legendar${c}y ipsum dolor sit amet," val after = "legendar${c}y ipsum dolor sit amet,"
@ -56,9 +53,8 @@ class PutViaIdeaTest : VimTestCase() {
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText("ppp") typeText("ppp")
val after = "Ilegendarylegendarylegendar${c}y found it in a legendary land" val after = "Ilegendarylegendarylegendar${c}y found it in a legendary land"
@ -74,14 +70,10 @@ class PutViaIdeaTest : VimTestCase() {
CopyPasteManager.getInstance().setContents(TextBlockTransferable("Fill", emptyList(), null)) CopyPasteManager.getInstance().setContents(TextBlockTransferable("Fill", emptyList(), null))
CopyPasteManager.getInstance().setContents(TextBlockTransferable("Buffer", emptyList(), null)) CopyPasteManager.getInstance().setContents(TextBlockTransferable("Buffer", emptyList(), null))
VimPlugin.getRegister()
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister()
val registerService = injector.registerGroup .storeText(
registerService.storeText(
vimEditor, vimEditor,
context,
vimEditor.primaryCaret(),
before rangeOf "legendary$randomUUID", before rangeOf "legendary$randomUUID",
SelectionType.CHARACTER_WISE, SelectionType.CHARACTER_WISE,
false, false,
@ -105,12 +97,8 @@ class PutViaIdeaTest : VimTestCase() {
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim val vimEditor = fixture.editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(
val registerService = injector.registerGroup
registerService.storeText(
vimEditor, vimEditor,
context,
vimEditor.primaryCaret(),
before rangeOf "\nLorem ipsum dolor sit amet,\n", before rangeOf "\nLorem ipsum dolor sit amet,\n",
SelectionType.CHARACTER_WISE, SelectionType.CHARACTER_WISE,
false, false,

View File

@ -10,6 +10,7 @@
package org.jetbrains.plugins.ideavim.action.copy package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType import com.maddyhome.idea.vim.state.mode.SelectionType
@ -73,12 +74,8 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text`() { fun `test put visual text`() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = "legendar${c}y it in a legendary land" val after = "legendar${c}y it in a legendary land"
assertState(after) assertState(after)
@ -89,12 +86,8 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text twice`() { fun `test put visual text twice`() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "2p")) typeText(injector.parser.parseKeys("v2e" + "2p"))
val after = "legendarylegendar${c}y in a legendary land" val after = "legendarylegendar${c}y in a legendary land"
assertState(after) assertState(after)
@ -105,12 +98,8 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text full line`() { fun `test put visual text full line`() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v$" + "2p")) typeText(injector.parser.parseKeys("v$" + "2p"))
val after = "legendarylegendar${c}y" val after = "legendarylegendar${c}y"
assertState(after) assertState(after)
@ -121,9 +110,7 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text multicaret`() { fun `test put visual text multicaret`() {
val before = "${c}I found ${c}it in a ${c}legendary land" val before = "${c}I found ${c}it in a ${c}legendary land"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "legendary", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "legendary", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = "legendar${c}y legendar${c}y in a legendar${c}y land" val after = "legendar${c}y legendar${c}y in a legendar${c}y land"
assertState(after) assertState(after)
@ -134,9 +121,7 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text multicaret clipboard register`() { fun `test put visual text multicaret clipboard register`() {
val before = "${c}I found ${c}it in a ${c}legendary land" val before = "${c}I found ${c}it in a ${c}legendary land"
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "legendary", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "legendary", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = "legendar${c}y legendar${c}y in a legendar${c}y land" val after = "legendar${c}y legendar${c}y in a legendar${c}y land"
assertState(after) assertState(after)
@ -147,12 +132,8 @@ class PutVisualTextActionTest : VimTestCase() {
fun `test put visual text another direction`() { fun `test put visual text another direction`() {
val before = "I foun${c}d it in a legendary land" val before = "I foun${c}d it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("vb" + "p")) typeText(injector.parser.parseKeys("vb" + "p"))
val after = "I legendar${c}y it in a legendary land" val after = "I legendar${c}y it in a legendary land"
assertState(after) assertState(after)
@ -172,12 +153,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -204,12 +181,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -236,12 +209,8 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the torrent of a mountain pass. ${c}hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -268,12 +237,8 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the torrent of a mountain pass. ${c}hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("v$" + "p")) typeText(injector.parser.parseKeys("v$" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -300,9 +265,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the torrent of a mountain pass. ${c}hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"*p")) typeText(injector.parser.parseKeys("ve" + "\"*p"))
val after = """ val after = """
A Discovery A Discovery
@ -333,9 +296,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the torrent of a mountain pass. ${c}hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -366,9 +327,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the$c torrent of a mountain pass. ${c}hard by the$c torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -397,9 +356,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the$c torrent of a mountain pass. ${c}hard by the$c torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -428,9 +385,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the$c torrent of a mountain pass. ${c}hard by the$c torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "2\"+p")) typeText(injector.parser.parseKeys("ve" + "2\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -461,9 +416,7 @@ class PutVisualTextActionTest : VimTestCase() {
${c}hard by the$c torrent of a mountain pass. ${c}hard by the$c torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "2\"+p")) typeText(injector.parser.parseKeys("ve" + "2\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -501,12 +454,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy underside, the checquered fringe. the dingy underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -541,12 +490,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p")) typeText(injector.parser.parseKeys("ve" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -583,12 +528,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "2p")) typeText(injector.parser.parseKeys("ve" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -625,10 +566,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) // VimPlugin.getRegister().storeText(editor.vim, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
injector.registerGroup.storeText(vimEditor, context,'+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
// registerService.storeText(editor.vim context,, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -665,10 +604,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) // VimPlugin.getRegister().storeText(editor.vim, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
injector.registerGroup.storeText(vimEditor, context,'+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
// registerService.storeText(editor.vim context,, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "\"+p")) typeText(injector.parser.parseKeys("ve" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -702,12 +639,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -732,12 +665,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "2p")) typeText(injector.parser.parseKeys("V" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -773,12 +702,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by ${c}the torrent of a mountain pass. hard by ${c}the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -814,9 +739,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "Discovery", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'*', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p")) typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """ val after = """
A Discovery A Discovery
@ -852,9 +775,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "Discovery", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -890,9 +811,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "Discovery", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -928,9 +847,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "Discovery", SelectionType.CHARACTER_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -958,12 +875,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -988,12 +901,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "2p")) typeText(injector.parser.parseKeys("V" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -1029,12 +938,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1070,9 +975,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p")) typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """ val after = """
A Discovery A Discovery
@ -1108,9 +1011,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -1146,9 +1047,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -1184,9 +1083,7 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the ${c}torrent of a mountain pass. hard by the ${c}torrent of a mountain pass.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "A Discovery\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -1219,12 +1116,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy underside, the checquered fringe. the dingy underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1278,12 +1171,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("V" + "p")) typeText(injector.parser.parseKeys("V" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1343,12 +1232,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("V" + "2p")) typeText(injector.parser.parseKeys("V" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -1407,9 +1292,7 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -1470,9 +1353,7 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy ${c}underside, the checquered fringe. the dingy ${c}underside, the checquered fringe.
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context,'+', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
typeText(injector.parser.parseKeys("V" + "\"+p")) typeText(injector.parser.parseKeys("V" + "\"+p"))
val after = """ val after = """
A Discovery A Discovery
@ -1527,12 +1408,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1557,12 +1434,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("<C-V>3e2k" + "p")) typeText(injector.parser.parseKeys("<C-V>3e2k" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1587,12 +1460,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -1617,12 +1486,8 @@ class PutVisualTextActionTest : VimTestCase() {
ha|rd by the torrent of a mountain pass. ha|rd by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("<C-V>3j$" + "p")) typeText(injector.parser.parseKeys("<C-V>3j$" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1660,12 +1525,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1692,12 +1553,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "P")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "P"))
val after = """ val after = """
A Discovery A Discovery
@ -1735,12 +1592,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
val after = """ val after = """
A Discovery A Discovery
@ -1779,12 +1632,8 @@ class PutVisualTextActionTest : VimTestCase() {
ha|rd by| the torrent of a mountain pass. ha|rd by| the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p")) typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1822,12 +1671,8 @@ class PutVisualTextActionTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2j$" + "p")) typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1861,12 +1706,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy underside, the checquered fringe. the dingy underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e2j" + "p")) typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1901,12 +1742,8 @@ class PutVisualTextActionTest : VimTestCase() {
the |dingy un|derside, the checquered fringe. the |dingy un|derside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2e3j" + "p")) typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1941,12 +1778,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy underside, the checquered fringe. the dingy underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2ej" + "p")) typeText(injector.parser.parseKeys("<C-V>2ej" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -1982,10 +1815,7 @@ class PutVisualTextActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<C-V>elj" + "p")) typeText(injector.parser.parseKeys("<C-V>elj" + "p"))
val after = """ val after = """
A Discovery A Discovery
@ -2021,12 +1851,8 @@ class PutVisualTextActionTest : VimTestCase() {
the dingy underside, the checquered fringe. the dingy underside, the checquered fringe.
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<C-V>2j$" + "p")) typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
val after = """ val after = """
A Discovery A Discovery

View File

@ -8,6 +8,7 @@
package org.jetbrains.plugins.ideavim.action.copy package org.jetbrains.plugins.ideavim.action.copy
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.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
@ -32,9 +33,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "2gp")) typeText(injector.parser.parseKeys("v2e" + "2gp"))
val after = "legendarylegendary$c in a legendary land" val after = "legendarylegendary$c in a legendary land"
assertState(after) assertState(after)
@ -46,9 +45,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "gp")) typeText(injector.parser.parseKeys("v2e" + "gp"))
val after = """ val after = """
@ -64,9 +61,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "gp")) typeText(injector.parser.parseKeys("V" + "gp"))
val after = "legendary\n$c" val after = "legendary\n$c"
assertState(after) assertState(after)
@ -93,9 +88,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(file) val editor = configureByText(file)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(2, 11), SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(2, 11), SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "gp")) typeText(injector.parser.parseKeys("V" + "gp"))
assertState(newFile) assertState(newFile)
} }
@ -141,9 +134,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "gP")) typeText(injector.parser.parseKeys("v2e" + "gP"))
val after = """ val after = """
@ -159,9 +150,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "2gP")) typeText(injector.parser.parseKeys("v2e" + "2gP"))
val after = "legendarylegendary$c in a legendary land" val after = "legendarylegendary$c in a legendary land"
assertState(after) assertState(after)
@ -173,9 +162,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v$" + "2gP")) typeText(injector.parser.parseKeys("v$" + "2gP"))
val after = "legendarylegendar${c}y" val after = "legendarylegendar${c}y"
assertState(after) assertState(after)
@ -187,9 +174,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}I found it in a legendary land" val before = "${c}I found it in a legendary land"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "gP")) typeText(injector.parser.parseKeys("V" + "gP"))
val after = "legendary\n$c" val after = "legendary\n$c"
assertState(after) assertState(after)
@ -230,9 +215,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "zxcvbn\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '+', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("vl" + "\"+gp")) typeText(injector.parser.parseKeys("vl" + "\"+gp"))
val after = """ val after = """
q q
@ -260,9 +243,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
configureByText(before) configureByText(before)
val vimEditor = fixture.editor.vim injector.registerGroup.storeText('+', "zxcvbn\n", SelectionType.LINE_WISE)
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
injector.registerGroup.storeText(vimEditor, context, '+', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("vl" + "\"+gp")) typeText(injector.parser.parseKeys("vl" + "\"+gp"))
val after = """ val after = """
q q
@ -292,9 +273,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.BLOCK_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("<S-v>" + "gp")) typeText(injector.parser.parseKeys("<S-v>" + "gp"))
val after = """ val after = """
${c}fgh ${c}fgh
@ -320,9 +299,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
""".trimIndent() """.trimIndent()
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.LINE_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("<C-v>" + "h" + "gp")) typeText(injector.parser.parseKeys("<C-v>" + "h" + "gp"))
val after = """ val after = """
q q
@ -343,9 +320,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn" val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
val editor = configureByText(before) val editor = configureByText(before)
val vimEditor = editor.vim val vimEditor = editor.vim
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor) VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
val registerService = injector.registerGroup
registerService.storeText(vimEditor, context, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("v2e" + "2gp")) typeText(injector.parser.parseKeys("v2e" + "2gp"))
val after = "fghfgh$c fghfgh$c fghfgh$c" val after = "fghfgh$c fghfgh$c fghfgh$c"
assertState(after) assertState(after)

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