mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-11-04 01:40:12 +01:00 
			
		
		
		
	Compare commits
	
		
			19 Commits
		
	
	
		
			f33589fbce
			...
			customized
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						3da1cc300f
	
				 | 
					
					
						|||
| 
						
						
							
						
						4d535c4148
	
				 | 
					
					
						|||
| 
						
						
							
						
						5768209a33
	
				 | 
					
					
						|||
| 
						
						
							
						
						fe0f4fde9d
	
				 | 
					
					
						|||
| 
						
						
							
						
						25e4eb9078
	
				 | 
					
					
						|||
| 
						
						
							
						
						9b507e6033
	
				 | 
					
					
						|||
| 
						
						
							
						
						4d0a54221a
	
				 | 
					
					
						|||
| 
						
						
							
						
						17d49bc35d
	
				 | 
					
					
						|||
| 
						
						
							
						
						ba9966d996
	
				 | 
					
					
						|||
| 
						
						
							
						
						ae1cb45854
	
				 | 
					
					
						|||
| 
						
						
							
						
						27c8d9e610
	
				 | 
					
					
						|||
| 
						
						
							
						
						5a247843e4
	
				 | 
					
					
						|||
| 
						
						
							
						
						4438c654d0
	
				 | 
					
					
						|||
| 
						
						
							
						
						705530fdfd
	
				 | 
					
					
						|||
| 
						
						
							
						
						a1c0cfda52
	
				 | 
					
					
						|||
| 
						
						
							
						
						9261d17491
	
				 | 
					
					
						|||
| 
						
						
							
						
						c89099bb0c
	
				 | 
					
					
						|||
| 
						
						
							
						
						00f73f52bd
	
				 | 
					
					
						|||
| 
						
						
							
						
						b0474cec7d
	
				 | 
					
					
						
							
								
								
									
										3
									
								
								.github/workflows/closeYoutrackOnCommit.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/closeYoutrackOnCommit.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,9 +8,6 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches: [ master ]
 | 
					    branches: [ master ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
permissions:
 | 
					 | 
				
			||||||
  contents: write
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							@@ -20,11 +20,6 @@ on:
 | 
				
			|||||||
  schedule:
 | 
					  schedule:
 | 
				
			||||||
    - cron: '44 12 * * 4'
 | 
					    - cron: '44 12 * * 4'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
permissions:
 | 
					 | 
				
			||||||
  actions: read
 | 
					 | 
				
			||||||
  contents: read
 | 
					 | 
				
			||||||
  security-events: write
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  analyze:
 | 
					  analyze:
 | 
				
			||||||
    name: Analyze
 | 
					    name: Analyze
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								.github/workflows/syncDoc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/syncDoc.yml
									
									
									
									
										vendored
									
									
								
							@@ -10,9 +10,6 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches: [ master ]
 | 
					    branches: [ master ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
permissions:
 | 
					 | 
				
			||||||
  contents: write
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,17 +34,6 @@ jobs:
 | 
				
			|||||||
        id: update_authors
 | 
					        id: update_authors
 | 
				
			||||||
        run: cp -a origin/doc/. docs
 | 
					        run: cp -a origin/doc/. docs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # The Wiki for github should have no `.md` in references
 | 
					 | 
				
			||||||
      # Otherwise, such links will lead to the raw text.
 | 
					 | 
				
			||||||
      # However, the `.md` should exist to have a navigation in GitHub code.
 | 
					 | 
				
			||||||
      - name: Replace `.md)` with `)`
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          # Define the directory you want to process
 | 
					 | 
				
			||||||
          DIRECTORY="docs"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          # Find all files in the directory and perform the replacement
 | 
					 | 
				
			||||||
          find $DIRECTORY -type f -exec sed -i 's/\.md)/)/g' {} +
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Commit changes
 | 
					      - name: Commit changes
 | 
				
			||||||
        uses: stefanzweifel/git-auto-commit-action@v4
 | 
					        uses: stefanzweifel/git-auto-commit-action@v4
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -27,6 +27,9 @@
 | 
				
			|||||||
# Generated by gradle task "generateGrammarSource"
 | 
					# Generated by gradle task "generateGrammarSource"
 | 
				
			||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
					vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
				
			||||||
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
					vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
				
			||||||
 | 
					# Generated JSONs for lazy classloading
 | 
				
			||||||
 | 
					/vim-engine/src/main/resources/ksp-generated
 | 
				
			||||||
 | 
					/src/main/resources/ksp-generated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Created by github automation
 | 
					# Created by github automation
 | 
				
			||||||
settings.xml
 | 
					settings.xml
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							@@ -5,12 +5,13 @@ object Constants {
 | 
				
			|||||||
  const val EAP_CHANNEL = "eap"
 | 
					  const val EAP_CHANNEL = "eap"
 | 
				
			||||||
  const val DEV_CHANNEL = "Dev"
 | 
					  const val DEV_CHANNEL = "Dev"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const val NVIM_TESTS = "2024.2.1"
 | 
					  const val GITHUB_TESTS = "2024.1.1"
 | 
				
			||||||
  const val PROPERTY_TESTS = "2024.2.1"
 | 
					  const val NVIM_TESTS = "2024.1.1"
 | 
				
			||||||
  const val LONG_RUNNING_TESTS = "2024.2.1"
 | 
					  const val PROPERTY_TESTS = "2024.1.1"
 | 
				
			||||||
  const val QODANA_TESTS = "2024.2.1"
 | 
					  const val LONG_RUNNING_TESTS = "2024.1.1"
 | 
				
			||||||
  const val RELEASE = "2024.2.1"
 | 
					  const val QODANA_TESTS = "2024.1.1"
 | 
				
			||||||
 | 
					  const val RELEASE = "2024.1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const val RELEASE_DEV = "2024.2.1"
 | 
					  const val RELEASE_DEV = "2024.1.1"
 | 
				
			||||||
  const val RELEASE_EAP = "2024.2.1"
 | 
					  const val RELEASE_EAP = "2024.1.1"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							@@ -8,6 +8,7 @@ import _Self.buildTypes.PropertyBased
 | 
				
			|||||||
import _Self.buildTypes.Qodana
 | 
					import _Self.buildTypes.Qodana
 | 
				
			||||||
import _Self.buildTypes.TestingBuildType
 | 
					import _Self.buildTypes.TestingBuildType
 | 
				
			||||||
import _Self.subprojects.GitHub
 | 
					import _Self.subprojects.GitHub
 | 
				
			||||||
 | 
					import _Self.subprojects.OldTests
 | 
				
			||||||
import _Self.subprojects.Releases
 | 
					import _Self.subprojects.Releases
 | 
				
			||||||
import _Self.vcsRoots.GitHubPullRequest
 | 
					import _Self.vcsRoots.GitHubPullRequest
 | 
				
			||||||
import _Self.vcsRoots.ReleasesVcsRoot
 | 
					import _Self.vcsRoots.ReleasesVcsRoot
 | 
				
			||||||
@@ -17,7 +18,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.Project
 | 
				
			|||||||
object Project : Project({
 | 
					object Project : Project({
 | 
				
			||||||
  description = "Vim engine for JetBrains IDEs"
 | 
					  description = "Vim engine for JetBrains IDEs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  subProjects(Releases, GitHub)
 | 
					  subProjects(Releases, OldTests, GitHub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // VCS roots
 | 
					  // VCS roots
 | 
				
			||||||
  vcsRoot(GitHubPullRequest)
 | 
					  vcsRoot(GitHubPullRequest)
 | 
				
			||||||
@@ -25,7 +26,7 @@ object Project : Project({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Active tests
 | 
					  // Active tests
 | 
				
			||||||
  buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
					  buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
				
			||||||
  buildType(TestingBuildType("2024.2.1", "<default>"))
 | 
					  buildType(TestingBuildType("2024.1.1", "<default>"))
 | 
				
			||||||
  buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
					  buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  buildType(PropertyBased)
 | 
					  buildType(PropertyBased)
 | 
				
			||||||
@@ -42,9 +43,6 @@ object Project : Project({
 | 
				
			|||||||
abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
 | 
					abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
 | 
				
			||||||
  artifactRules = """
 | 
					  artifactRules = """
 | 
				
			||||||
        +:build/reports => build/reports
 | 
					        +:build/reports => build/reports
 | 
				
			||||||
        +:tests/java-tests/build/reports => java-tests/build/reports
 | 
					 | 
				
			||||||
        +:tests/long-running-tests/build/reports => long-running-tests/build/reports
 | 
					 | 
				
			||||||
        +:tests/property-tests/build/reports => property-tests/build/reports
 | 
					 | 
				
			||||||
        +:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
 | 
					        +:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
 | 
				
			||||||
    """.trimIndent()
 | 
					    """.trimIndent()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,7 +52,7 @@ abstract class IdeaVimBuildType(init: BuildType.() -> Unit) : BuildType({
 | 
				
			|||||||
    // These requirements define Linux-Medium configuration.
 | 
					    // These requirements define Linux-Medium configuration.
 | 
				
			||||||
    // Unfortunately, requirement by name (teamcity.agent.name) doesn't work
 | 
					    // Unfortunately, requirement by name (teamcity.agent.name) doesn't work
 | 
				
			||||||
    //   IDK the reason for it, but on our agents this property is empty
 | 
					    //   IDK the reason for it, but on our agents this property is empty
 | 
				
			||||||
    equals("teamcity.agent.hardware.cpuCount", "16")
 | 
					    equals("teamcity.agent.hardware.cpuCount", "4")
 | 
				
			||||||
    equals("teamcity.agent.os.family", "Linux")
 | 
					    equals("teamcity.agent.os.family", "Linux")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.teamcity/_Self/buildTypes/Compatibility.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.teamcity/_Self/buildTypes/Compatibility.kt
									
									
									
									
										vendored
									
									
								
							@@ -40,9 +40,6 @@ object Compatibility : IdeaVimBuildType({
 | 
				
			|||||||
              # java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
 | 
					              # java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
 | 
				
			||||||
              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
 | 
					              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
 | 
				
			||||||
              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
 | 
					              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
 | 
				
			||||||
              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.peekaboo' [latest-IU] -team-city
 | 
					 | 
				
			||||||
              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.switch' [latest-IU] -team-city
 | 
					 | 
				
			||||||
              java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}com.julienphalip.ideavim.functiontextobj' [latest-IU] -team-city
 | 
					 | 
				
			||||||
            """.trimIndent()
 | 
					            """.trimIndent()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ object ReleaseEapFromBranch : IdeaVimBuildType({
 | 
				
			|||||||
  vcs {
 | 
					  vcs {
 | 
				
			||||||
    root(ReleasesVcsRoot)
 | 
					    root(ReleasesVcsRoot)
 | 
				
			||||||
    branchFilter = """
 | 
					    branchFilter = """
 | 
				
			||||||
      +:heads/releases/*
 | 
					      +:heads/(releases/*)
 | 
				
			||||||
      """.trimIndent()
 | 
					      """.trimIndent()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    checkoutMode = CheckoutMode.AUTO
 | 
					    checkoutMode = CheckoutMode.AUTO
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,11 +39,9 @@ open class TestingBuildType(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  steps {
 | 
					  steps {
 | 
				
			||||||
    gradle {
 | 
					    gradle {
 | 
				
			||||||
      clearConditions()
 | 
					 | 
				
			||||||
      tasks = "clean test"
 | 
					      tasks = "clean test"
 | 
				
			||||||
      buildFile = ""
 | 
					      buildFile = ""
 | 
				
			||||||
      enableStacktrace = true
 | 
					      enableStacktrace = true
 | 
				
			||||||
      jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.teamcity/_Self/subprojects/GitHub.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.teamcity/_Self/subprojects/GitHub.kt
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,6 @@
 | 
				
			|||||||
package _Self.subprojects
 | 
					package _Self.subprojects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import _Self.Constants
 | 
				
			||||||
import _Self.IdeaVimBuildType
 | 
					import _Self.IdeaVimBuildType
 | 
				
			||||||
import _Self.vcsRoots.GitHubPullRequest
 | 
					import _Self.vcsRoots.GitHubPullRequest
 | 
				
			||||||
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
 | 
				
			||||||
@@ -24,6 +25,7 @@ class GithubBuildType(command: String, desc: String) : IdeaVimBuildType({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  params {
 | 
					  params {
 | 
				
			||||||
    param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
 | 
					    param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
 | 
				
			||||||
 | 
					    param("env.ORG_GRADLE_PROJECT_ideaVersion", Constants.GITHUB_TESTS)
 | 
				
			||||||
    param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
 | 
					    param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								.teamcity/_Self/subprojects/OldTests.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								.teamcity/_Self/subprojects/OldTests.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package _Self.subprojects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import _Self.buildTypes.TestingBuildType
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.Project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object OldTests : Project({
 | 
				
			||||||
 | 
					  name = "Old IdeaVim tests"
 | 
				
			||||||
 | 
					  description = "Tests for older versions of IJ"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2018.1", "181-182", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2018.2", "181-182", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2018.3", "183", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2019.1", "191-193", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2019.2", "191-193", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2019.3", "191-193", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2020.1", "201", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2020.2", "202", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2020.3", "203-212", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2021.1", "203-212", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2021.2.2", "203-212", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2021.3.2", "213-221", javaVersion = "1.8", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2022.2.3", branch = "222", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2023.1", "231-232", javaPlugin = false))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("IC-2023.2", "231-232", javaPlugin = false))
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										39
									
								
								.teamcity/patches/buildTypes/IdeaVimTests_Latest_EAP.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.teamcity/patches/buildTypes/IdeaVimTests_Latest_EAP.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package patches.buildTypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.*
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.GradleBuildStep
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					This patch script was generated by TeamCity on settings change in UI.
 | 
				
			||||||
 | 
					To apply the patch, change the buildType with id = 'IdeaVimTests_Latest_EAP'
 | 
				
			||||||
 | 
					accordingly, and delete the patch script.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					changeBuildType(RelativeId("IdeaVimTests_Latest_EAP")) {
 | 
				
			||||||
 | 
					    check(artifactRules == """
 | 
				
			||||||
 | 
					        +:build/reports => build/reports
 | 
				
			||||||
 | 
					        +:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
 | 
				
			||||||
 | 
					    """.trimIndent()) {
 | 
				
			||||||
 | 
					        "Unexpected option value: artifactRules = $artifactRules"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    artifactRules = """
 | 
				
			||||||
 | 
					        +:build/reports => build/reports
 | 
				
			||||||
 | 
					        +:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
 | 
				
			||||||
 | 
					        +:tests/java-tests/build/reports => tests/java-tests/build/reports
 | 
				
			||||||
 | 
					    """.trimIndent()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expectSteps {
 | 
				
			||||||
 | 
					        gradle {
 | 
				
			||||||
 | 
					            tasks = "clean test"
 | 
				
			||||||
 | 
					            buildFile = ""
 | 
				
			||||||
 | 
					            enableStacktrace = true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    steps {
 | 
				
			||||||
 | 
					        update<GradleBuildStep>(0) {
 | 
				
			||||||
 | 
					            clearConditions()
 | 
				
			||||||
 | 
					            jdkHome = "/usr/lib/jvm/java-17-amazon-corretto"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								.teamcity/patches/buildTypes/ReleaseEapFromBranch.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.teamcity/patches/buildTypes/ReleaseEapFromBranch.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package patches.buildTypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.*
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					This patch script was generated by TeamCity on settings change in UI.
 | 
				
			||||||
 | 
					To apply the patch, change the buildType with id = 'ReleaseEapFromBranch'
 | 
				
			||||||
 | 
					accordingly, and delete the patch script.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					changeBuildType(RelativeId("ReleaseEapFromBranch")) {
 | 
				
			||||||
 | 
					    vcs {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check(branchFilter == "+:heads/(releases/*)") {
 | 
				
			||||||
 | 
					            "Unexpected option value: branchFilter = $branchFilter"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        branchFilter = "heads/releases/*"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								AUTHORS.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								AUTHORS.md
									
									
									
									
									
								
							@@ -523,46 +523,6 @@ Contributors:
 | 
				
			|||||||
  [![icon][github]](https://github.com/LazyScaper)
 | 
					  [![icon][github]](https://github.com/LazyScaper)
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
  Jake
 | 
					  Jake
 | 
				
			||||||
* [![icon][mail]](mailto:the1xdeveloper@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/The1xDeveloper)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  The1xDeveloper
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:shaunewilliams@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/shaunlebron)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  shaun
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:i.i.babko@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/igorbabko)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Igor Babko
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:533601+felixwiemuth@users.noreply.github.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/felixwiemuth)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Felix Wiemuth
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:kirill.karnaukhov@jetbrains.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/kkarnauk)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Kirill Karnaukhov, 
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:sander.hestvik@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/SanderHestvik)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  SanderHestvik
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/gregsh)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Greg Shrago
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:jphalip@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/jphalip)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Julien Phalip
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:j.trimailovas@gmail.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/trimailov)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Justas Trimailovas, 
 | 
					 | 
				
			||||||
* [![icon][mail]](mailto:justast@wix.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/justast-wix)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Justas Trimailovas
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Previous contributors:
 | 
					Previous contributors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -574,10 +534,6 @@ Previous contributors:
 | 
				
			|||||||
  [![icon][github]](https://github.com/kevin70)
 | 
					  [![icon][github]](https://github.com/kevin70)
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
  kk
 | 
					  kk
 | 
				
			||||||
* [![icon][mail]](mailto:gregory.shrago@jetbrains.com)
 | 
					 | 
				
			||||||
  [![icon][github]](https://github.com/gregsh)
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
  Greg Shrago
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
If you are a contributor and your name is not listed here, feel free to
 | 
					If you are a contributor and your name is not listed here, feel free to
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,8 +27,8 @@ usual beta standards.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Since version 2.9.0, the changelog can be found on YouTrack
 | 
					Since version 2.9.0, the changelog can be found on YouTrack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [To Be Released](https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20)
 | 
					To Be Released: https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20
 | 
				
			||||||
* [Version Fixes](https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20%7BFix%20versions%7D%20asc)
 | 
					Latest Fixes: https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20updated%20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 2.9.0, 2024-02-20
 | 
					## 2.9.0, 2024-02-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,16 +62,12 @@ for a few days or send it to a friend for testing.
 | 
				
			|||||||
If you are looking for:
 | 
					If you are looking for:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Vim commands (`w`, `<C-O>`, `p`, etc.):
 | 
					- Vim commands (`w`, `<C-O>`, `p`, etc.):
 | 
				
			||||||
    - Any particular command:
 | 
					    - Any particular command: `package-info.java`.
 | 
				
			||||||
      - [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_commands.json)
 | 
					 | 
				
			||||||
      - [IdeaVim only commands](src/main/resources/ksp-generated/intellij_commands.json)
 | 
					 | 
				
			||||||
    - How commands are executed in common: `EditorActionHandlerBase`.
 | 
					    - How commands are executed in common: `EditorActionHandlerBase`.
 | 
				
			||||||
    - Key mapping: `KeyHandler.handleKey()`.
 | 
					    - Key mapping: `KeyHandler.handleKey()`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Ex commands (`:set`, `:s`, `:nohlsearch`):
 | 
					- Ex commands (`:set`, `:s`, `:nohlsearch`):
 | 
				
			||||||
    - Any particular command:
 | 
					    - Any particular ex command: package `com.maddyhome.idea.vim.ex.handler`.
 | 
				
			||||||
        - [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_ex_commands.json)
 | 
					 | 
				
			||||||
        - [IdeaVim only commands](src/main/resources/ksp-generated/intellij_ex_commands.json)
 | 
					 | 
				
			||||||
    - Vim script grammar: `Vimscript.g4`.
 | 
					    - Vim script grammar: `Vimscript.g4`.
 | 
				
			||||||
    - Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
 | 
					    - Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
 | 
				
			||||||
    - Vim script executor: `Executor`.
 | 
					    - Vim script executor: `Executor`.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,6 +109,7 @@ etc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
See also:
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [The list of all supported commands](src/main/java/com/maddyhome/idea/vim/package-info.java)
 | 
				
			||||||
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
 | 
					* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
 | 
				
			||||||
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
 | 
					* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
 | 
				
			||||||
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
 | 
					* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ repositories {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  compileOnly("com.google.devtools.ksp:symbol-processing-api:2.1.0-1.0.29")
 | 
					  compileOnly("com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.24")
 | 
				
			||||||
  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") {
 | 
					  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlinxSerializationVersion") {
 | 
				
			||||||
    // kotlin stdlib is provided by IJ, so there is no need to include it into the distribution
 | 
					    // kotlin stdlib is provided by IJ, so there is no need to include it into the distribution
 | 
				
			||||||
    exclude("org.jetbrains.kotlin", "kotlin-stdlib")
 | 
					    exclude("org.jetbrains.kotlin", "kotlin-stdlib")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,7 @@ class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironme
 | 
				
			|||||||
    Files.createDirectories(generatedDirPath)
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
 | 
					    val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
 | 
				
			||||||
    val sortedCommands = commands.sortedWith(compareBy({ it.keys }, { it.`class` }))
 | 
					    val fileContent = json.encodeToString(commands)
 | 
				
			||||||
    val fileContent = json.encodeToString(sortedCommands)
 | 
					 | 
				
			||||||
    filePath.writeText(fileContent)
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return emptyList()
 | 
					    return emptyList()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,7 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
 | 
				
			|||||||
    Files.createDirectories(generatedDirPath)
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
 | 
					    val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
 | 
				
			||||||
    val sortedCommandToClass = commandToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
 | 
					    val fileContent = json.encodeToString(commandToClass)
 | 
				
			||||||
    val fileContent = json.encodeToString(sortedCommandToClass)
 | 
					 | 
				
			||||||
    filePath.writeText(fileContent)
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return emptyList()
 | 
					    return emptyList()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,7 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
 | 
				
			|||||||
    Files.createDirectories(generatedDirPath)
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
 | 
					    val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
 | 
				
			||||||
    val sortedNameToClass = nameToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
 | 
					    val fileContent = json.encodeToString(nameToClass)
 | 
				
			||||||
    val fileContent = json.encodeToString(sortedNameToClass)
 | 
					 | 
				
			||||||
    filePath.writeText(fileContent)
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return emptyList()
 | 
					    return emptyList()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,14 +50,14 @@ buildscript {
 | 
				
			|||||||
    classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
					    classpath("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This is needed for jgit to connect to ssh
 | 
					    // This is needed for jgit to connect to ssh
 | 
				
			||||||
    classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r")
 | 
					    classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
 | 
				
			||||||
    classpath("org.kohsuke:github-api:1.305")
 | 
					    classpath("org.kohsuke:github-api:1.305")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    classpath("io.ktor:ktor-client-core:3.0.2")
 | 
					    classpath("io.ktor:ktor-client-core:2.3.12")
 | 
				
			||||||
    classpath("io.ktor:ktor-client-cio:3.0.2")
 | 
					    classpath("io.ktor:ktor-client-cio:2.3.10")
 | 
				
			||||||
    classpath("io.ktor:ktor-client-auth:3.0.2")
 | 
					    classpath("io.ktor:ktor-client-auth:2.3.12")
 | 
				
			||||||
    classpath("io.ktor:ktor-client-content-negotiation:3.0.2")
 | 
					    classpath("io.ktor:ktor-client-content-negotiation:2.3.10")
 | 
				
			||||||
    classpath("io.ktor:ktor-serialization-kotlinx-json:3.0.2")
 | 
					    classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This comes from the changelog plugin
 | 
					    // This comes from the changelog plugin
 | 
				
			||||||
//        classpath("org.jetbrains:markdown:0.3.1")
 | 
					//        classpath("org.jetbrains:markdown:0.3.1")
 | 
				
			||||||
@@ -69,7 +69,7 @@ plugins {
 | 
				
			|||||||
  kotlin("jvm") version "2.0.0"
 | 
					  kotlin("jvm") version "2.0.0"
 | 
				
			||||||
  application
 | 
					  application
 | 
				
			||||||
  id("java-test-fixtures")
 | 
					  id("java-test-fixtures")
 | 
				
			||||||
  id("org.jetbrains.intellij.platform") version "2.2.0"
 | 
					  id("org.jetbrains.intellij.platform") version "2.0.0-rc2"
 | 
				
			||||||
  id("org.jetbrains.changelog") version "2.2.1"
 | 
					  id("org.jetbrains.changelog") version "2.2.1"
 | 
				
			||||||
  id("org.jetbrains.kotlinx.kover") version "0.6.1"
 | 
					  id("org.jetbrains.kotlinx.kover") version "0.6.1"
 | 
				
			||||||
  id("com.dorongold.task-tree") version "4.0.0"
 | 
					  id("com.dorongold.task-tree") version "4.0.0"
 | 
				
			||||||
@@ -85,6 +85,7 @@ val ideaVersion: String by project
 | 
				
			|||||||
val ideaType: String by project
 | 
					val ideaType: String by project
 | 
				
			||||||
val instrumentPluginCode: String by project
 | 
					val instrumentPluginCode: String by project
 | 
				
			||||||
val remoteRobotVersion: String by project
 | 
					val remoteRobotVersion: String by project
 | 
				
			||||||
 | 
					val splitModeVersion: String by project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val publishChannels: String by project
 | 
					val publishChannels: String by project
 | 
				
			||||||
val publishToken: String by project
 | 
					val publishToken: String by project
 | 
				
			||||||
@@ -107,17 +108,13 @@ dependencies {
 | 
				
			|||||||
  compileOnly(project(":annotation-processors"))
 | 
					  compileOnly(project(":annotation-processors"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
 | 
					  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
 | 
				
			||||||
  compileOnly("org.jetbrains:annotations:26.0.1")
 | 
					  compileOnly("org.jetbrains:annotations:24.1.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  intellijPlatform {
 | 
					  intellijPlatform {
 | 
				
			||||||
    // Snapshots don't use installers
 | 
					 | 
				
			||||||
    // https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html#target-versions-installers
 | 
					 | 
				
			||||||
    val useInstaller = "EAP-SNAPSHOT" !in ideaVersion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Note that it is also possible to use local("...") to compile against a locally installed IDE
 | 
					    // Note that it is also possible to use local("...") to compile against a locally installed IDE
 | 
				
			||||||
    // E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
 | 
					    // E.g. local("/Users/{user}/Applications/IntelliJ IDEA Ultimate.app")
 | 
				
			||||||
    // Or something like: intellijIdeaUltimate(ideaVersion)
 | 
					    // Or something like: intellijIdeaUltimate(ideaVersion)
 | 
				
			||||||
    create(ideaType, ideaVersion, useInstaller)
 | 
					    create(ideaType, ideaVersion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pluginVerifier()
 | 
					    pluginVerifier()
 | 
				
			||||||
    zipSigner()
 | 
					    zipSigner()
 | 
				
			||||||
@@ -128,7 +125,6 @@ dependencies {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // AceJump is an optional dependency. We use their SessionManager class to check if it's active
 | 
					    // AceJump is an optional dependency. We use their SessionManager class to check if it's active
 | 
				
			||||||
    plugin("AceJump", "3.8.19")
 | 
					    plugin("AceJump", "3.8.19")
 | 
				
			||||||
    plugin("com.intellij.classic.ui", "242.20224.159")
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
 | 
					  moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
 | 
				
			||||||
@@ -150,17 +146,17 @@ dependencies {
 | 
				
			|||||||
  // https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
 | 
					  // https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
 | 
				
			||||||
  testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
 | 
					  testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5")
 | 
					  testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
 | 
				
			||||||
  testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5")
 | 
					  testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
 | 
				
			||||||
  testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5")
 | 
					  testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
 | 
				
			||||||
  testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.5")
 | 
					  testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
 | 
				
			||||||
  testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.5")
 | 
					  testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.3")
 | 
				
			||||||
  testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.5")
 | 
					  testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Temp workaround suggested in https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4
 | 
					  // Temp workaround suggested in https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4
 | 
				
			||||||
  // Can be removed when IJPL-159134 is fixed
 | 
					  // Can be removed when IJPL-159134 is fixed
 | 
				
			||||||
//  testRuntimeOnly("junit:junit:4.13.2")
 | 
					//  testRuntimeOnly("junit:junit:4.13.2")
 | 
				
			||||||
  testImplementation("org.junit.vintage:junit-vintage-engine:5.10.5")
 | 
					  testImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
 | 
				
			||||||
//  testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
 | 
					//  testFixturesImplementation("org.junit.vintage:junit-vintage-engine:5.10.3")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -214,8 +210,6 @@ tasks {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  compileTestKotlin {
 | 
					  compileTestKotlin {
 | 
				
			||||||
    enabled = false
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    kotlinOptions {
 | 
					    kotlinOptions {
 | 
				
			||||||
      jvmTarget = javaVersion
 | 
					      jvmTarget = javaVersion
 | 
				
			||||||
      apiVersion = "1.9"
 | 
					      apiVersion = "1.9"
 | 
				
			||||||
@@ -235,7 +229,6 @@ tasks {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
 | 
					  // Uncomment to run the plugin in a custom IDE, rather than the IDE specified as a compile target in dependencies
 | 
				
			||||||
  // Note that the version must be greater than the plugin's target version, for obvious reasons
 | 
					  // Note that the version must be greater than the plugin's target version, for obvious reasons
 | 
				
			||||||
  // You can also set splitMode and splitModeTarget here to test split mode in a custom IDE
 | 
					 | 
				
			||||||
//  val runIdeCustom by intellijPlatformTesting.runIde.registering {
 | 
					//  val runIdeCustom by intellijPlatformTesting.runIde.registering {
 | 
				
			||||||
//    type = IntelliJPlatformType.Rider
 | 
					//    type = IntelliJPlatformType.Rider
 | 
				
			||||||
//    version = "2024.1.2"
 | 
					//    version = "2024.1.2"
 | 
				
			||||||
@@ -268,6 +261,10 @@ tasks {
 | 
				
			|||||||
  val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
 | 
					  val runIdeSplitMode by intellijPlatformTesting.runIde.registering {
 | 
				
			||||||
    splitMode = true
 | 
					    splitMode = true
 | 
				
			||||||
    splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
 | 
					    splitModeTarget = SplitModeAware.SplitModeTarget.FRONTEND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Frontend split mode support requires 242+
 | 
				
			||||||
 | 
					    // TODO: Remove this once IdeaVim targets 242, as the task will naturally use the target version to run
 | 
				
			||||||
 | 
					    version.set(splitModeVersion)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Add plugin open API sources to the plugin ZIP
 | 
					  // Add plugin open API sources to the plugin ZIP
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -322,9 +322,6 @@ If you want to optimize highlight duration, assign a time in milliseconds:
 | 
				
			|||||||
If you want to change background color of highlight you can provide the rgba of the color you want e.g.  
 | 
					If you want to change background color of highlight you can provide the rgba of the color you want e.g.  
 | 
				
			||||||
      `let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"`
 | 
					      `let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"`
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
If you want to change text color of highlight you can provide the rgba of the color you want e.g.  
 | 
					 | 
				
			||||||
`let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt
 | 
					https://github.com/machakann/vim-highlightedyank/blob/master/doc/highlightedyank.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</details>
 | 
					</details>
 | 
				
			||||||
@@ -438,50 +435,3 @@ Original plugin: [vim-which-key](https://github.com/liuchengxu/vim-which-key).
 | 
				
			|||||||
https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation
 | 
					https://github.com/TheBlob42/idea-which-key?tab=readme-ov-file#installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</details>
 | 
					</details>
 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary><h2>Vim Peekaboo</h2></summary>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
By Julien Phalip  
 | 
					 | 
				
			||||||
Original plugin: [vim-peekaboo](https://github.com/junegunn/vim-peekaboo).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Add `set peekaboo` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
 | 
					 | 
				
			||||||
or restart the IDE.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Instructions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary><h2>FunctionTextObj</h2></summary>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
By Julien Phalip  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Add `set functiontextobj` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
 | 
					 | 
				
			||||||
or restart the IDE.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Instructions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary><h2>Switch</h2></summary>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
By Julien Phalip  
 | 
					 | 
				
			||||||
Original plugin: [switch.vim](https://github.com/AndrewRadev/switch.vim).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Add `set switch` to your `~/.ideavimrc` file, then run `:source ~/.ideavimrc`
 | 
					 | 
				
			||||||
or restart the IDE.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Instructions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
https://plugins.jetbrains.com/plugin/25899-vim-switch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ Every effort is made to make these options compatible with Vim behaviour.
 | 
				
			|||||||
However, some differences are inevitable.
 | 
					However, some differences are inevitable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
'clipboard'     'cb'    Defines clipboard behavior
 | 
					'clipboard'     'cb'    Defines clipboard behavioue
 | 
				
			||||||
        A comma-separated list of words to control clipboard behaviour:
 | 
					        A comma-separated list of words to control clipboard behaviour:
 | 
				
			||||||
           unnamed      The clipboard register '*' is used instead of the
 | 
					           unnamed      The clipboard register '*' is used instead of the
 | 
				
			||||||
                        unnamed register
 | 
					                        unnamed register
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
# Support Guide
 | 
					# Support Guide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This document is created to help our support team.
 | 
					This document is created to help our support team.
 | 
				
			||||||
It's not intended to be read by the users as it brings no value to them.
 | 
					It's not intended to be read by the users as it brings to value to them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Support channels
 | 
					## Support channels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +25,7 @@ It's not intended to be read by the users as it brings no value to them.
 | 
				
			|||||||
IdeaVim has multiple YouTrack statuses, main are:
 | 
					IdeaVim has multiple YouTrack statuses, main are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets.
 | 
					- Submitted: issue is created by user, but not processed by our team. This is the default status for new tickets.
 | 
				
			||||||
- Open: issues is processed by our team, what means that the issues is reproduced and accepted
 | 
					- Open: issues is processed by out team, what means that the issues is reproduced and accepted
 | 
				
			||||||
- Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the
 | 
					- Waiting For Reply: Waiting for further information from the user. These issues are automatically closed if the
 | 
				
			||||||
     user doesn't reply in 30 days.
 | 
					     user doesn't reply in 30 days.
 | 
				
			||||||
- Ready To Release: Bug is fixed, but not yet released
 | 
					- Ready To Release: Bug is fixed, but not yet released
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,11 +20,17 @@ ideaVersion=2024.2
 | 
				
			|||||||
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
 | 
					# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
 | 
				
			||||||
ideaType=IC
 | 
					ideaType=IC
 | 
				
			||||||
instrumentPluginCode=true
 | 
					instrumentPluginCode=true
 | 
				
			||||||
version=chylex-42
 | 
					version=chylex-38
 | 
				
			||||||
javaVersion=17
 | 
					javaVersion=17
 | 
				
			||||||
remoteRobotVersion=0.11.23
 | 
					remoteRobotVersion=0.11.23
 | 
				
			||||||
antlrVersion=4.10.1
 | 
					antlrVersion=4.10.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# [VERSION UPDATE] 2024.2 - remove when IdeaVim targets 2024.2
 | 
				
			||||||
 | 
					# Running IdeaVim in split mode requires 242. Update this version once 242 has been released, and remove it completely
 | 
				
			||||||
 | 
					# when IdeaVim targets 242, at which point runIdeSplitMode will run correctly with the target version.
 | 
				
			||||||
 | 
					# See also runIdeSplitMode
 | 
				
			||||||
 | 
					splitModeVersion=242-EAP-SNAPSHOT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Please don't forget to update kotlin version in buildscript section
 | 
					# Please don't forget to update kotlin version in buildscript section
 | 
				
			||||||
# Also update kotlinxSerializationVersion version
 | 
					# Also update kotlinxSerializationVersion version
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
distributionBase=GRADLE_USER_HOME
 | 
					distributionBase=GRADLE_USER_HOME
 | 
				
			||||||
distributionPath=wrapper/dists
 | 
					distributionPath=wrapper/dists
 | 
				
			||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
 | 
					distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
 | 
				
			||||||
networkTimeout=10000
 | 
					networkTimeout=10000
 | 
				
			||||||
validateDistributionUrl=true
 | 
					validateDistributionUrl=true
 | 
				
			||||||
zipStoreBase=GRADLE_USER_HOME
 | 
					zipStoreBase=GRADLE_USER_HOME
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							@@ -15,8 +15,6 @@
 | 
				
			|||||||
# See the License for the specific language governing permissions and
 | 
					# See the License for the specific language governing permissions and
 | 
				
			||||||
# limitations under the License.
 | 
					# limitations under the License.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
##############################################################################
 | 
					##############################################################################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -57,7 +55,7 @@
 | 
				
			|||||||
#       Darwin, MinGW, and NonStop.
 | 
					#       Darwin, MinGW, and NonStop.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#   (3) This script is generated from the Groovy template
 | 
					#   (3) This script is generated from the Groovy template
 | 
				
			||||||
#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
					#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
				
			||||||
#       within the Gradle project.
 | 
					#       within the Gradle project.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#       You can find Gradle at https://github.com/gradle/gradle/.
 | 
					#       You can find Gradle at https://github.com/gradle/gradle/.
 | 
				
			||||||
@@ -85,9 +83,7 @@ done
 | 
				
			|||||||
# This is normally unused
 | 
					# This is normally unused
 | 
				
			||||||
# shellcheck disable=SC2034
 | 
					# shellcheck disable=SC2034
 | 
				
			||||||
APP_BASE_NAME=${0##*/}
 | 
					APP_BASE_NAME=${0##*/}
 | 
				
			||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
 | 
					APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 | 
				
			||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
 | 
					 | 
				
			||||||
' "$PWD" ) || exit
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
					# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
				
			||||||
MAX_FD=maximum
 | 
					MAX_FD=maximum
 | 
				
			||||||
@@ -148,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
 | 
				
			|||||||
    case $MAX_FD in #(
 | 
					    case $MAX_FD in #(
 | 
				
			||||||
      max*)
 | 
					      max*)
 | 
				
			||||||
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
 | 
					        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
 | 
				
			||||||
        # shellcheck disable=SC2039,SC3045
 | 
					        # shellcheck disable=SC3045
 | 
				
			||||||
        MAX_FD=$( ulimit -H -n ) ||
 | 
					        MAX_FD=$( ulimit -H -n ) ||
 | 
				
			||||||
            warn "Could not query maximum file descriptor limit"
 | 
					            warn "Could not query maximum file descriptor limit"
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
@@ -156,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
 | 
				
			|||||||
      '' | soft) :;; #(
 | 
					      '' | soft) :;; #(
 | 
				
			||||||
      *)
 | 
					      *)
 | 
				
			||||||
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
 | 
					        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
 | 
				
			||||||
        # shellcheck disable=SC2039,SC3045
 | 
					        # shellcheck disable=SC3045
 | 
				
			||||||
        ulimit -n "$MAX_FD" ||
 | 
					        ulimit -n "$MAX_FD" ||
 | 
				
			||||||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
 | 
					            warn "Could not set maximum file descriptor limit to $MAX_FD"
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
@@ -205,11 +201,11 @@ fi
 | 
				
			|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
					# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
				
			||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
					DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Collect all arguments for the java command:
 | 
					# Collect all arguments for the java command;
 | 
				
			||||||
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
 | 
					#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
 | 
				
			||||||
#     and any embedded shellness will be escaped.
 | 
					#     shell script including quotes and variable substitutions, so put them in
 | 
				
			||||||
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
 | 
					#     double quotes to make sure that they get re-expanded; and
 | 
				
			||||||
#     treated as '${Hostname}' itself on the command line.
 | 
					#   * put everything else in single quotes, so that it's not re-expanded.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -- \
 | 
					set -- \
 | 
				
			||||||
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
 | 
					        "-Dorg.gradle.appname=$APP_BASE_NAME" \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							@@ -13,8 +13,6 @@
 | 
				
			|||||||
@rem See the License for the specific language governing permissions and
 | 
					@rem See the License for the specific language governing permissions and
 | 
				
			||||||
@rem limitations under the License.
 | 
					@rem limitations under the License.
 | 
				
			||||||
@rem
 | 
					@rem
 | 
				
			||||||
@rem SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
@rem
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if "%DEBUG%"=="" @echo off
 | 
					@if "%DEBUG%"=="" @echo off
 | 
				
			||||||
@rem ##########################################################################
 | 
					@rem ##########################################################################
 | 
				
			||||||
@@ -45,11 +43,11 @@ set JAVA_EXE=java.exe
 | 
				
			|||||||
%JAVA_EXE% -version >NUL 2>&1
 | 
					%JAVA_EXE% -version >NUL 2>&1
 | 
				
			||||||
if %ERRORLEVEL% equ 0 goto execute
 | 
					if %ERRORLEVEL% equ 0 goto execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo. 1>&2
 | 
					echo.
 | 
				
			||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
 | 
					echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
				
			||||||
echo. 1>&2
 | 
					echo.
 | 
				
			||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
 | 
					echo Please set the JAVA_HOME variable in your environment to match the
 | 
				
			||||||
echo location of your Java installation. 1>&2
 | 
					echo location of your Java installation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
goto fail
 | 
					goto fail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if exist "%JAVA_EXE%" goto execute
 | 
					if exist "%JAVA_EXE%" goto execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo. 1>&2
 | 
					echo.
 | 
				
			||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
 | 
					echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
 | 
				
			||||||
echo. 1>&2
 | 
					echo.
 | 
				
			||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
 | 
					echo Please set the JAVA_HOME variable in your environment to match the
 | 
				
			||||||
echo location of your Java installation. 1>&2
 | 
					echo location of your Java installation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
goto fail
 | 
					goto fail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ exclude:
 | 
				
			|||||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
 | 
					      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
 | 
				
			||||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
 | 
					      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
 | 
				
			||||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
 | 
					      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
 | 
				
			||||||
 | 
					      - src/main/java/com/maddyhome/idea/vim/package-info.java
 | 
				
			||||||
      - vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
					      - vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
				
			||||||
      - vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
					      - vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
				
			||||||
      - src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
 | 
					      - src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,17 +20,17 @@ repositories {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
 | 
					  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.25")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation("io.ktor:ktor-client-core:3.0.2")
 | 
					  implementation("io.ktor:ktor-client-core:2.3.12")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-cio:3.0.2")
 | 
					  implementation("io.ktor:ktor-client-cio:2.3.10")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-content-negotiation:3.0.2")
 | 
					  implementation("io.ktor:ktor-client-content-negotiation:2.3.10")
 | 
				
			||||||
  implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.2")
 | 
					  implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-auth:3.0.2")
 | 
					  implementation("io.ktor:ktor-client-auth:2.3.12")
 | 
				
			||||||
  implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
					  implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This is needed for jgit to connect to ssh
 | 
					  // This is needed for jgit to connect to ssh
 | 
				
			||||||
  implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r")
 | 
					  implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.10.0.202406032230-r")
 | 
				
			||||||
  implementation("com.vdurmont:semver4j:3.1.0")
 | 
					  implementation("com.vdurmont:semver4j:3.1.0")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,9 +40,6 @@ val knownPlugins = setOf(
 | 
				
			|||||||
  "com.protoseo.input-source-auto-converter",
 | 
					  "com.protoseo.input-source-auto-converter",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//   "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
 | 
					//   "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
 | 
				
			||||||
  "com.julienphalip.ideavim.peekaboo", // https://plugins.jetbrains.com/plugin/25776-vim-peekaboo
 | 
					 | 
				
			||||||
  "com.julienphalip.ideavim.switch", // https://plugins.jetbrains.com/plugin/25899-vim-switch
 | 
					 | 
				
			||||||
  "com.julienphalip.ideavim.functiontextobj", // https://plugins.jetbrains.com/plugin/25897-vim-functiontextobj
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend fun main() {
 | 
					suspend fun main() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim
 | 
					package com.maddyhome.idea.vim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.ide.BrowserUtil
 | 
					 | 
				
			||||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
 | 
					 | 
				
			||||||
import com.intellij.ide.plugins.PluginStateListener
 | 
					 | 
				
			||||||
import com.intellij.ide.plugins.PluginStateManager
 | 
					 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
					import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
@@ -33,9 +29,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private var firstInitializationOccurred = false
 | 
					  private var firstInitializationOccurred = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO
 | 
					 | 
				
			||||||
  // We should migrate to some solution from https://plugins.jetbrains.com/docs/intellij/plugin-components.html#application-startup
 | 
					 | 
				
			||||||
  // If you'd like to add a new code here, please consider using one of the things described there.
 | 
					 | 
				
			||||||
  override suspend fun execute(project: Project) {
 | 
					  override suspend fun execute(project: Project) {
 | 
				
			||||||
    if (firstInitializationOccurred) return
 | 
					    if (firstInitializationOccurred) return
 | 
				
			||||||
    firstInitializationOccurred = true
 | 
					    firstInitializationOccurred = true
 | 
				
			||||||
@@ -47,18 +40,6 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // This code should be executed once
 | 
					    // This code should be executed once
 | 
				
			||||||
    VimPlugin.getInstance().initialize()
 | 
					    VimPlugin.getInstance().initialize()
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Uninstall survey. Should be registered once for all projects
 | 
					 | 
				
			||||||
    PluginStateManager.addStateListener(object : PluginStateListener {
 | 
					 | 
				
			||||||
      override fun install(p0: IdeaPluginDescriptor) {/*Nothing*/
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      override fun uninstall(descriptor: IdeaPluginDescriptor) {
 | 
					 | 
				
			||||||
        if (descriptor.pluginId == VimPlugin.getPluginId()) {
 | 
					 | 
				
			||||||
          BrowserUtil.open("https://surveys.jetbrains.com/s3/ideavim-uninstall-feedback")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ package com.maddyhome.idea.vim;
 | 
				
			|||||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
 | 
					import com.intellij.ide.plugins.IdeaPluginDescriptor;
 | 
				
			||||||
import com.intellij.ide.plugins.PluginManagerCore;
 | 
					import com.intellij.ide.plugins.PluginManagerCore;
 | 
				
			||||||
import com.intellij.openapi.Disposable;
 | 
					import com.intellij.openapi.Disposable;
 | 
				
			||||||
import com.intellij.openapi.application.AccessToken;
 | 
					 | 
				
			||||||
import com.intellij.openapi.application.Application;
 | 
					import com.intellij.openapi.application.Application;
 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager;
 | 
					import com.intellij.openapi.application.ApplicationManager;
 | 
				
			||||||
import com.intellij.openapi.components.PersistentStateComponent;
 | 
					import com.intellij.openapi.components.PersistentStateComponent;
 | 
				
			||||||
@@ -25,8 +24,10 @@ import com.intellij.openapi.project.Project;
 | 
				
			|||||||
import com.intellij.openapi.ui.Messages;
 | 
					import com.intellij.openapi.ui.Messages;
 | 
				
			||||||
import com.intellij.openapi.util.Disposer;
 | 
					import com.intellij.openapi.util.Disposer;
 | 
				
			||||||
import com.intellij.openapi.util.SystemInfo;
 | 
					import com.intellij.openapi.util.SystemInfo;
 | 
				
			||||||
import com.intellij.util.SlowOperations;
 | 
					import com.maddyhome.idea.vim.api.VimEditor;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.*;
 | 
					import com.maddyhome.idea.vim.api.VimInjectorKt;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimKeyGroup;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimOptionGroup;
 | 
				
			||||||
import com.maddyhome.idea.vim.config.VimState;
 | 
					import com.maddyhome.idea.vim.config.VimState;
 | 
				
			||||||
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
 | 
					import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
 | 
				
			||||||
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
 | 
					import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
 | 
				
			||||||
@@ -35,6 +36,7 @@ import com.maddyhome.idea.vim.group.copy.PutGroup;
 | 
				
			|||||||
import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
 | 
					import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
 | 
					import com.maddyhome.idea.vim.helper.MacKeyRepeat;
 | 
				
			||||||
import com.maddyhome.idea.vim.listener.VimListenerManager;
 | 
					import com.maddyhome.idea.vim.listener.VimListenerManager;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.IjVimInjector;
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
 | 
					import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup;
 | 
					import com.maddyhome.idea.vim.newapi.IjVimSearchGroup;
 | 
				
			||||||
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
 | 
					import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
 | 
				
			||||||
@@ -139,8 +141,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
 | 
				
			|||||||
    return (MacroGroup)VimInjectorKt.getInjector().getMacro();
 | 
					    return (MacroGroup)VimInjectorKt.getInjector().getMacro();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public static @NotNull VimDigraphGroup getDigraph() {
 | 
					  public static @NotNull DigraphGroup getDigraph() {
 | 
				
			||||||
    return VimInjectorKt.getInjector().getDigraphGroup();
 | 
					    return (DigraphGroup)VimInjectorKt.getInjector().getDigraphGroup();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public static @NotNull HistoryGroup getHistory() {
 | 
					  public static @NotNull HistoryGroup getHistory() {
 | 
				
			||||||
@@ -337,9 +339,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // 4) ~/.ideavimrc execution
 | 
					    // 4) ~/.ideavimrc execution
 | 
				
			||||||
    // Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
 | 
					    // Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
 | 
				
			||||||
    try (AccessToken ignore = SlowOperations.knownIssue("VIM-3661")) {
 | 
					    registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
 | 
				
			||||||
      registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Turing on should be performed after all commands registration
 | 
					    // Turing on should be performed after all commands registration
 | 
				
			||||||
    getSearch().turnOn();
 | 
					    getSearch().turnOn();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,52 +0,0 @@
 | 
				
			|||||||
package com.maddyhome.idea.vim.action
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
					 | 
				
			||||||
import com.intellij.openapi.actionSystem.AnActionEvent
 | 
					 | 
				
			||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
					 | 
				
			||||||
import com.intellij.openapi.command.WriteCommandAction
 | 
					 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
					 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
					 | 
				
			||||||
import com.intellij.openapi.project.DumbAwareAction
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VimRunLastMacroInOpenFiles : DumbAwareAction() {
 | 
					 | 
				
			||||||
  override fun update(e: AnActionEvent) {
 | 
					 | 
				
			||||||
    val lastRegister = injector.macro.lastRegister
 | 
					 | 
				
			||||||
    val isEnabled = lastRegister != 0.toChar()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    e.presentation.isEnabled = isEnabled
 | 
					 | 
				
			||||||
    e.presentation.text = if (isEnabled) "Run Macro '${lastRegister}' in Open Files" else "Run Last Macro in Open Files"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun getActionUpdateThread(): ActionUpdateThread {
 | 
					 | 
				
			||||||
    return ActionUpdateThread.EDT
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun actionPerformed(e: AnActionEvent) {
 | 
					 | 
				
			||||||
    val project = e.project ?: return
 | 
					 | 
				
			||||||
    val fileEditorManager = FileEditorManagerEx.getInstanceExIfCreated(project) ?: return
 | 
					 | 
				
			||||||
    val editors = fileEditorManager.allEditors.filterIsInstance<TextEditor>()
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    WriteCommandAction.writeCommandAction(project)
 | 
					 | 
				
			||||||
      .withName(e.presentation.text)
 | 
					 | 
				
			||||||
      .withGlobalUndo()
 | 
					 | 
				
			||||||
      .withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION)
 | 
					 | 
				
			||||||
      .run<RuntimeException> {
 | 
					 | 
				
			||||||
        val reg = injector.macro.lastRegister
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        for (editor in editors) {
 | 
					 | 
				
			||||||
          fileEditorManager.openFile(editor.file, true)
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          val vimEditor = editor.editor.vim
 | 
					 | 
				
			||||||
          vimEditor.mode = Mode.NORMAL()
 | 
					 | 
				
			||||||
          KeyHandler.getInstance().reset(vimEditor)
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          injector.macro.playbackRegister(vimEditor, IjEditorExecutionContext(e.dataContext), reg, 1)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -298,10 +298,26 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
 | 
				
			|||||||
        .addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK))
 | 
					        .addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK))
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0))
 | 
					        .addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0))
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK))
 | 
					        .addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK))
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_UP, 0))
 | 
					        .addAll(getKeyStrokes(KeyEvent.VK_UP, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0))
 | 
					        .addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK))
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_LEFT, 0))
 | 
					        .addAll(
 | 
				
			||||||
        .addAll(getKeyStrokes(KeyEvent.VK_RIGHT, 0))
 | 
					          getKeyStrokes(
 | 
				
			||||||
 | 
					            KeyEvent.VK_LEFT,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            InputEvent.CTRL_DOWN_MASK,
 | 
				
			||||||
 | 
					            InputEvent.SHIFT_DOWN_MASK,
 | 
				
			||||||
 | 
					            InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .addAll(
 | 
				
			||||||
 | 
					          getKeyStrokes(
 | 
				
			||||||
 | 
					            KeyEvent.VK_RIGHT,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            InputEvent.CTRL_DOWN_MASK,
 | 
				
			||||||
 | 
					            InputEvent.SHIFT_DOWN_MASK,
 | 
				
			||||||
 | 
					            InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        .addAll(
 | 
					        .addAll(
 | 
				
			||||||
          getKeyStrokes(
 | 
					          getKeyStrokes(
 | 
				
			||||||
            KeyEvent.VK_HOME,
 | 
					            KeyEvent.VK_HOME,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
 | 
				
			|||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
 | 
					import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// todo make it multicaret
 | 
					// todo make it multicaret
 | 
				
			||||||
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, motionType: SelectionType): Boolean {
 | 
					private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
 | 
				
			||||||
  val func = injector.globalOptions().operatorfunc
 | 
					  val func = injector.globalOptions().operatorfunc
 | 
				
			||||||
  if (func.isEmpty()) {
 | 
					  if (func.isEmpty()) {
 | 
				
			||||||
    VimPlugin.showMessage(MessageHelper.message("E774"))
 | 
					    VimPlugin.showMessage(MessageHelper.message("E774"))
 | 
				
			||||||
@@ -57,9 +57,9 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
 | 
				
			|||||||
        if (value is VimFuncref) {
 | 
					        if (value is VimFuncref) {
 | 
				
			||||||
          handler = value.handler
 | 
					          handler = value.handler
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } catch (_: ExException) {
 | 
					      } catch (ex: ExException) {
 | 
				
			||||||
        // Get the argument for function('...') or funcref('...') for the error message
 | 
					        // Get the argument for function('...') or funcref('...') for the error message
 | 
				
			||||||
        val functionName = if (expression is FunctionCallExpression && expression.arguments.isNotEmpty()) {
 | 
					        val functionName = if (expression is FunctionCallExpression && expression.arguments.size > 0) {
 | 
				
			||||||
          expression.arguments[0].evaluate(editor, context, scriptContext).toString()
 | 
					          expression.arguments[0].evaluate(editor, context, scriptContext).toString()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
@@ -77,7 +77,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
 | 
				
			|||||||
    return false
 | 
					    return false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val arg = when (motionType) {
 | 
					  val arg = when (selectionType) {
 | 
				
			||||||
    SelectionType.LINE_WISE -> "line"
 | 
					    SelectionType.LINE_WISE -> "line"
 | 
				
			||||||
    SelectionType.CHARACTER_WISE -> "char"
 | 
					    SelectionType.CHARACTER_WISE -> "char"
 | 
				
			||||||
    SelectionType.BLOCK_WISE -> "block"
 | 
					    SelectionType.BLOCK_WISE -> "block"
 | 
				
			||||||
@@ -101,13 +101,19 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
  override val argumentType: Argument.Type = Argument.Type.MOTION
 | 
					  override val argumentType: Argument.Type = Argument.Type.MOTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
					  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
				
			||||||
    val argument = cmd.argument as? Argument.Motion ?: return false
 | 
					    val argument = cmd.argument ?: return false
 | 
				
			||||||
    if (!editor.inRepeatMode) {
 | 
					    if (!editor.inRepeatMode) {
 | 
				
			||||||
      argumentCaptured = argument
 | 
					      argumentCaptured = argument
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val range = getMotionRange(editor, context, argument, operatorArguments)
 | 
					    val range = getMotionRange(editor, context, argument, operatorArguments)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (range != null) {
 | 
					    if (range != null) {
 | 
				
			||||||
      return doOperatorAction(editor, context, range, argument.getMotionType())
 | 
					      val selectionType = if (argument.motion.isLinewiseMotion()) {
 | 
				
			||||||
 | 
					        SelectionType.LINE_WISE
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        SelectionType.CHARACTER_WISE
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return doOperatorAction(editor, context, range, selectionType)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false
 | 
					    return false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -115,7 +121,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
  private fun getMotionRange(
 | 
					  private fun getMotionRange(
 | 
				
			||||||
    editor: VimEditor,
 | 
					    editor: VimEditor,
 | 
				
			||||||
    context: ExecutionContext,
 | 
					    context: ExecutionContext,
 | 
				
			||||||
    argument: Argument.Motion,
 | 
					    argument: Argument,
 | 
				
			||||||
    operatorArguments: OperatorArguments,
 | 
					    operatorArguments: OperatorArguments,
 | 
				
			||||||
  ): TextRange? {
 | 
					  ): TextRange? {
 | 
				
			||||||
    // Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
 | 
					    // Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
 | 
				
			||||||
@@ -130,7 +136,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
      operatorArguments,
 | 
					      operatorArguments,
 | 
				
			||||||
    )?.normalize()?.let {
 | 
					    )?.normalize()?.let {
 | 
				
			||||||
      // If we're linewise, make sure the end offset isn't just the EOL char
 | 
					      // If we're linewise, make sure the end offset isn't just the EOL char
 | 
				
			||||||
      if (argument.getMotionType() == SelectionType.LINE_WISE && it.endOffset < editor.fileSize()) {
 | 
					      if (argument.motion.isLinewiseMotion() && it.endOffset < editor.fileSize()) {
 | 
				
			||||||
        TextRange(it.startOffset, it.endOffset + 1)
 | 
					        TextRange(it.startOffset, it.endOffset + 1)
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        it
 | 
					        it
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
					  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
				
			||||||
    val state = injector.vimState
 | 
					    val state = injector.vimState
 | 
				
			||||||
    var lastCommand = VimRepeater.lastChangeCommand
 | 
					    val lastCommand = VimRepeater.lastChangeCommand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (lastCommand == null && Extension.lastExtensionHandler == null) return false
 | 
					    if (lastCommand == null && Extension.lastExtensionHandler == null) return false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,7 +57,12 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
      )
 | 
					      )
 | 
				
			||||||
    } else if (!repeatHandler && lastCommand != null) {
 | 
					    } else if (!repeatHandler && lastCommand != null) {
 | 
				
			||||||
      if (cmd.rawCount > 0) {
 | 
					      if (cmd.rawCount > 0) {
 | 
				
			||||||
        lastCommand = lastCommand.copy(rawCount = cmd.rawCount)
 | 
					        lastCommand.rawCount = cmd.count
 | 
				
			||||||
 | 
					        val arg = lastCommand.argument
 | 
				
			||||||
 | 
					        if (arg != null) {
 | 
				
			||||||
 | 
					          val mot = arg.motion
 | 
				
			||||||
 | 
					          mot.rawCount = 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      state.executingCommand = lastCommand
 | 
					      state.executingCommand = lastCommand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecuti
 | 
				
			|||||||
  ): Boolean {
 | 
					  ): Boolean {
 | 
				
			||||||
    injector.editorGroup.notifyIdeaJoin(editor)
 | 
					    injector.editorGroup.notifyIdeaJoin(editor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, false)
 | 
					    return injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun execute(
 | 
					  override fun execute(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
 | 
				
			|||||||
    injector.editorGroup.notifyIdeaJoin(editor)
 | 
					    injector.editorGroup.notifyIdeaJoin(editor)
 | 
				
			||||||
    var res = true
 | 
					    var res = true
 | 
				
			||||||
    editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
 | 
					    editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
 | 
				
			||||||
      if (!injector.changeGroup.deleteJoinLines(editor, context, caret, operatorArguments.count1, true)) {
 | 
					      if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) {
 | 
				
			||||||
        res = false
 | 
					        res = false
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,6 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution(
 | 
				
			|||||||
      val range = caretsAndSelections[caret] ?: return@forEach
 | 
					      val range = caretsAndSelections[caret] ?: return@forEach
 | 
				
			||||||
      if (!injector.changeGroup.deleteJoinRange(
 | 
					      if (!injector.changeGroup.deleteJoinRange(
 | 
				
			||||||
          editor,
 | 
					          editor,
 | 
				
			||||||
          context,
 | 
					 | 
				
			||||||
          caret,
 | 
					          caret,
 | 
				
			||||||
          range.toVimTextRange(true).normalize(),
 | 
					          range.toVimTextRange(true).normalize(),
 | 
				
			||||||
          false,
 | 
					          false,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,6 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec
 | 
				
			|||||||
      val range = caretsAndSelections[caret] ?: return@forEach
 | 
					      val range = caretsAndSelections[caret] ?: return@forEach
 | 
				
			||||||
      if (!injector.changeGroup.deleteJoinRange(
 | 
					      if (!injector.changeGroup.deleteJoinRange(
 | 
				
			||||||
          editor,
 | 
					          editor,
 | 
				
			||||||
          context,
 | 
					 | 
				
			||||||
          caret,
 | 
					          caret,
 | 
				
			||||||
          range.toVimTextRange(true).normalize(),
 | 
					          range.toVimTextRange(true).normalize(),
 | 
				
			||||||
          true,
 | 
					          true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,13 @@ import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			|||||||
import com.maddyhome.idea.vim.handler.IdeActionHandler
 | 
					import com.maddyhome.idea.vim.handler.IdeActionHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
					import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.enumSetOf
 | 
					import com.maddyhome.idea.vim.helper.enumSetOf
 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
 | 
					 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<C-H>", "<BS>"], modes = [Mode.INSERT])
 | 
				
			||||||
 | 
					internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE) {
 | 
				
			||||||
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
 | 
					@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE) {
 | 
					internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE) {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
@@ -41,13 +44,8 @@ internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CA
 | 
				
			|||||||
    operatorArguments: OperatorArguments
 | 
					    operatorArguments: OperatorArguments
 | 
				
			||||||
  ): Boolean {
 | 
					  ): Boolean {
 | 
				
			||||||
    val undo = injector.undo
 | 
					    val undo = injector.undo
 | 
				
			||||||
    when (undo) {
 | 
					    val nanoTime = System.nanoTime()
 | 
				
			||||||
      is VimKeyBasedUndoService -> undo.setMergeUndoKey()
 | 
					    editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
				
			||||||
      is VimTimestampBasedUndoService -> {
 | 
					 | 
				
			||||||
        val nanoTime = System.nanoTime()
 | 
					 | 
				
			||||||
        editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return super.execute(editor, context, cmd, operatorArguments)
 | 
					    return super.execute(editor, context, cmd, operatorArguments)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -70,13 +68,8 @@ internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARE
 | 
				
			|||||||
    operatorArguments: OperatorArguments
 | 
					    operatorArguments: OperatorArguments
 | 
				
			||||||
  ): Boolean {
 | 
					  ): Boolean {
 | 
				
			||||||
    val undo = injector.undo
 | 
					    val undo = injector.undo
 | 
				
			||||||
    when (undo) {
 | 
					    val nanoTime = System.nanoTime()
 | 
				
			||||||
      is VimKeyBasedUndoService -> undo.setMergeUndoKey()
 | 
					    editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
				
			||||||
      is VimTimestampBasedUndoService -> {
 | 
					 | 
				
			||||||
        val nanoTime = System.nanoTime()
 | 
					 | 
				
			||||||
        editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return super.execute(editor, context, cmd, operatorArguments)
 | 
					    return super.execute(editor, context, cmd, operatorArguments)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,30 +27,6 @@ public interface VimExtension {
 | 
				
			|||||||
    return MappingOwner.Plugin.Companion.get(getName());
 | 
					    return MappingOwner.Plugin.Companion.get(getName());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * This method is always called AFTER the full execution of the `.ideavimrc` file.
 | 
					 | 
				
			||||||
   * <p>
 | 
					 | 
				
			||||||
   * During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
 | 
					 | 
				
			||||||
   * This practically means that the .vimrc file is initialized first; then the plugins are loaded.
 | 
					 | 
				
			||||||
   * See `:h initialization`
 | 
					 | 
				
			||||||
   * <p>
 | 
					 | 
				
			||||||
   * Why does this matter? Because this affects the order of commands are executed. For example,
 | 
					 | 
				
			||||||
   * ```
 | 
					 | 
				
			||||||
   * plug 'tommcdo/vim-exchange'
 | 
					 | 
				
			||||||
   * let g:exchange_no_mappings=1
 | 
					 | 
				
			||||||
   * ```
 | 
					 | 
				
			||||||
   * Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
 | 
					 | 
				
			||||||
   *    immediately, this variable won't be initialized at the moment of plugin initialization.
 | 
					 | 
				
			||||||
   * <p>
 | 
					 | 
				
			||||||
   * There is also a tricky case for mappings override:
 | 
					 | 
				
			||||||
   * ```
 | 
					 | 
				
			||||||
   * plug 'tommcdo/vim-exchange'
 | 
					 | 
				
			||||||
   * map X <Plug>(ExchangeLine)
 | 
					 | 
				
			||||||
   * ```
 | 
					 | 
				
			||||||
   * For this case, a plugin with a good implementation detects that there is already a defined mapping for
 | 
					 | 
				
			||||||
   *   `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
 | 
					 | 
				
			||||||
   *   to be defined before the plugin initialization.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  void init();
 | 
					  void init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  default void dispose() {
 | 
					  default void dispose() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,8 @@ object VimExtensionFacade {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  @Deprecated("Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
					  @Deprecated(
 | 
				
			||||||
 | 
					    "Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
				
			||||||
    ReplaceWith(
 | 
					    ReplaceWith(
 | 
				
			||||||
      "VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
					      "VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
				
			||||||
      "com.maddyhome.idea.vim.VimPlugin"
 | 
					      "com.maddyhome.idea.vim.VimPlugin"
 | 
				
			||||||
@@ -188,22 +189,14 @@ object VimExtensionFacade {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** Get the current contents of the given register similar to 'getreg()'. */
 | 
					  /** Get the current contents of the given register similar to 'getreg()'. */
 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  @Deprecated("Please use com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister(com.maddyhome.idea.vim.api.VimEditor, char)")
 | 
					 | 
				
			||||||
  fun getRegister(register: Char): List<KeyStroke>? {
 | 
					  fun getRegister(register: Char): List<KeyStroke>? {
 | 
				
			||||||
    val reg = VimPlugin.getRegister().getRegister(register) ?: return null
 | 
					    val reg = VimPlugin.getRegister().getRegister(register) ?: return null
 | 
				
			||||||
    return reg.keys
 | 
					    return reg.keys
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Get the current contents of the given register similar to 'getreg()'. */
 | 
					 | 
				
			||||||
  @JvmStatic
 | 
					 | 
				
			||||||
  fun getRegister(editor: VimEditor, register: Char): List<KeyStroke>? {
 | 
					 | 
				
			||||||
    val reg = VimPlugin.getRegister().getRegister(editor, injector.executionContextManager.getEditorExecutionContext(editor), register) ?: return null
 | 
					 | 
				
			||||||
    return reg.keys
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
 | 
					  fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
 | 
				
			||||||
    val reg = caret.registerStorage.getRegister(register) ?: return null
 | 
					    val reg = injector.registerGroup.getRegister(register) ?: return null
 | 
				
			||||||
    return reg.keys
 | 
					    return reg.keys
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -216,7 +209,7 @@ object VimExtensionFacade {
 | 
				
			|||||||
  /** Set the current contents of the given register */
 | 
					  /** Set the current contents of the given register */
 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
 | 
					  fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
 | 
				
			||||||
    caret.registerStorage.setKeys(register, keys?.filterNotNull() ?: emptyList())
 | 
					    injector.registerGroup.setKeys(register, keys?.filterNotNull() ?: emptyList())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Set the current contents of the given register */
 | 
					  /** Set the current contents of the given register */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,10 +88,29 @@ internal object VimExtensionRegistrar : VimExtensionRegistrator {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * See the docs for [VimExtension.init]
 | 
					   * During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
 | 
				
			||||||
 | 
					   * This practically means that the .vimrc file is initialized first, then the plugins are loaded.
 | 
				
			||||||
 | 
					   * See `:h initialization`
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
 | 
					   * In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
 | 
				
			||||||
   *   the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
 | 
					   *   the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * Why this matters? Because this affects the order of commands are executed. For example:
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * plug 'tommcdo/vim-exchange'
 | 
				
			||||||
 | 
					   * let g:exchange_no_mappings=1
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
 | 
				
			||||||
 | 
					   *    immediately, this variable won't be initialized at the moment of plugin initialization.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * There is also a tricky case for mappings override:
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * plug 'tommcdo/vim-exchange'
 | 
				
			||||||
 | 
					   * map X <Plug>(ExchangeLine)
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * For this case, a plugin with a good implementation detects that there is already a defined mapping for
 | 
				
			||||||
 | 
					   *   `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
 | 
				
			||||||
 | 
					   *   to be defined before the plugin initialization.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  fun enableDelayedExtensions() {
 | 
					  fun enableDelayedExtensions() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayDeque;
 | 
					import java.util.ArrayDeque;
 | 
				
			||||||
import java.util.Deque;
 | 
					import java.util.Deque;
 | 
				
			||||||
 | 
					import java.util.EnumSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
				
			||||||
@@ -63,8 +64,8 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  private static class BracketPairs {
 | 
					  private static class BracketPairs {
 | 
				
			||||||
    // NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
 | 
					    // NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
 | 
				
			||||||
    private final @NotNull String openBrackets;
 | 
					    @NotNull private final String openBrackets;
 | 
				
			||||||
    private final @NotNull String closeBrackets;
 | 
					    @NotNull private final String closeBrackets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static class ParseException extends Exception {
 | 
					    static class ParseException extends Exception {
 | 
				
			||||||
      public ParseException(@NotNull String message) {
 | 
					      public ParseException(@NotNull String message) {
 | 
				
			||||||
@@ -86,7 +87,8 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
     * @param bracketPairs comma-separated list of colon-separated bracket pairs.
 | 
					     * @param bracketPairs comma-separated list of colon-separated bracket pairs.
 | 
				
			||||||
     * @throws ParseException if a syntax error is detected.
 | 
					     * @throws ParseException if a syntax error is detected.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    static @NotNull BracketPairs fromBracketPairList(final @NotNull String bracketPairs) throws ParseException {
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseException {
 | 
				
			||||||
      StringBuilder openBrackets = new StringBuilder();
 | 
					      StringBuilder openBrackets = new StringBuilder();
 | 
				
			||||||
      StringBuilder closeBrackets = new StringBuilder();
 | 
					      StringBuilder closeBrackets = new StringBuilder();
 | 
				
			||||||
      ParseState state = ParseState.OPEN;
 | 
					      ParseState state = ParseState.OPEN;
 | 
				
			||||||
@@ -126,7 +128,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
      return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
 | 
					      return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    BracketPairs(final @NotNull String openBrackets, final @NotNull String closeBrackets) {
 | 
					    BracketPairs(@NotNull final String openBrackets, @NotNull final String closeBrackets) {
 | 
				
			||||||
      assert openBrackets.length() == closeBrackets.length();
 | 
					      assert openBrackets.length() == closeBrackets.length();
 | 
				
			||||||
      this.openBrackets = openBrackets;
 | 
					      this.openBrackets = openBrackets;
 | 
				
			||||||
      this.closeBrackets = closeBrackets;
 | 
					      this.closeBrackets = closeBrackets;
 | 
				
			||||||
@@ -156,9 +158,10 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
 | 
					  public static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static @Nullable String bracketPairsVariable() {
 | 
					  @Nullable
 | 
				
			||||||
 | 
					  private static String bracketPairsVariable() {
 | 
				
			||||||
    final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
 | 
					    final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
 | 
				
			||||||
    if (value instanceof VimString vimValue) {
 | 
					    if (value instanceof VimString vimValue) {
 | 
				
			||||||
      return vimValue.getValue();
 | 
					      return vimValue.getValue();
 | 
				
			||||||
@@ -189,12 +192,13 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
        this.isInner = isInner;
 | 
					        this.isInner = isInner;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @Nullable
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
					      public TextRange getRange(@NotNull VimEditor editor,
 | 
				
			||||||
                                          @NotNull ImmutableVimCaret caret,
 | 
					                                @NotNull ImmutableVimCaret caret,
 | 
				
			||||||
                                          @NotNull ExecutionContext context,
 | 
					                                @NotNull ExecutionContext context,
 | 
				
			||||||
                                          int count,
 | 
					                                int count,
 | 
				
			||||||
                                          int rawCount) {
 | 
					                                int rawCount) {
 | 
				
			||||||
        BracketPairs bracketPairs = DEFAULT_BRACKET_PAIRS;
 | 
					        BracketPairs bracketPairs = DEFAULT_BRACKET_PAIRS;
 | 
				
			||||||
        final String bracketPairsVar = bracketPairsVariable();
 | 
					        final String bracketPairsVar = bracketPairsVariable();
 | 
				
			||||||
        if (bracketPairsVar != null) {
 | 
					        if (bracketPairsVar != null) {
 | 
				
			||||||
@@ -232,22 +236,24 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
        return new TextRange(finder.getLeftBound(), finder.getRightBound());
 | 
					        return new TextRange(finder.getLeftBound(), finder.getRightBound());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @NotNull
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
					      public TextObjectVisualType getVisualType() {
 | 
				
			||||||
        return TextObjectVisualType.CHARACTER_WISE;
 | 
					        return TextObjectVisualType.CHARACTER_WISE;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
					    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
				
			||||||
 | 
					      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
				
			||||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
					      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
				
			||||||
 | 
					      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
 | 
					      final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
 | 
				
			||||||
      //noinspection DuplicatedCode
 | 
					      //noinspection DuplicatedCode
 | 
				
			||||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
					      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
				
			||||||
        int count0 = operatorArguments.getCount0();
 | 
					 | 
				
			||||||
        editor.nativeCarets().forEach((VimCaret caret) -> {
 | 
					        editor.nativeCarets().forEach((VimCaret caret) -> {
 | 
				
			||||||
          final TextRange range = textObjectHandler.getRange(editor, caret, context, Math.max(1, count0), count0);
 | 
					          final TextRange range = textObjectHandler.getRange(editor, caret, context, count, 0);
 | 
				
			||||||
          if (range != null) {
 | 
					          if (range != null) {
 | 
				
			||||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
					            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
				
			||||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
					              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
				
			||||||
@@ -259,7 +265,8 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
					        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
				
			||||||
 | 
					                                                                                         textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -269,9 +276,9 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
   * position
 | 
					   * position
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  private static class ArgBoundsFinder {
 | 
					  private static class ArgBoundsFinder {
 | 
				
			||||||
    private final @NotNull CharSequence text;
 | 
					    @NotNull private final CharSequence text;
 | 
				
			||||||
    private final @NotNull Document document;
 | 
					    @NotNull private final Document document;
 | 
				
			||||||
    private final @NotNull BracketPairs brackets;
 | 
					    @NotNull private final BracketPairs brackets;
 | 
				
			||||||
    private int leftBound = Integer.MAX_VALUE;
 | 
					    private int leftBound = Integer.MAX_VALUE;
 | 
				
			||||||
    private int rightBound = Integer.MIN_VALUE;
 | 
					    private int rightBound = Integer.MIN_VALUE;
 | 
				
			||||||
    private int leftBracket;
 | 
					    private int leftBracket;
 | 
				
			||||||
@@ -298,7 +305,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
				
			|||||||
     * @param position starting position.
 | 
					     * @param position starting position.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    boolean findBoundsAt(int position) throws IllegalStateException {
 | 
					    boolean findBoundsAt(int position) throws IllegalStateException {
 | 
				
			||||||
      if (text.isEmpty()) {
 | 
					      if (text.length() == 0) {
 | 
				
			||||||
        error = "empty document";
 | 
					        error = "empty document";
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,9 @@ import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.getLineEndOffset
 | 
					import com.maddyhome.idea.vim.api.getLineEndOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.api.globalOptions
 | 
					import com.maddyhome.idea.vim.api.globalOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.Argument
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.Command
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.CommandFlags
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode
 | 
					import com.maddyhome.idea.vim.command.MappingMode
 | 
				
			||||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.command.TextObjectVisualType
 | 
					import com.maddyhome.idea.vim.command.TextObjectVisualType
 | 
				
			||||||
@@ -49,6 +52,7 @@ import com.maddyhome.idea.vim.newapi.ij
 | 
				
			|||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class CommentaryExtension : VimExtension {
 | 
					internal class CommentaryExtension : VimExtension {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -180,8 +184,10 @@ internal class CommentaryExtension : VimExtension {
 | 
				
			|||||||
    override val isRepeatable = true
 | 
					    override val isRepeatable = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
					    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
 | 
					      val command = Command(operatorArguments.count1, CommentaryTextObjectMotionHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags::class.java))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val keyState = KeyHandler.getInstance().keyHandlerState
 | 
					      val keyState = KeyHandler.getInstance().keyHandlerState
 | 
				
			||||||
      keyState.commandBuilder.addAction(CommentaryTextObjectMotionHandler)
 | 
					      keyState.commandBuilder.completeCommandPart(Argument(command))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,10 +222,10 @@ internal class VimExchangeExtension : VimExtension {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val zRegText = getRegister(editor.vim, 'z')
 | 
					      val zRegText = getRegister('z')
 | 
				
			||||||
      val unnRegText = getRegister(editor.vim, '"')
 | 
					      val unnRegText = getRegister('"')
 | 
				
			||||||
      val startRegText = getRegister(editor.vim, '*')
 | 
					      val startRegText = getRegister('*')
 | 
				
			||||||
      val plusRegText = getRegister(editor.vim, '+')
 | 
					      val plusRegText = getRegister('+')
 | 
				
			||||||
      runWriteAction {
 | 
					      runWriteAction {
 | 
				
			||||||
        // TODO handle:
 | 
					        // TODO handle:
 | 
				
			||||||
        // 	" Compare using =~ because "'==' != 0" returns 0
 | 
					        // 	" Compare using =~ because "'==' != 0" returns 0
 | 
				
			||||||
@@ -299,7 +299,7 @@ internal class VimExchangeExtension : VimExtension {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange {
 | 
					    private fun getExchange(editor: Editor, isVisual: Boolean, selectionType: SelectionType): Exchange {
 | 
				
			||||||
      // TODO: improve KeyStroke list to sting conversion
 | 
					      // TODO: improve KeyStroke list to sting conversion
 | 
				
			||||||
      fun getRegisterText(reg: Char): String = getRegister(editor.vim, reg)?.map { it.keyChar }?.joinToString("") ?: ""
 | 
					      fun getRegisterText(reg: Char): String = getRegister(reg)?.map { it.keyChar }?.joinToString("") ?: ""
 | 
				
			||||||
      fun getMarks(isVisual: Boolean): Pair<Mark, Mark> {
 | 
					      fun getMarks(isVisual: Boolean): Pair<Mark, Mark> {
 | 
				
			||||||
        val (startMark, endMark) =
 | 
					        val (startMark, endMark) =
 | 
				
			||||||
          if (isVisual) {
 | 
					          if (isVisual) {
 | 
				
			||||||
@@ -313,9 +313,9 @@ internal class VimExchangeExtension : VimExtension {
 | 
				
			|||||||
        return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!)
 | 
					        return Pair(marks.getMark(vimEditor.primaryCaret(), startMark)!!, marks.getMark(vimEditor.primaryCaret(), endMark)!!)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val unnRegText = getRegister(editor.vim, '"')
 | 
					      val unnRegText = getRegister('"')
 | 
				
			||||||
      val starRegText = getRegister(editor.vim, '*')
 | 
					      val starRegText = getRegister('*')
 | 
				
			||||||
      val plusRegText = getRegister(editor.vim, '+')
 | 
					      val plusRegText = getRegister('+')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val (selectionStart, selectionEnd) = getMarks(isVisual)
 | 
					      val (selectionStart, selectionEnd) = getMarks(isVisual)
 | 
				
			||||||
      if (isVisual) {
 | 
					      if (isVisual) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,10 +45,6 @@ private val HIGHLIGHT_DURATION_VARIABLE_NAME = "highlightedyank_highlight_durati
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@NonNls
 | 
					@NonNls
 | 
				
			||||||
private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color"
 | 
					private val HIGHLIGHT_COLOR_VARIABLE_NAME = "highlightedyank_highlight_color"
 | 
				
			||||||
 | 
					 | 
				
			||||||
@NonNls
 | 
					 | 
				
			||||||
private val HIGHLIGHT_FOREGROUND_COLOR_VARIABLE_NAME = "highlightedyank_highlight_foreground_color"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private var defaultHighlightTextColor: Color? = null
 | 
					private var defaultHighlightTextColor: Color? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun getDefaultHighlightTextColor(): Color {
 | 
					private fun getDefaultHighlightTextColor(): Color {
 | 
				
			||||||
@@ -79,9 +75,6 @@ internal class HighlightColorResetter : LafManagerListener {
 | 
				
			|||||||
 * if you want to change background color of highlight you can provide the rgba of the color you want e.g.
 | 
					 * if you want to change background color of highlight you can provide the rgba of the color you want e.g.
 | 
				
			||||||
 * let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"
 | 
					 * let g:highlightedyank_highlight_color = "rgba(160, 160, 160, 155)"
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * if you want to change text color of highlight you can provide the rgba of the color you want e.g.
 | 
					 | 
				
			||||||
 * let g:highlightedyank_highlight_foreground_color = "rgba(0, 0, 0, 255)"
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * When a new text is yanked or user starts editing, the old highlighting would be deleted.
 | 
					 * When a new text is yanked or user starts editing, the old highlighting would be deleted.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
 | 
					internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeListener {
 | 
				
			||||||
@@ -188,15 +181,13 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
 | 
				
			|||||||
      highlighters.clear()
 | 
					      highlighters.clear()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun getHighlightTextAttributes(editor: Editor): TextAttributes {
 | 
					    private fun getHighlightTextAttributes(editor: Editor) = TextAttributes(
 | 
				
			||||||
      return TextAttributes(
 | 
					      null,
 | 
				
			||||||
        extractUserHighlightForegroundColor(),
 | 
					      extractUsersHighlightColor(),
 | 
				
			||||||
        extractUsersHighlightColor(),
 | 
					      editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
 | 
				
			||||||
        editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
 | 
					      EffectType.SEARCH_MATCH,
 | 
				
			||||||
        EffectType.SEARCH_MATCH,
 | 
					      Font.PLAIN,
 | 
				
			||||||
        Font.PLAIN,
 | 
					    )
 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun extractUsersHighlightDuration(): Int {
 | 
					    private fun extractUsersHighlightDuration(): Int {
 | 
				
			||||||
      return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) {
 | 
					      return extractVariable(HIGHLIGHT_DURATION_VARIABLE_NAME, DEFAULT_HIGHLIGHT_DURATION) {
 | 
				
			||||||
@@ -209,52 +200,15 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun extractUsersHighlightColor(): Color {
 | 
					    private fun extractUsersHighlightColor(): Color {
 | 
				
			||||||
      val value = VimPlugin.getVariableService().getGlobalVariableValue(HIGHLIGHT_COLOR_VARIABLE_NAME)
 | 
					      return extractVariable(HIGHLIGHT_COLOR_VARIABLE_NAME, getDefaultHighlightTextColor()) { value ->
 | 
				
			||||||
      if (value != null) {
 | 
					        val rgba = value.asString()
 | 
				
			||||||
        return try {
 | 
					          .substring(4)
 | 
				
			||||||
          parseRgbaColor(value.asString())
 | 
					          .filter { it != '(' && it != ')' && !it.isWhitespace() }
 | 
				
			||||||
        } catch (e: Exception) {
 | 
					          .split(',')
 | 
				
			||||||
          @VimNlsSafe val message = MessageHelper.message(
 | 
					          .map { it.toInt() }
 | 
				
			||||||
            "highlightedyank.invalid.value.of.0.1",
 | 
					
 | 
				
			||||||
            "g:$HIGHLIGHT_COLOR_VARIABLE_NAME",
 | 
					        Color(rgba[0], rgba[1], rgba[2], rgba[3])
 | 
				
			||||||
            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)
 | 
					 | 
				
			||||||
        .filter { it != '(' && it != ')' && !it.isWhitespace() }
 | 
					 | 
				
			||||||
        .split(',')
 | 
					 | 
				
			||||||
        .map { it.toInt() }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (rgba.size != 4 || rgba.any { it < 0 || it > 255 }) {
 | 
					 | 
				
			||||||
        throw IllegalArgumentException("Invalid RGBA values. Each component must be between 0 and 255")
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return Color(rgba[0], rgba[1], rgba[2], rgba[3])
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T {
 | 
					    private fun <T> extractVariable(variable: String, default: T, extractFun: (value: VimDataType) -> T): T {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,6 @@ import com.maddyhome.idea.vim.helper.enumSetOf
 | 
				
			|||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
import java.util.regex.Pattern
 | 
					import java.util.regex.Pattern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,29 +93,34 @@ internal class Matchit : VimExtension {
 | 
				
			|||||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
					    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
      val keyHandler = KeyHandler.getInstance()
 | 
					      val keyHandler = KeyHandler.getInstance()
 | 
				
			||||||
      val keyState = keyHandler.keyHandlerState
 | 
					      val keyState = keyHandler.keyHandlerState
 | 
				
			||||||
 | 
					      val count = keyState.commandBuilder.count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Reset the command count so it doesn't transfer onto subsequent commands.
 | 
					      // Reset the command count so it doesn't transfer onto subsequent commands.
 | 
				
			||||||
      keyState.commandBuilder.resetCount()
 | 
					      keyState.commandBuilder.resetCount()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Normally we want to jump to the start of the matching pair. But when moving forward in operator
 | 
					      // Normally we want to jump to the start of the matching pair. But when moving forward in operator
 | 
				
			||||||
      // pending mode, we want to include the entire match. isInOpPending makes that distinction.
 | 
					      // pending mode, we want to include the entire match. isInOpPending makes that distinction.
 | 
				
			||||||
      if (editor.mode is Mode.OP_PENDING) {
 | 
					      val isInOpPending = keyHandler.isOperatorPending(editor.mode, keyState)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isInOpPending) {
 | 
				
			||||||
        val matchitAction = MatchitAction()
 | 
					        val matchitAction = MatchitAction()
 | 
				
			||||||
        matchitAction.reverse = reverse
 | 
					        matchitAction.reverse = reverse
 | 
				
			||||||
        matchitAction.isInOpPending = true
 | 
					        matchitAction.isInOpPending = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        keyState.commandBuilder.addAction(matchitAction)
 | 
					        keyState.commandBuilder.completeCommandPart(
 | 
				
			||||||
 | 
					          Argument(
 | 
				
			||||||
 | 
					            Command(
 | 
				
			||||||
 | 
					              count,
 | 
				
			||||||
 | 
					              matchitAction,
 | 
				
			||||||
 | 
					              Command.Type.MOTION,
 | 
				
			||||||
 | 
					              EnumSet.noneOf(CommandFlags::class.java),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        editor.sortedCarets().forEach { caret ->
 | 
					        editor.sortedCarets().forEach { caret ->
 | 
				
			||||||
          injector.jumpService.saveJumpLocation(editor)
 | 
					          injector.jumpService.saveJumpLocation(editor)
 | 
				
			||||||
          caret.moveToOffset(
 | 
					          caret.moveToOffset(getMatchitOffset(editor.ij, caret.ij, count, isInOpPending, reverse))
 | 
				
			||||||
            getMatchitOffset(
 | 
					 | 
				
			||||||
              editor.ij,
 | 
					 | 
				
			||||||
              caret.ij,
 | 
					 | 
				
			||||||
              operatorArguments.count0,
 | 
					 | 
				
			||||||
              isInOpPending = false,
 | 
					 | 
				
			||||||
              reverse
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -350,7 +354,7 @@ private object FileTypePatterns {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')
 | 
					private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPending: Boolean, reverse: Boolean): Int {
 | 
					private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPending: Boolean, reverse: Boolean): Int {
 | 
				
			||||||
  val virtualFile = EditorHelper.getVirtualFile(editor)
 | 
					  val virtualFile = EditorHelper.getVirtualFile(editor)
 | 
				
			||||||
  var caretOffset = caret.offset
 | 
					  var caretOffset = caret.offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -363,9 +367,9 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPe
 | 
				
			|||||||
  val currentChar = editor.document.charsSequence[caretOffset]
 | 
					  val currentChar = editor.document.charsSequence[caretOffset]
 | 
				
			||||||
  var motionOffset: Int? = null
 | 
					  var motionOffset: Int? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (count0 > 0) {
 | 
					  if (count > 0) {
 | 
				
			||||||
    // Matchit doesn't affect the percent motion, so we fall back to the default behavior.
 | 
					    // Matchit doesn't affect the percent motion, so we fall back to the default behavior.
 | 
				
			||||||
    motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count0)
 | 
					    motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count)
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    // Check the simplest case first.
 | 
					    // Check the simplest case first.
 | 
				
			||||||
    if (DEFAULT_PAIRS.contains(currentChar)) {
 | 
					    if (DEFAULT_PAIRS.contains(currentChar)) {
 | 
				
			||||||
@@ -396,7 +400,8 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPe
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private fun getMotionOffset(motion: Motion): Int? {
 | 
					private fun getMotionOffset(motion: Motion): Int? {
 | 
				
			||||||
  return when (motion) {
 | 
					  return when (motion) {
 | 
				
			||||||
    is Motion.AdjustedOffset, is Motion.AbsoluteOffset -> motion.offset
 | 
					    is Motion.AbsoluteOffset -> motion.offset
 | 
				
			||||||
 | 
					    is Motion.AdjustedOffset -> motion.offset
 | 
				
			||||||
    is Motion.Error, is Motion.NoMotion -> null
 | 
					    is Motion.Error, is Motion.NoMotion -> null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,10 +42,13 @@ import com.maddyhome.idea.vim.extension.VimExtension
 | 
				
			|||||||
import com.maddyhome.idea.vim.group.KeyGroup
 | 
					import com.maddyhome.idea.vim.group.KeyGroup
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.MessageHelper
 | 
					import com.maddyhome.idea.vim.helper.MessageHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.runAfterGotFocus
 | 
					import com.maddyhome.idea.vim.helper.runAfterGotFocus
 | 
				
			||||||
import com.maddyhome.idea.vim.key.KeyStrokeTrie
 | 
					import com.maddyhome.idea.vim.key.CommandNode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.CommandPartNode
 | 
				
			||||||
import com.maddyhome.idea.vim.key.MappingOwner
 | 
					import com.maddyhome.idea.vim.key.MappingOwner
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.Node
 | 
				
			||||||
import com.maddyhome.idea.vim.key.RequiredShortcut
 | 
					import com.maddyhome.idea.vim.key.RequiredShortcut
 | 
				
			||||||
import com.maddyhome.idea.vim.key.add
 | 
					import com.maddyhome.idea.vim.key.RootNode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.addLeafs
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
 | 
					import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
 | 
				
			||||||
@@ -195,8 +198,6 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    internal var waitForSearch = false
 | 
					    internal var waitForSearch = false
 | 
				
			||||||
    internal var speedSearchListenerInstalled = false
 | 
					    internal var speedSearchListenerInstalled = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val keys = mutableListOf<KeyStroke>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun actionPerformed(e: AnActionEvent) {
 | 
					    override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
      var keyStroke = getKeyStroke(e) ?: return
 | 
					      var keyStroke = getKeyStroke(e) ?: return
 | 
				
			||||||
      val keyChar = keyStroke.keyChar
 | 
					      val keyChar = keyStroke.keyChar
 | 
				
			||||||
@@ -204,14 +205,20 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
        keyStroke = KeyStroke.getKeyStroke(keyChar)
 | 
					        keyStroke = KeyStroke.getKeyStroke(keyChar)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      keys.add(keyStroke)
 | 
					      val nextNode = currentNode[keyStroke]
 | 
				
			||||||
      actionsRoot.getData(keys)?.let { action ->
 | 
					 | 
				
			||||||
        when (action) {
 | 
					 | 
				
			||||||
          is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim)
 | 
					 | 
				
			||||||
          is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        keys.clear()
 | 
					      when (nextNode) {
 | 
				
			||||||
 | 
					        null -> currentNode = actionsRoot
 | 
				
			||||||
 | 
					        is CommandNode<NerdAction> -> {
 | 
				
			||||||
 | 
					          currentNode = actionsRoot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          val action = nextNode.actionHolder
 | 
				
			||||||
 | 
					          when (action) {
 | 
				
			||||||
 | 
					            is NerdAction.ToIj -> Util.callAction(null, action.name, e.dataContext.vim)
 | 
				
			||||||
 | 
					            is NerdAction.Code -> e.project?.let { action.action(it, e.dataContext, e) }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        is CommandPartNode<NerdAction> -> currentNode = nextNode
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -533,29 +540,37 @@ private fun addCommand(alias: String, handler: CommandAliasHandler) {
 | 
				
			|||||||
  VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler))
 | 
					  VimPlugin.getCommand().setAlias(alias, CommandAlias.Call(0, -1, alias, handler))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun registerCommand(variable: String, defaultMapping: String, action: NerdAction) {
 | 
					private fun registerCommand(variable: String, default: String, action: NerdAction) {
 | 
				
			||||||
  val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable)
 | 
					  val variableValue = VimPlugin.getVariableService().getGlobalVariableValue(variable)
 | 
				
			||||||
  val mapping = if (variableValue is VimString) {
 | 
					  val mappings = if (variableValue is VimString) {
 | 
				
			||||||
    variableValue.value
 | 
					    variableValue.value
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    defaultMapping
 | 
					    default
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  registerCommand(mapping, action)
 | 
					  actionsRoot.addLeafs(mappings, action)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun registerCommand(mapping: String, action: NerdAction) {
 | 
					private fun registerCommand(default: String, action: NerdAction) {
 | 
				
			||||||
  actionsRoot.add(mapping, action)
 | 
					  actionsRoot.addLeafs(default, action)
 | 
				
			||||||
  injector.parser.parseKeys(mapping).forEach {
 | 
					 | 
				
			||||||
    distinctShortcuts.add(it)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private val actionsRoot: KeyStrokeTrie<NerdAction> = KeyStrokeTrie<NerdAction>("NERDTree")
 | 
					
 | 
				
			||||||
private val distinctShortcuts = mutableSetOf<KeyStroke>()
 | 
					private val actionsRoot: RootNode<NerdAction> = RootNode()
 | 
				
			||||||
 | 
					private var currentNode: CommandPartNode<NerdAction> = actionsRoot
 | 
				
			||||||
 | 
					private fun collectShortcuts(node: Node<NerdAction>): Set<KeyStroke> {
 | 
				
			||||||
 | 
					  return if (node is CommandPartNode<NerdAction>) {
 | 
				
			||||||
 | 
					    val res = node.keys.toMutableSet()
 | 
				
			||||||
 | 
					    res += node.values.map { collectShortcuts(it) }.flatten()
 | 
				
			||||||
 | 
					    res
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    emptySet()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun installDispatcher(project: Project) {
 | 
					private fun installDispatcher(project: Project) {
 | 
				
			||||||
  val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
 | 
					  val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
 | 
				
			||||||
  val shortcuts = distinctShortcuts.map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
 | 
					  val shortcuts =
 | 
				
			||||||
 | 
					    collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
 | 
				
			||||||
  dispatcher.registerCustomShortcutSet(
 | 
					  dispatcher.registerCustomShortcutSet(
 | 
				
			||||||
    KeyGroup.toShortcutSet(shortcuts),
 | 
					    KeyGroup.toShortcutSet(shortcuts),
 | 
				
			||||||
    (ProjectView.getInstance(project) as ProjectViewImpl).component,
 | 
					    (ProjectView.getInstance(project) as ProjectViewImpl).component,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@ internal class ParagraphMotion : VimExtension {
 | 
				
			|||||||
    toKeys: List<KeyStroke>,
 | 
					    toKeys: List<KeyStroke>,
 | 
				
			||||||
    recursive: Boolean,
 | 
					    recursive: Boolean,
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().getKeyMapping(it).getLayer(fromKeys) != null }
 | 
					    val filteredModes = modes.filterNotTo(HashSet()) { VimPlugin.getKey().hasmapfrom(it, fromKeys) }
 | 
				
			||||||
    putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive)
 | 
					    putKeyMappingIfMissing(filteredModes, fromKeys, pluginOwner, toKeys, recursive)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ package com.maddyhome.idea.vim.extension.replacewithregister
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.actionSystem.DataContext
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
					import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
				
			||||||
@@ -143,7 +144,7 @@ internal class ReplaceWithRegister : VimExtension {
 | 
				
			|||||||
private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
 | 
					private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
 | 
				
			||||||
  val registerGroup = injector.registerGroup
 | 
					  val registerGroup = injector.registerGroup
 | 
				
			||||||
  val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
 | 
					  val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
 | 
				
			||||||
  val savedRegister = caret.registerStorage.getRegister(lastRegisterChar) ?: return
 | 
					  val savedRegister = registerGroup.getRegister(lastRegisterChar) ?: return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var usedType = savedRegister.type
 | 
					  var usedType = savedRegister.type
 | 
				
			||||||
  var usedText = savedRegister.text
 | 
					  var usedText = savedRegister.text
 | 
				
			||||||
@@ -165,11 +166,17 @@ private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimC
 | 
				
			|||||||
    putToLine = -1,
 | 
					    putToLine = -1,
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
  val vimEditor = editor.vim
 | 
					  val vimEditor = editor.vim
 | 
				
			||||||
 | 
					  val keyHandler = KeyHandler.getInstance()
 | 
				
			||||||
  ClipboardOptionHelper.IdeaputDisabler().use {
 | 
					  ClipboardOptionHelper.IdeaputDisabler().use {
 | 
				
			||||||
    VimPlugin.getPut().putText(
 | 
					    VimPlugin.getPut().putText(
 | 
				
			||||||
      vimEditor,
 | 
					      vimEditor,
 | 
				
			||||||
      context.vim,
 | 
					      context.vim,
 | 
				
			||||||
      putData,
 | 
					      putData,
 | 
				
			||||||
 | 
					      operatorArguments = OperatorArguments(
 | 
				
			||||||
 | 
					        keyHandler.isOperatorPending(vimEditor.mode, keyHandler.keyHandlerState),
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					        editor.vim.mode,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
      saveToRegister = false
 | 
					      saveToRegister = false
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
 | 
				
			|||||||
import com.maddyhome.idea.vim.extension.VimExtensionHandler
 | 
					import com.maddyhome.idea.vim.extension.VimExtensionHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.StrictMode
 | 
					import com.maddyhome.idea.vim.helper.StrictMode
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
import org.jetbrains.annotations.TestOnly
 | 
					 | 
				
			||||||
import java.awt.Font
 | 
					import java.awt.Font
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
@@ -46,26 +45,15 @@ private const val DEFAULT_HIGHLIGHT_DURATION_SNEAK = 300
 | 
				
			|||||||
// By [Mikhail Levchenko](https://github.com/Mishkun)
 | 
					// By [Mikhail Levchenko](https://github.com/Mishkun)
 | 
				
			||||||
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
 | 
					// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
 | 
				
			||||||
internal class IdeaVimSneakExtension : VimExtension {
 | 
					internal class IdeaVimSneakExtension : VimExtension {
 | 
				
			||||||
  @Suppress("CompanionObjectInExtension")
 | 
					 | 
				
			||||||
  companion object {
 | 
					 | 
				
			||||||
    private var highlightHandler: HighlightHandler? = null
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @TestOnly
 | 
					 | 
				
			||||||
    internal fun stopTimer() {
 | 
					 | 
				
			||||||
      highlightHandler?.stopExistingTimer()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun getName(): String = "sneak"
 | 
					  override fun getName(): String = "sneak"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun init() {
 | 
					  override fun init() {
 | 
				
			||||||
    val _highlightHandler = HighlightHandler()
 | 
					    val highlightHandler = HighlightHandler()
 | 
				
			||||||
    highlightHandler = _highlightHandler
 | 
					    mapToFunctionAndProvideKeys("s", SneakHandler(highlightHandler, Direction.FORWARD), MappingMode.NXO)
 | 
				
			||||||
    mapToFunctionAndProvideKeys("s", SneakHandler(_highlightHandler, Direction.FORWARD), MappingMode.NXO)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330
 | 
					    // vim-sneak uses `Z` for visual mode because `S` conflict with vim-sneak plugin VIM-3330
 | 
				
			||||||
    mapToFunctionAndProvideKeys("S", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.NO)
 | 
					    mapToFunctionAndProvideKeys("S", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.NO)
 | 
				
			||||||
    mapToFunctionAndProvideKeys("Z", SneakHandler(_highlightHandler, Direction.BACKWARD), MappingMode.X)
 | 
					    mapToFunctionAndProvideKeys("Z", SneakHandler(highlightHandler, Direction.BACKWARD), MappingMode.X)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // workaround to support ; and , commands
 | 
					    // workaround to support ; and , commands
 | 
				
			||||||
    mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO)
 | 
					    mapToFunctionAndProvideKeys("f", SneakMemoryHandler("f"), MappingMode.NXO)
 | 
				
			||||||
@@ -73,8 +61,8 @@ internal class IdeaVimSneakExtension : VimExtension {
 | 
				
			|||||||
    mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO)
 | 
					    mapToFunctionAndProvideKeys("t", SneakMemoryHandler("t"), MappingMode.NXO)
 | 
				
			||||||
    mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO)
 | 
					    mapToFunctionAndProvideKeys("T", SneakMemoryHandler("T"), MappingMode.NXO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mapToFunctionAndProvideKeys(";", SneakRepeatHandler(_highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO)
 | 
					    mapToFunctionAndProvideKeys(";", SneakRepeatHandler(highlightHandler, RepeatDirection.IDENTICAL), MappingMode.NXO)
 | 
				
			||||||
    mapToFunctionAndProvideKeys(",", SneakRepeatHandler(_highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO)
 | 
					    mapToFunctionAndProvideKeys(",", SneakRepeatHandler(highlightHandler, RepeatDirection.REVERSE), MappingMode.NXO)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private class SneakHandler(
 | 
					  private class SneakHandler(
 | 
				
			||||||
@@ -221,7 +209,6 @@ internal class IdeaVimSneakExtension : VimExtension {
 | 
				
			|||||||
  private class HighlightHandler {
 | 
					  private class HighlightHandler {
 | 
				
			||||||
    private var editor: Editor? = null
 | 
					    private var editor: Editor? = null
 | 
				
			||||||
    private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf()
 | 
					    private val sneakHighlighters: MutableSet<RangeHighlighter> = mutableSetOf()
 | 
				
			||||||
    private var timer: Timer? = null
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun highlightSneakRange(editor: Editor, range: TextRange) {
 | 
					    fun highlightSneakRange(editor: Editor, range: TextRange) {
 | 
				
			||||||
      clearAllSneakHighlighters()
 | 
					      clearAllSneakHighlighters()
 | 
				
			||||||
@@ -267,19 +254,13 @@ internal class IdeaVimSneakExtension : VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
 | 
					    private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
 | 
				
			||||||
      stopExistingTimer()
 | 
					      val timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
 | 
				
			||||||
      timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
 | 
					 | 
				
			||||||
        if (editor?.isDisposed != true) {
 | 
					        if (editor?.isDisposed != true) {
 | 
				
			||||||
          editor?.markupModel?.removeHighlighter(highlighter)
 | 
					          editor?.markupModel?.removeHighlighter(highlighter)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      timer?.isRepeats = false
 | 
					      timer.isRepeats = false
 | 
				
			||||||
      timer?.start()
 | 
					      timer.start()
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun stopExistingTimer() {
 | 
					 | 
				
			||||||
      timer?.stop()
 | 
					 | 
				
			||||||
      timer?.actionListeners?.forEach { it.actionPerformed(null) }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun getHighlightTextAttributes() = TextAttributes(
 | 
					    private fun getHighlightTextAttributes() = TextAttributes(
 | 
				
			||||||
@@ -326,7 +307,7 @@ private fun VimExtension.mapToFunctionAndProvideKeys(
 | 
				
			|||||||
    VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
 | 
					    VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  val filteredFromModes = mappingModes.filterNotTo(HashSet()) {
 | 
					  val filteredFromModes = mappingModes.filterNotTo(HashSet()) {
 | 
				
			||||||
    injector.keyGroup.getKeyMapping(it).getLayer(fromKeys) != null
 | 
					    injector.keyGroup.hasmapfrom(it, fromKeys)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val doubleFiltered = mappingModes
 | 
					  val doubleFiltered = mappingModes
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,11 +47,11 @@ import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
 | 
				
			|||||||
import com.maddyhome.idea.vim.put.PutData
 | 
					import com.maddyhome.idea.vim.put.PutData
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.returnTo
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.selectionType
 | 
					import com.maddyhome.idea.vim.state.mode.selectionType
 | 
				
			||||||
import org.jetbrains.annotations.NonNls
 | 
					import org.jetbrains.annotations.NonNls
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.returnTo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Port of vim-surround.
 | 
					 * Port of vim-surround.
 | 
				
			||||||
@@ -161,17 +161,17 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
      fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) {
 | 
					      fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
 | 
				
			||||||
        editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
 | 
					        editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: SurroundPair?) {
 | 
					      fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
 | 
				
			||||||
        // Save old register values for carets
 | 
					        // Save old register values for carets
 | 
				
			||||||
        val surroundings = editor.sortedCarets()
 | 
					        val surroundings = editor.sortedCarets()
 | 
				
			||||||
          .map {
 | 
					          .map {
 | 
				
			||||||
            val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
 | 
					            val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
 | 
				
			||||||
            setRegisterForCaret(REGISTER, it, null)
 | 
					            setRegisterForCaret(REGISTER, it, null)
 | 
				
			||||||
            SurroundingInfo(it, null, oldValue, false)
 | 
					            SurroundingInfo(it, null, oldValue)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Delete surrounding's content
 | 
					        // Delete surrounding's content
 | 
				
			||||||
@@ -187,25 +187,21 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          val registerValue = getRegisterForCaret(REGISTER, it.caret)
 | 
					          val registerValue = getRegisterForCaret(REGISTER, it.caret)
 | 
				
			||||||
          val innerValue = if (registerValue.isNullOrEmpty()) emptyList() else registerValue
 | 
					          val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue
 | 
				
			||||||
          it.innerText = innerValue
 | 
					          it.innerText = innerValue
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // Valid surroundings are only those that:
 | 
					        surroundings.forEach {
 | 
				
			||||||
          // - are validly wrapping with surround characters (i.e. parenthesis, brackets, tags, quotes, etc.);
 | 
					          if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
 | 
				
			||||||
          // - or have non-empty inner text (e.g. when we are surrounding words: `csw"`)
 | 
					            it.innerText = emptyList()
 | 
				
			||||||
          if (currentSurrounding != null || innerValue.isNotEmpty()) {
 | 
					 | 
				
			||||||
            it.isValidSurrounding = true
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        surroundings
 | 
					        surroundings
 | 
				
			||||||
          .filter { it.isValidSurrounding } // we do nothing with carets that are not inside the surrounding
 | 
					          .filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
 | 
				
			||||||
          .map { surrounding ->
 | 
					          .map { surrounding ->
 | 
				
			||||||
            val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
 | 
					            val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
 | 
				
			||||||
            val text = newSurround?.let {
 | 
					            val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
 | 
				
			||||||
              val trimmedValue = if (newSurround.shouldTrim) innerValue.trim() else innerValue
 | 
					 | 
				
			||||||
              it.first + trimmedValue + it.second
 | 
					 | 
				
			||||||
            } ?: innerValue
 | 
					 | 
				
			||||||
            val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
 | 
					            val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
 | 
				
			||||||
            val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
 | 
					            val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -258,7 +254,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var isValidSurrounding: Boolean) {
 | 
					  private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?) {
 | 
				
			||||||
    fun restoreRegister() {
 | 
					    fun restoreRegister() {
 | 
				
			||||||
      setRegisterForCaret(REGISTER, caret, oldRegisterContent)
 | 
					      setRegisterForCaret(REGISTER, caret, oldRegisterContent)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -301,7 +297,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
      return true
 | 
					      return true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: SurroundPair, count: Int) {
 | 
					    private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
 | 
				
			||||||
      // XXX: Will it work with line-wise or block-wise selections?
 | 
					      // XXX: Will it work with line-wise or block-wise selections?
 | 
				
			||||||
      val primaryCaret = editor.caretModel.primaryCaret
 | 
					      val primaryCaret = editor.caretModel.primaryCaret
 | 
				
			||||||
      val range = getSurroundRange(primaryCaret.vim)
 | 
					      val range = getSurroundRange(primaryCaret.vim)
 | 
				
			||||||
@@ -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()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,12 +29,14 @@ import com.maddyhome.idea.vim.state.mode.Mode;
 | 
				
			|||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.EnumSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Port of vim-entire:
 | 
					 * Port of vim-entire:
 | 
				
			||||||
 * <a href="https://github.com/kana/vim-textobj-entire">vim-textobj-entire</a>
 | 
					 * https://github.com/kana/vim-textobj-entire
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * vim-textobj-entire provides two text objects:
 | 
					 * vim-textobj-entire provides two text objects:
 | 
				
			||||||
@@ -49,7 +51,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingI
 | 
				
			|||||||
 * </ul>
 | 
					 * </ul>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See also the reference manual for more details at:
 | 
					 * See also the reference manual for more details at:
 | 
				
			||||||
 * <a href="https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt">text-obj-entire.txt</a>
 | 
					 * https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Alexandre Grison (@agrison)
 | 
					 * @author Alexandre Grison (@agrison)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -92,12 +94,13 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
				
			|||||||
        this.ignoreLeadingAndTrailing = ignoreLeadingAndTrailing;
 | 
					        this.ignoreLeadingAndTrailing = ignoreLeadingAndTrailing;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @Nullable
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
					      public TextRange getRange(@NotNull VimEditor editor,
 | 
				
			||||||
                                          @NotNull ImmutableVimCaret caret,
 | 
					                                @NotNull ImmutableVimCaret caret,
 | 
				
			||||||
                                          @NotNull ExecutionContext context,
 | 
					                                @NotNull ExecutionContext context,
 | 
				
			||||||
                                          int count,
 | 
					                                int count,
 | 
				
			||||||
                                          int rawCount) {
 | 
					                                int rawCount) {
 | 
				
			||||||
        int start = 0, end = ((IjVimEditor)editor).getEditor().getDocument().getTextLength();
 | 
					        int start = 0, end = ((IjVimEditor)editor).getEditor().getDocument().getTextLength();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // for the `ie` text object we don't want leading an trailing spaces
 | 
					        // for the `ie` text object we don't want leading an trailing spaces
 | 
				
			||||||
@@ -122,22 +125,24 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
				
			|||||||
        return new TextRange(start, end);
 | 
					        return new TextRange(start, end);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @NotNull
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
					      public TextObjectVisualType getVisualType() {
 | 
				
			||||||
        return TextObjectVisualType.CHARACTER_WISE;
 | 
					        return TextObjectVisualType.CHARACTER_WISE;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
					    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
				
			||||||
 | 
					      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
				
			||||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
					      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
				
			||||||
 | 
					      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
 | 
					      final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
 | 
				
			||||||
      //noinspection DuplicatedCode
 | 
					      //noinspection DuplicatedCode
 | 
				
			||||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
					      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
				
			||||||
        int count0 = operatorArguments.getCount0();
 | 
					 | 
				
			||||||
        ((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
					        ((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
				
			||||||
          final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
 | 
					          final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, count, 0);
 | 
				
			||||||
          if (range != null) {
 | 
					          if (range != null) {
 | 
				
			||||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
					            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
				
			||||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
					              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
				
			||||||
@@ -150,7 +155,9 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
					        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
				
			||||||
 | 
					                                                                                         textObjectHandler, Command.Type.MOTION,
 | 
				
			||||||
 | 
					                                                                                         EnumSet.noneOf(CommandFlags.class))));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,12 +30,14 @@ import com.maddyhome.idea.vim.state.mode.Mode;
 | 
				
			|||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.EnumSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
				
			||||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
 | 
					import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Port of vim-indent-object:
 | 
					 * Port of vim-indent-object:
 | 
				
			||||||
 * <a href="https://github.com/michaeljsmith/vim-indent-object">vim-indent-object</a>
 | 
					 * https://github.com/michaeljsmith/vim-indent-object
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * vim-indent-object provides these text objects based on the cursor line's indentation:
 | 
					 * vim-indent-object provides these text objects based on the cursor line's indentation:
 | 
				
			||||||
@@ -47,7 +49,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
 | 
				
			|||||||
 * </ul>
 | 
					 * </ul>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See also the reference manual for more details at:
 | 
					 * See also the reference manual for more details at:
 | 
				
			||||||
 * <a href="https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt">indent-object.txt</a>
 | 
					 * https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Shrikant Kandula (@sharat87)
 | 
					 * @author Shrikant Kandula (@sharat87)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -96,12 +98,13 @@ public class VimIndentObject implements VimExtension {
 | 
				
			|||||||
        this.includeBelow = includeBelow;
 | 
					        this.includeBelow = includeBelow;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @Nullable
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
					      public TextRange getRange(@NotNull VimEditor editor,
 | 
				
			||||||
                                          @NotNull ImmutableVimCaret caret,
 | 
					                                @NotNull ImmutableVimCaret caret,
 | 
				
			||||||
                                          @NotNull ExecutionContext context,
 | 
					                                @NotNull ExecutionContext context,
 | 
				
			||||||
                                          int count,
 | 
					                                int count,
 | 
				
			||||||
                                          int rawCount) {
 | 
					                                int rawCount) {
 | 
				
			||||||
        final CharSequence charSequence = ((IjVimEditor)editor).getEditor().getDocument().getCharsSequence();
 | 
					        final CharSequence charSequence = ((IjVimEditor)editor).getEditor().getDocument().getCharsSequence();
 | 
				
			||||||
        final int caretOffset = ((IjVimCaret)caret).getCaret().getOffset();
 | 
					        final int caretOffset = ((IjVimCaret)caret).getCaret().getOffset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -246,8 +249,9 @@ public class VimIndentObject implements VimExtension {
 | 
				
			|||||||
        return new TextRange(upperBoundaryOffset, lowerBoundaryOffset);
 | 
					        return new TextRange(upperBoundaryOffset, lowerBoundaryOffset);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @NotNull
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
					      public TextObjectVisualType getVisualType() {
 | 
				
			||||||
        return TextObjectVisualType.LINE_WISE;
 | 
					        return TextObjectVisualType.LINE_WISE;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,14 +264,15 @@ public class VimIndentObject implements VimExtension {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
					    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
				
			||||||
      IjVimEditor vimEditor = (IjVimEditor)editor;
 | 
					      IjVimEditor vimEditor = (IjVimEditor)editor;
 | 
				
			||||||
 | 
					      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
				
			||||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
					      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
				
			||||||
 | 
					      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
 | 
					      final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
					      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
				
			||||||
        int count0 = operatorArguments.getCount0();
 | 
					 | 
				
			||||||
        ((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
					        ((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
				
			||||||
          final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
 | 
					          final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, count, 0);
 | 
				
			||||||
          if (range != null) {
 | 
					          if (range != null) {
 | 
				
			||||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
					            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
				
			||||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
					              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
				
			||||||
@@ -280,7 +285,9 @@ public class VimIndentObject implements VimExtension {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
					        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
				
			||||||
 | 
					                                                                                         textObjectHandler, Command.Type.MOTION,
 | 
				
			||||||
 | 
					                                                                                         EnumSet.noneOf(CommandFlags.class))));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,12 +36,9 @@ import com.maddyhome.idea.vim.helper.inInsertMode
 | 
				
			|||||||
import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance
 | 
					import com.maddyhome.idea.vim.key.KeyHandlerKeeper.Companion.getInstance
 | 
				
			||||||
import com.maddyhome.idea.vim.listener.VimInsertListener
 | 
					import com.maddyhome.idea.vim.listener.VimInsertListener
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
					import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimCopiedText
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides all the insert/replace related functionality
 | 
					 * Provides all the insert/replace related functionality
 | 
				
			||||||
@@ -64,15 +61,9 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
    val editor = (vimEditor as IjVimEditor).editor
 | 
					    val editor = (vimEditor as IjVimEditor).editor
 | 
				
			||||||
    val ijContext = context.ij
 | 
					    val ijContext = context.ij
 | 
				
			||||||
    val doc = vimEditor.editor.document
 | 
					    val doc = vimEditor.editor.document
 | 
				
			||||||
 | 
					 | 
				
			||||||
    val undo = injector.undo
 | 
					    val undo = injector.undo
 | 
				
			||||||
    when (undo) {
 | 
					    val nanoTime = System.nanoTime()
 | 
				
			||||||
      is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
 | 
					    vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
 | 
				
			||||||
      is VimTimestampBasedUndoService -> {
 | 
					 | 
				
			||||||
        val nanoTime = System.nanoTime()
 | 
					 | 
				
			||||||
        vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    CommandProcessor.getInstance().executeCommand(
 | 
					    CommandProcessor.getInstance().executeCommand(
 | 
				
			||||||
      editor.project, {
 | 
					      editor.project, {
 | 
				
			||||||
        ApplicationManager.getApplication()
 | 
					        ApplicationManager.getApplication()
 | 
				
			||||||
@@ -112,11 +103,6 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun processBackspace(editor: VimEditor, context: ExecutionContext) {
 | 
					 | 
				
			||||||
    injector.actionExecutor.executeAction(editor, name = IdeActions.ACTION_EDITOR_BACKSPACE, context = context)
 | 
					 | 
				
			||||||
    injector.scroll.scrollCaretIntoView(editor)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun restoreCursor(editor: VimEditor, caret: VimCaret, startLine: Int) {
 | 
					  private fun restoreCursor(editor: VimEditor, caret: VimCaret, startLine: Int) {
 | 
				
			||||||
    if (caret != editor.primaryCaret()) {
 | 
					    if (caret != editor.primaryCaret()) {
 | 
				
			||||||
      (editor as IjVimEditor).editor.caretModel.addCaret(
 | 
					      (editor as IjVimEditor).editor.caretModel.addCaret(
 | 
				
			||||||
@@ -145,10 +131,10 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux
 | 
					    // FIXME: Here we do selection, and it is not a good idea, because it updates primary selection in Linux
 | 
				
			||||||
    // FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method
 | 
					    // FIXME: I'll leave here a dirty fix that restores primary selection, but it would be better to rewrite this method
 | 
				
			||||||
    var copiedText: IjVimCopiedText? = null
 | 
					    var primaryTextAndTransferableData: Pair<String, List<Any>?>? = null
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      if (injector.registerGroup.isPrimaryRegisterSupported()) {
 | 
					      if (injector.registerGroup.isPrimaryRegisterSupported()) {
 | 
				
			||||||
        copiedText = injector.clipboardManager.getPrimaryContent(editor, context) as IjVimCopiedText
 | 
					        primaryTextAndTransferableData = injector.clipboardManager.getPrimaryTextAndTransferableData()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (e: Exception) {
 | 
					    } catch (e: Exception) {
 | 
				
			||||||
      // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
 | 
					      // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
 | 
				
			||||||
@@ -174,8 +160,12 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
      afterAction.invoke()
 | 
					      afterAction.invoke()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      if (copiedText != null) {
 | 
					      if (primaryTextAndTransferableData != null) {
 | 
				
			||||||
        injector.clipboardManager.setPrimaryContent(editor, context, copiedText)
 | 
					        injector.clipboardManager.setPrimaryText(
 | 
				
			||||||
 | 
					          primaryTextAndTransferableData.first,
 | 
				
			||||||
 | 
					          primaryTextAndTransferableData.first,
 | 
				
			||||||
 | 
					          primaryTextAndTransferableData.second ?: emptyList()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (e: Exception) {
 | 
					    } catch (e: Exception) {
 | 
				
			||||||
      // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
 | 
					      // FIXME: [isPrimaryRegisterSupported()] is not implemented perfectly, so there might be thrown an exception after trying to access the primary selection
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										78
									
								
								src/main/java/com/maddyhome/idea/vim/group/DigraphGroup.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/main/java/com/maddyhome/idea/vim/group/DigraphGroup.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.Logger;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimEditor;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class DigraphGroup extends VimDigraphGroupBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void showDigraphs(@NotNull VimEditor editor) {
 | 
				
			||||||
 | 
					    int width = EditorHelper.getApproximateScreenWidth(((IjVimEditor) editor).getEditor());
 | 
				
			||||||
 | 
					    if (width < 10) {
 | 
				
			||||||
 | 
					      width = 80;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int colCount = width / 12;
 | 
				
			||||||
 | 
					    int height = (int)Math.ceil((double) getDigraphs().size() / (double)colCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (logger.isDebugEnabled()) {
 | 
				
			||||||
 | 
					      logger.debug("width=" + width);
 | 
				
			||||||
 | 
					      logger.debug("colCount=" + colCount);
 | 
				
			||||||
 | 
					      logger.debug("height=" + height);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    StringBuilder res = new StringBuilder();
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    for (Character code : getKeys().keySet()) {
 | 
				
			||||||
 | 
					      String key = getKeys().get(code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      res.append(key);
 | 
				
			||||||
 | 
					      res.append(' ');
 | 
				
			||||||
 | 
					      if (code < 32) {
 | 
				
			||||||
 | 
					        res.append('^');
 | 
				
			||||||
 | 
					        res.append((char)(code + '@'));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if (code >= 128 && code <= 159) {
 | 
				
			||||||
 | 
					        res.append('~');
 | 
				
			||||||
 | 
					        res.append((char)(code - 128 + '@'));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        res.append(code);
 | 
				
			||||||
 | 
					        res.append(' ');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      res.append(' ');
 | 
				
			||||||
 | 
					      if (code < 0x1000) {
 | 
				
			||||||
 | 
					        res.append('0');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (code < 0x100) {
 | 
				
			||||||
 | 
					        res.append('0');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (code < 0x10) {
 | 
				
			||||||
 | 
					        res.append('0');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      res.append(Integer.toHexString(code));
 | 
				
			||||||
 | 
					      res.append("  ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      cnt++;
 | 
				
			||||||
 | 
					      if (cnt == colCount) {
 | 
				
			||||||
 | 
					        res.append('\n');
 | 
				
			||||||
 | 
					        cnt = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ExOutputModel.getInstance(((IjVimEditor) editor).getEditor()).output(res.toString());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -374,9 +374,9 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
 | 
				
			|||||||
          if (activeCommandLine != null) {
 | 
					          if (activeCommandLine != null) {
 | 
				
			||||||
            activeCommandLine.close(true, false);
 | 
					            activeCommandLine.close(true, false);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          VimOutputPanel outputPanel = injector.getOutputPanel().getCurrentOutputPanel();
 | 
					          ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
 | 
				
			||||||
          if (outputPanel != null) {
 | 
					          if (exOutputModel != null) {
 | 
				
			||||||
            outputPanel.close();
 | 
					            exOutputModel.close();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
 | 
					          VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
 | 
				
			||||||
          if (modalInput != null) {
 | 
					          if (modalInput != null) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
				
			|||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.execute
 | 
					import com.maddyhome.idea.vim.newapi.execute
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.VimStateMachine.Companion.getInstance
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
 | 
					import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,9 @@ import com.intellij.openapi.components.State;
 | 
				
			|||||||
import com.intellij.openapi.components.Storage;
 | 
					import com.intellij.openapi.components.Storage;
 | 
				
			||||||
import com.intellij.openapi.diagnostic.Logger;
 | 
					import com.intellij.openapi.diagnostic.Logger;
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
import com.maddyhome.idea.vim.history.*;
 | 
					import com.maddyhome.idea.vim.history.HistoryBlock;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.history.HistoryEntry;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.history.VimHistoryBase;
 | 
				
			||||||
import org.jdom.Element;
 | 
					import org.jdom.Element;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
@@ -33,20 +35,21 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
				
			|||||||
    logger.debug("saveData");
 | 
					    logger.debug("saveData");
 | 
				
			||||||
    Element hist = new Element("history");
 | 
					    Element hist = new Element("history");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (Type type : getHistories().keySet()) {
 | 
					    saveData(hist, SEARCH);
 | 
				
			||||||
      saveData(hist, type);
 | 
					    saveData(hist, COMMAND);
 | 
				
			||||||
    }
 | 
					    saveData(hist, EXPRESSION);
 | 
				
			||||||
 | 
					    saveData(hist, INPUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    element.addContent(hist);
 | 
					    element.addContent(hist);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void saveData(@NotNull Element element, VimHistory.Type type) {
 | 
					  private void saveData(@NotNull Element element, String key) {
 | 
				
			||||||
    final HistoryBlock block = getHistories().get(type);
 | 
					    final HistoryBlock block = getHistories().get(key);
 | 
				
			||||||
    if (block == null) {
 | 
					    if (block == null) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final Element root = new Element("history-" + typeToKey(type));
 | 
					    final Element root = new Element("history-" + key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (HistoryEntry entry : block.getEntries()) {
 | 
					    for (HistoryEntry entry : block.getEntries()) {
 | 
				
			||||||
      final Element entryElement = new Element("entry");
 | 
					      final Element entryElement = new Element("entry");
 | 
				
			||||||
@@ -64,10 +67,10 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (Element child : hist.getChildren()) {
 | 
					    readData(hist, SEARCH);
 | 
				
			||||||
      String key = child.getName().replace("history-", "");
 | 
					    readData(hist, COMMAND);
 | 
				
			||||||
      readData(hist, key);
 | 
					    readData(hist, EXPRESSION);
 | 
				
			||||||
    }
 | 
					    readData(hist, INPUT);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void readData(@NotNull Element element, String key) {
 | 
					  private void readData(@NotNull Element element, String key) {
 | 
				
			||||||
@@ -77,7 +80,7 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    block = new HistoryBlock();
 | 
					    block = new HistoryBlock();
 | 
				
			||||||
    getHistories().put(getTypeForString(key), block);
 | 
					    getHistories().put(key, block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final Element root = element.getChild("history-" + key);
 | 
					    final Element root = element.getChild("history-" + key);
 | 
				
			||||||
    if (root != null) {
 | 
					    if (root != null) {
 | 
				
			||||||
@@ -91,25 +94,6 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private String typeToKey(VimHistory.Type type) {
 | 
					 | 
				
			||||||
    if (type instanceof VimHistory.Type.Search) {
 | 
					 | 
				
			||||||
      return SEARCH;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (type instanceof VimHistory.Type.Command) {
 | 
					 | 
				
			||||||
      return COMMAND;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (type instanceof VimHistory.Type.Expression) {
 | 
					 | 
				
			||||||
      return EXPRESSION;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (type instanceof VimHistory.Type.Input) {
 | 
					 | 
				
			||||||
      return INPUT;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (type instanceof VimHistory.Type.Custom) {
 | 
					 | 
				
			||||||
      return ((Type.Custom) type).getId();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return "unreachable";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Nullable
 | 
					  @Nullable
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Element getState() {
 | 
					  public Element getState() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.group;
 | 
					package com.maddyhome.idea.vim.group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.collect.ImmutableList;
 | 
				
			||||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
 | 
					import com.intellij.codeInsight.lookup.impl.LookupImpl;
 | 
				
			||||||
import com.intellij.openapi.actionSystem.*;
 | 
					import com.intellij.openapi.actionSystem.*;
 | 
				
			||||||
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
 | 
					import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
 | 
				
			||||||
@@ -16,16 +17,21 @@ import com.intellij.openapi.application.ApplicationManager;
 | 
				
			|||||||
import com.intellij.openapi.components.PersistentStateComponent;
 | 
					import com.intellij.openapi.components.PersistentStateComponent;
 | 
				
			||||||
import com.intellij.openapi.components.State;
 | 
					import com.intellij.openapi.components.State;
 | 
				
			||||||
import com.intellij.openapi.components.Storage;
 | 
					import com.intellij.openapi.components.Storage;
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.Logger;
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.Editor;
 | 
				
			||||||
import com.intellij.openapi.keymap.Keymap;
 | 
					import com.intellij.openapi.keymap.Keymap;
 | 
				
			||||||
import com.intellij.openapi.keymap.KeymapManager;
 | 
					import com.intellij.openapi.keymap.KeymapManager;
 | 
				
			||||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
 | 
					import com.intellij.openapi.keymap.ex.KeymapManagerEx;
 | 
				
			||||||
import com.intellij.util.containers.MultiMap;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.EventFacade;
 | 
					import com.maddyhome.idea.vim.EventFacade;
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
					import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
				
			||||||
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
 | 
					import com.maddyhome.idea.vim.action.change.LazyVimCommand;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.*;
 | 
					import com.maddyhome.idea.vim.api.NativeAction;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimEditor;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimInjectorKt;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimKeyGroupBase;
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode;
 | 
					import com.maddyhome.idea.vim.command.MappingMode;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
				
			||||||
import com.maddyhome.idea.vim.key.*;
 | 
					import com.maddyhome.idea.vim.key.*;
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjNativeAction;
 | 
					import com.maddyhome.idea.vim.newapi.IjNativeAction;
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
				
			||||||
@@ -55,6 +61,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
  private static final @NonNls String OWNER_ATTRIBUTE = "owner";
 | 
					  private static final @NonNls String OWNER_ATTRIBUTE = "owner";
 | 
				
			||||||
  private static final String TEXT_ELEMENT = "text";
 | 
					  private static final String TEXT_ELEMENT = "text";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static final Logger logger = Logger.getInstance(KeyGroup.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
 | 
					  public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
 | 
				
			||||||
    EventFacade.getInstance()
 | 
					    EventFacade.getInstance()
 | 
				
			||||||
      .registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
 | 
					      .registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
 | 
				
			||||||
@@ -72,6 +80,25 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
                                                          ((IjVimEditor)editor).getEditor().getComponent());
 | 
					                                                          ((IjVimEditor)editor).getEditor().getComponent());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull Editor editor) {
 | 
				
			||||||
 | 
					    List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
 | 
				
			||||||
 | 
					    final StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					    for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
 | 
				
			||||||
 | 
					      MappingInfo mappingInfo = row.getSecond();
 | 
				
			||||||
 | 
					      builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
 | 
				
			||||||
 | 
					      builder.append(" ");
 | 
				
			||||||
 | 
					      builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
 | 
				
			||||||
 | 
					      builder.append(" ");
 | 
				
			||||||
 | 
					      builder.append(mappingInfo.isRecursive() ? " " : "*");
 | 
				
			||||||
 | 
					      builder.append(" ");
 | 
				
			||||||
 | 
					      builder.append(mappingInfo.getPresentableString());
 | 
				
			||||||
 | 
					      builder.append("\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ExOutputModel.getInstance(editor).output(builder.toString());
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public void updateShortcutKeysRegistration() {
 | 
					  public void updateShortcutKeysRegistration() {
 | 
				
			||||||
    for (VimEditor editor : injector.getEditorGroup().getEditors()) {
 | 
					    for (VimEditor editor : injector.getEditorGroup().getEditors()) {
 | 
				
			||||||
@@ -194,7 +221,8 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
      registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
 | 
					      registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (MappingMode mappingMode : command.getModes()) {
 | 
					      for (MappingMode mappingMode : command.getModes()) {
 | 
				
			||||||
        getBuiltinCommandsTrie(mappingMode).add(keyStrokes, command);
 | 
					        Node<LazyVimCommand> node = getKeyRoot(mappingMode);
 | 
				
			||||||
 | 
					        NodesKt.addLeafs(node, keyStrokes, command);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -219,79 +247,53 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
    return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0]));
 | 
					    return new CustomShortcutSet(shortcuts.toArray(new Shortcut[0]));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static @NotNull List<Pair<Set<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes,
 | 
					  private static @NotNull List<Pair<EnumSet<MappingMode>, MappingInfo>> getKeyMappingRows(@NotNull Set<? extends MappingMode> modes) {
 | 
				
			||||||
                                                                                      @NotNull List<? extends KeyStroke> prefix) {
 | 
					    final Map<ImmutableList<KeyStroke>, EnumSet<MappingMode>> actualModes = new HashMap<>();
 | 
				
			||||||
    // Some map commands set a mapping for more than one mode (e.g. `map` sets for Normal, Visual, Select and
 | 
					 | 
				
			||||||
    // Op-pending). Vim treats this as a single mapping, and when listing all maps only lists it once, with the
 | 
					 | 
				
			||||||
    // appropriate mode indicator(s) in the first column (NVO is a space char). If the lhs mapping is changed or cleared
 | 
					 | 
				
			||||||
    // for one of the modes, the original mapping is still a single map for the remaining modes, and the indicator
 | 
					 | 
				
			||||||
    // changes. E.g. `map foo bar` followed by `sunmap foo` would result in `nox foo bar` in the output to `map`.
 | 
					 | 
				
			||||||
    // Vim doesn't do automatic grouping - `nmap foo bar` followed by `omap foo bar` and `vmap foo bar` would result in
 | 
					 | 
				
			||||||
    // 3 lines in the output to `map` - one for `n`, one for `o` and one for `v`.
 | 
					 | 
				
			||||||
    // We store mappings separately per mode (to simplify lookup, especially when matching prefixes), but want to have
 | 
					 | 
				
			||||||
    // the same behaviour as Vim in map output. So we store the original modes with the mapping and check they're still
 | 
					 | 
				
			||||||
    // valid as we collect output
 | 
					 | 
				
			||||||
    final List<Pair<Set<MappingMode>, MappingInfo>> rows = new ArrayList<>();
 | 
					 | 
				
			||||||
    final MultiMap<List<? extends KeyStroke>, Set<MappingMode>> multiModeMappings = MultiMap.create();
 | 
					 | 
				
			||||||
    final List<KeyStroke> fromKeys = new ArrayList<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (MappingMode mode : modes) {
 | 
					    for (MappingMode mode : modes) {
 | 
				
			||||||
      final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
 | 
					      final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
 | 
				
			||||||
 | 
					      for (List<? extends KeyStroke> fromKeys : mapping) {
 | 
				
			||||||
      final Iterator<KeyMappingEntry> iterator = mapping.getAll(prefix).iterator();
 | 
					        final ImmutableList<KeyStroke> key = ImmutableList.copyOf(fromKeys);
 | 
				
			||||||
      while (iterator.hasNext()) {
 | 
					        final EnumSet<MappingMode> value = actualModes.get(key);
 | 
				
			||||||
        final KeyMappingEntry entry = iterator.next();
 | 
					        final EnumSet<MappingMode> newValue;
 | 
				
			||||||
        final MappingInfo mappingInfo = entry.getMappingInfo();
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          newValue = value.clone();
 | 
				
			||||||
        final Set<@NotNull MappingMode> originalModes = mappingInfo.getOriginalModes();
 | 
					          newValue.add(mode);
 | 
				
			||||||
        if (originalModes.size() == 1) {
 | 
					 | 
				
			||||||
          rows.add(new Pair<>(originalModes, mappingInfo));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
          entry.collectPath(fromKeys);
 | 
					          newValue = EnumSet.of(mode);
 | 
				
			||||||
          if (!multiModeMappings.get(fromKeys).contains(originalModes)) {
 | 
					        }
 | 
				
			||||||
            multiModeMappings.putValue(new ArrayList<>(fromKeys), originalModes);
 | 
					        actualModes.put(key, newValue);
 | 
				
			||||||
            rows.add(new Pair<>(getModesForMapping(fromKeys, originalModes), mappingInfo));
 | 
					      }
 | 
				
			||||||
          }
 | 
					    }
 | 
				
			||||||
 | 
					    final List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = new ArrayList<>();
 | 
				
			||||||
 | 
					    for (Map.Entry<ImmutableList<KeyStroke>, EnumSet<MappingMode>> entry : actualModes.entrySet()) {
 | 
				
			||||||
 | 
					      final ArrayList<KeyStroke> fromKeys = new ArrayList<>(entry.getKey());
 | 
				
			||||||
 | 
					      final EnumSet<MappingMode> mappingModes = entry.getValue();
 | 
				
			||||||
 | 
					      if (!mappingModes.isEmpty()) {
 | 
				
			||||||
 | 
					        final MappingMode mode = mappingModes.iterator().next();
 | 
				
			||||||
 | 
					        final KeyMapping mapping = VimPlugin.getKey().getKeyMapping(mode);
 | 
				
			||||||
 | 
					        final MappingInfo mappingInfo = mapping.get(fromKeys);
 | 
				
			||||||
 | 
					        if (mappingInfo != null) {
 | 
				
			||||||
 | 
					          rows.add(new Pair<>(mappingModes, mappingInfo));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    rows.sort(Comparator.comparing(Pair<Set<MappingMode>, MappingInfo>::getSecond));
 | 
					    rows.sort(Comparator.comparing(Pair<EnumSet<MappingMode>, MappingInfo>::getSecond));
 | 
				
			||||||
    return rows;
 | 
					    return rows;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static @NotNull Set<MappingMode> getModesForMapping(@NotNull List<? extends KeyStroke> keyStrokes,
 | 
					 | 
				
			||||||
                                                              @NotNull Set<MappingMode> originalMappingModes) {
 | 
					 | 
				
			||||||
    final Set<MappingMode> actualModes = EnumSet.noneOf(MappingMode.class);
 | 
					 | 
				
			||||||
    for (MappingMode mode : originalMappingModes) {
 | 
					 | 
				
			||||||
      final MappingInfo mappingInfo = VimPlugin.getKey().getKeyMapping(mode).get(keyStrokes);
 | 
					 | 
				
			||||||
      if (mappingInfo != null && mappingInfo.getOriginalModes() == originalMappingModes) {
 | 
					 | 
				
			||||||
        actualModes.add(mode);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return actualModes;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
 | 
					  private static @NotNull @NonNls String getModesStringCode(@NotNull Set<MappingMode> modes) {
 | 
				
			||||||
    if (modes.equals(MappingMode.IC)) return "!";
 | 
					    if (modes.equals(MappingMode.NVO)) {
 | 
				
			||||||
    if (modes.equals(MappingMode.NVO)) return " ";
 | 
					      return "";
 | 
				
			||||||
    if (modes.equals(MappingMode.C)) return "c";
 | 
					 | 
				
			||||||
    if (modes.equals(MappingMode.I)) return "i";
 | 
					 | 
				
			||||||
    //if (modes.equals(MappingMode.L)) return "l";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The following modes are concatenated
 | 
					 | 
				
			||||||
    String mode = "";
 | 
					 | 
				
			||||||
    if (modes.containsAll(MappingMode.N)) mode += "n";
 | 
					 | 
				
			||||||
    if (modes.containsAll(MappingMode.O)) mode += "o";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (modes.containsAll(MappingMode.V)) {
 | 
					 | 
				
			||||||
      mode += "v";
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else if (modes.contains(MappingMode.INSERT)) {
 | 
				
			||||||
      if (modes.containsAll(MappingMode.X)) mode += "x";
 | 
					      return "i";
 | 
				
			||||||
      if (modes.containsAll(MappingMode.S)) mode += "s";
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return mode;
 | 
					    else if (modes.contains(MappingMode.NORMAL)) {
 | 
				
			||||||
 | 
					      return "n";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // TODO: Add more codes
 | 
				
			||||||
 | 
					    return "";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
 | 
					  private @NotNull List<AnAction> getActions(@NotNull Component component, @NotNull KeyStroke keyStroke) {
 | 
				
			||||||
@@ -355,23 +357,7 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull List<? extends KeyStroke> prefix, @NotNull VimEditor editor) {
 | 
					  public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
 | 
				
			||||||
    List<Pair<Set<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes, prefix);
 | 
					    return showKeyMappings(modes, ((IjVimEditor) editor).getEditor());
 | 
				
			||||||
 | 
					 | 
				
			||||||
    final StringBuilder builder = new StringBuilder();
 | 
					 | 
				
			||||||
    for (Pair<Set<MappingMode>, MappingInfo> row : rows) {
 | 
					 | 
				
			||||||
      MappingInfo mappingInfo = row.getSecond();
 | 
					 | 
				
			||||||
      builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 3, ' '));
 | 
					 | 
				
			||||||
      builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()) + " ", 12, ' '));
 | 
					 | 
				
			||||||
      builder.append(mappingInfo.isRecursive() ? " " : "*");  // Or `&` if script-local mappings being recursive
 | 
					 | 
				
			||||||
      builder.append(" ");  // Should be `@` if it's a buffer-local mapping
 | 
					 | 
				
			||||||
      builder.append(mappingInfo.getPresentableString());
 | 
					 | 
				
			||||||
      builder.append("\n");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
 | 
					 | 
				
			||||||
    outputPanel.addText(builder.toString(), true);
 | 
					 | 
				
			||||||
    outputPanel.show();
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ import com.maddyhome.idea.vim.command.Argument
 | 
				
			|||||||
import com.maddyhome.idea.vim.command.MotionType
 | 
					import com.maddyhome.idea.vim.command.MotionType
 | 
				
			||||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.common.TextRange
 | 
					import com.maddyhome.idea.vim.common.TextRange
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.ExternalActionHandler
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.Motion
 | 
					import com.maddyhome.idea.vim.handler.Motion
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
 | 
					import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.MotionActionHandler
 | 
					import com.maddyhome.idea.vim.handler.MotionActionHandler
 | 
				
			||||||
@@ -193,16 +193,21 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
      argument: Argument,
 | 
					      argument: Argument,
 | 
				
			||||||
      operatorArguments: OperatorArguments,
 | 
					      operatorArguments: OperatorArguments,
 | 
				
			||||||
    ): TextRange? {
 | 
					    ): TextRange? {
 | 
				
			||||||
      if (argument !is Argument.Motion) {
 | 
					 | 
				
			||||||
        throw RuntimeException("Unexpected argument passed to getMotionRange2: $argument")
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      var start: Int
 | 
					      var start: Int
 | 
				
			||||||
      var end: Int
 | 
					      var end: Int
 | 
				
			||||||
 | 
					      if (argument.type === Argument.Type.OFFSETS) {
 | 
				
			||||||
 | 
					        val offsets = argument.offsets[caret.vim] ?: return null
 | 
				
			||||||
 | 
					        val (first, second) = offsets.getNativeStartAndEnd()
 | 
				
			||||||
 | 
					        start = first
 | 
				
			||||||
 | 
					        end = second
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        val cmd = argument.motion
 | 
				
			||||||
 | 
					        // Normalize the counts between the command and the motion argument
 | 
				
			||||||
 | 
					        val cnt = cmd.count * operatorArguments.count1
 | 
				
			||||||
 | 
					        val raw = if (operatorArguments.count0 == 0 && cmd.rawCount == 0) 0 else cnt
 | 
				
			||||||
 | 
					        if (cmd.action is MotionActionHandler) {
 | 
				
			||||||
 | 
					          val action = cmd.action as MotionActionHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val action = argument.motion
 | 
					 | 
				
			||||||
      when (action) {
 | 
					 | 
				
			||||||
        is MotionActionHandler -> {
 | 
					 | 
				
			||||||
          // This is where we are now
 | 
					          // This is where we are now
 | 
				
			||||||
          start = caret.offset
 | 
					          start = caret.offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,8 +216,8 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
            editor.vim,
 | 
					            editor.vim,
 | 
				
			||||||
            caret.vim,
 | 
					            caret.vim,
 | 
				
			||||||
            IjEditorExecutionContext(context!!),
 | 
					            IjEditorExecutionContext(context!!),
 | 
				
			||||||
            argument.argument,
 | 
					            cmd.argument,
 | 
				
			||||||
            operatorArguments
 | 
					            operatorArguments.withCount0(raw),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // Invalid motion
 | 
					          // Invalid motion
 | 
				
			||||||
@@ -228,32 +233,22 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
              end++
 | 
					              end++
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        } else if (cmd.action is TextObjectActionHandler) {
 | 
				
			||||||
 | 
					          val action = cmd.action as TextObjectActionHandler
 | 
				
			||||||
        is TextObjectActionHandler -> {
 | 
					          val range =
 | 
				
			||||||
          val range = action.getRange(
 | 
					            action.getRange(editor.vim, caret.vim, IjEditorExecutionContext(context!!), cnt, raw) ?: return null
 | 
				
			||||||
            editor.vim,
 | 
					 | 
				
			||||||
            caret.vim,
 | 
					 | 
				
			||||||
            IjEditorExecutionContext(context!!),
 | 
					 | 
				
			||||||
            operatorArguments.count1,
 | 
					 | 
				
			||||||
            operatorArguments.count0
 | 
					 | 
				
			||||||
          ) ?: return null
 | 
					 | 
				
			||||||
          start = range.startOffset
 | 
					          start = range.startOffset
 | 
				
			||||||
          end = range.endOffset
 | 
					          end = range.endOffset
 | 
				
			||||||
          if (argument.isLinewiseMotion()) end--
 | 
					          if (cmd.isLinewiseMotion()) end--
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          throw RuntimeException(
 | 
				
			||||||
 | 
					            "Commands doesn't take " + cmd.action.javaClass.simpleName + " as an operator",
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        is ExternalActionHandler -> {
 | 
					 | 
				
			||||||
          val range = action.getRange(caret.vim) ?: return null
 | 
					 | 
				
			||||||
          start = range.startOffset
 | 
					 | 
				
			||||||
          end = range.endOffset
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        else -> throw RuntimeException("Commands doesn't take " + action.javaClass.simpleName + " as an operator")
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
 | 
					      // This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
 | 
				
			||||||
      val id = argument.motion.id
 | 
					      val id = argument.motion.action.id
 | 
				
			||||||
      if (id == VimChangeGroupBase.VIM_MOTION_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_BIG_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_CAMEL_RIGHT) {
 | 
					      if (id == VimChangeGroupBase.VIM_MOTION_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_BIG_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_CAMEL_RIGHT) {
 | 
				
			||||||
        val text = editor.document.charsSequence.subSequence(start, end).toString()
 | 
					        val text = editor.document.charsSequence.subSequence(start, end).toString()
 | 
				
			||||||
        val lastNewLine = text.lastIndexOf('\n')
 | 
					        val lastNewLine = text.lastIndexOf('\n')
 | 
				
			||||||
@@ -263,7 +258,6 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					 | 
				
			||||||
      return TextRange(start, end)
 | 
					      return TextRange(start, end)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -323,7 +317,7 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
              is Mode.CMD_LINE -> {
 | 
					              is Mode.CMD_LINE -> {
 | 
				
			||||||
                val commandLine = injector.commandLine.getActiveCommandLine() ?: return
 | 
					                val commandLine = injector.commandLine.getActiveCommandLine() ?: return
 | 
				
			||||||
                commandLine.close(refocusOwningEditor = false, resetCaret = false)
 | 
					                commandLine.close(refocusOwningEditor = false, resetCaret = false)
 | 
				
			||||||
                injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
					                ExOutputModel.tryGetInstance(editor)?.close()
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              else -> {}
 | 
					              else -> {}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,6 @@ import com.intellij.application.options.CodeStyle
 | 
				
			|||||||
import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction
 | 
					import com.intellij.codeStyle.AbstractConvertLineSeparatorsAction
 | 
				
			||||||
import com.intellij.openapi.Disposable
 | 
					import com.intellij.openapi.Disposable
 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					 | 
				
			||||||
import com.intellij.openapi.editor.EditorKind
 | 
					import com.intellij.openapi.editor.EditorKind
 | 
				
			||||||
import com.intellij.openapi.editor.EditorSettings.LineNumerationType
 | 
					import com.intellij.openapi.editor.EditorSettings.LineNumerationType
 | 
				
			||||||
import com.intellij.openapi.editor.ScrollPositionCalculator
 | 
					import com.intellij.openapi.editor.ScrollPositionCalculator
 | 
				
			||||||
@@ -20,6 +19,8 @@ import com.intellij.openapi.editor.ex.EditorEx
 | 
				
			|||||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
 | 
					import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
 | 
				
			||||||
import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces
 | 
					import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
					import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.TextEditor
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil
 | 
					import com.intellij.openapi.fileEditor.impl.LoadTextUtil
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl
 | 
					import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl
 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
@@ -157,24 +158,25 @@ internal class OptionGroup : VimOptionGroupBase(), IjVimOptionGroup, InternalOpt
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    fun editorReleased(editor: Editor) {
 | 
					    fun fileEditorManagerSelectionChangedCallback(event: FileEditorManagerEvent) {
 | 
				
			||||||
      // Vim always has at least one window; it's not possible to close it. Editing a new file will open a new buffer in
 | 
					      // Vim only has one window, and it's not possible to close it. This means that editing a new file will always
 | 
				
			||||||
      // the current window, or it's possible to split the current buffer into a new window, or open a new buffer in a
 | 
					      // reuse an existing window (opening a new window will always open from an existing window). More importantly,
 | 
				
			||||||
      // new window. This is important for us because when Vim opens a new window, the new window's local options are
 | 
					      // this means that any newly edited file will always get up-to-date local-to-window options. A new window is based
 | 
				
			||||||
      // copied from the current window.
 | 
					      // on the opening window (treated as split then edit, so copy local + per-window "global" window values, then
 | 
				
			||||||
      // In detail: splitting the current window gets a complete copy of local and per-window global option values.
 | 
					      // apply the per-window "global" values) and an edit reapplies the per-window "global" values.
 | 
				
			||||||
      // Editing a new file will split the current window and then edit the new buffer in-place.
 | 
					      // If we close all windows, and open a new one, we can only use the per-window "global" values from the fallback
 | 
				
			||||||
      // IntelliJ does not always have an open window. It would be weird to close the last editor tab, and then open
 | 
					      // window, but this is only initialised when we first read `~/.ideavimrc` during startup. Vim would use the values
 | 
				
			||||||
      // the next tab with different options - the user would expect the editor to look like the last one did.
 | 
					      // from the current window, so to simulate this, we should update the fallback window with the values from the
 | 
				
			||||||
      // Therefore, we have a dummy "fallback" window that captures the options of the last closed editor. When opening
 | 
					      // window that was selected at the time that the last window was closed.
 | 
				
			||||||
      // an editor and there are no currently open editors, we use the fallback window to initialise the new window.
 | 
					      // Unfortunately, we can't reliably know if a closing editor is the selected editor. Instead, we rely on selection
 | 
				
			||||||
      // This callback tracks when editors are closed, and if the last editor in a project is being closed, updates the
 | 
					      // change events. If an editor is losing selection and there is no new selection, we can assume this means that
 | 
				
			||||||
      // fallback window's options.
 | 
					      // the last editor has been closed, and use the closed editor to update the fallback window
 | 
				
			||||||
      val project = editor.project ?: return
 | 
					      //
 | 
				
			||||||
      if (!injector.editorGroup.getEditorsRaw()
 | 
					      // XXX: event.oldEditor will must probably return a disposed editor. So, it should be treated with care
 | 
				
			||||||
          .any { it.ij != editor && it.ij.project === project && it.ij.editorKind == EditorKind.MAIN_EDITOR }
 | 
					      if (event.newEditor == null) {
 | 
				
			||||||
      ) {
 | 
					        (event.oldEditor as? TextEditor)?.editor?.let {
 | 
				
			||||||
        (VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, editor.vim)
 | 
					          (VimPlugin.getOptionGroup() as OptionGroup).updateFallbackWindow(injector.fallbackWindow, it.vim)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import com.intellij.openapi.components.State;
 | 
				
			|||||||
import com.intellij.openapi.components.Storage;
 | 
					import com.intellij.openapi.components.Storage;
 | 
				
			||||||
import com.intellij.openapi.diagnostic.Logger;
 | 
					import com.intellij.openapi.diagnostic.Logger;
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimInjectorKt;
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
 | 
					import com.maddyhome.idea.vim.newapi.IjVimInjectorKt;
 | 
				
			||||||
import com.maddyhome.idea.vim.register.Register;
 | 
					import com.maddyhome.idea.vim.register.Register;
 | 
				
			||||||
import com.maddyhome.idea.vim.register.VimRegisterGroupBase;
 | 
					import com.maddyhome.idea.vim.register.VimRegisterGroupBase;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.group
 | 
					package com.maddyhome.idea.vim.group
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.codeWithMe.ClientId
 | 
				
			||||||
import com.intellij.ide.bookmark.Bookmark
 | 
					import com.intellij.ide.bookmark.Bookmark
 | 
				
			||||||
import com.intellij.ide.bookmark.BookmarkGroup
 | 
					import com.intellij.ide.bookmark.BookmarkGroup
 | 
				
			||||||
import com.intellij.ide.bookmark.BookmarksListener
 | 
					import com.intellij.ide.bookmark.BookmarksListener
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,8 +51,6 @@ import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			|||||||
import com.maddyhome.idea.vim.state.mode.isBlock
 | 
					import com.maddyhome.idea.vim.state.mode.isBlock
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.isChar
 | 
					import com.maddyhome.idea.vim.state.mode.isChar
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.isLine
 | 
					import com.maddyhome.idea.vim.state.mode.isLine
 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
 | 
					 | 
				
			||||||
import java.awt.datatransfer.DataFlavor
 | 
					import java.awt.datatransfer.DataFlavor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
@@ -87,15 +85,9 @@ 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()
 | 
					      vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
 | 
				
			||||||
        is VimTimestampBasedUndoService -> {
 | 
					 | 
				
			||||||
          vimEditor.forEachCaret { undo.startInsertSequence(it, it.offset, nanoTime) }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    EditorHelper.getOrderedCaretsList(editor).forEach { caret ->
 | 
					    EditorHelper.getOrderedCaretsList(editor).forEach { caret ->
 | 
				
			||||||
      val startOffset =
 | 
					      val startOffset =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.group.visual
 | 
					package com.maddyhome.idea.vim.group.visual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager
 | 
					 | 
				
			||||||
import com.intellij.openapi.diagnostic.Logger
 | 
					import com.intellij.openapi.diagnostic.Logger
 | 
				
			||||||
import com.intellij.openapi.diagnostic.trace
 | 
					import com.intellij.openapi.diagnostic.trace
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
@@ -16,8 +15,6 @@ import com.maddyhome.idea.vim.KeyHandler
 | 
				
			|||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.api.options
 | 
					import com.maddyhome.idea.vim.api.options
 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.controlNonVimSelectionChange
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl.predictMode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.helper.exitSelectMode
 | 
					import com.maddyhome.idea.vim.helper.exitSelectMode
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
 | 
					import com.maddyhome.idea.vim.helper.exitVisualMode
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.hasVisualSelection
 | 
					import com.maddyhome.idea.vim.helper.hasVisualSelection
 | 
				
			||||||
@@ -66,15 +63,12 @@ internal object IdeaSelectionControl {
 | 
				
			|||||||
      //  - There was no selection and now it is
 | 
					      //  - There was no selection and now it is
 | 
				
			||||||
      //  - There was a selection and now it doesn't exist
 | 
					      //  - There was a selection and now it doesn't exist
 | 
				
			||||||
      //  - There was a selection and now it exists as well (transforming char selection to line selection, for example)
 | 
					      //  - There was a selection and now it exists as well (transforming char selection to line selection, for example)
 | 
				
			||||||
      val hasSelection = ApplicationManager.getApplication().runReadAction<Boolean> {
 | 
					      if (initialMode?.hasVisualSelection == false && !editor.selectionModel.hasSelection(true)) {
 | 
				
			||||||
        editor.selectionModel.hasSelection(true)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (initialMode?.hasVisualSelection == false && !hasSelection) {
 | 
					 | 
				
			||||||
        logger.trace { "Exiting without selection adjusting" }
 | 
					        logger.trace { "Exiting without selection adjusting" }
 | 
				
			||||||
        return@singleTask
 | 
					        return@singleTask
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (hasSelection) {
 | 
					      if (editor.selectionModel.hasSelection(true)) {
 | 
				
			||||||
        if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) {
 | 
					        if (editor.vim.inCommandLineMode && editor.vim.mode.returnTo().hasVisualSelection) {
 | 
				
			||||||
          logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" }
 | 
					          logger.trace { "Modifying selection while in Command-line mode, most likely incsearch" }
 | 
				
			||||||
          return@singleTask
 | 
					          return@singleTask
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@
 | 
				
			|||||||
package com.maddyhome.idea.vim.group.visual
 | 
					package com.maddyhome.idea.vim.group.visual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.group.visual.VimVisualTimer.mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.group.visual.VimVisualTimer.singleTask
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import java.awt.event.ActionEvent
 | 
					import java.awt.event.ActionEvent
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -183,7 +183,6 @@ internal abstract class OctopusHandler(private val nextHandler: EditorActionHand
 | 
				
			|||||||
 * - App code - set handler after
 | 
					 * - App code - set handler after
 | 
				
			||||||
 * - Template - doesn't intersect with enter anymore
 | 
					 * - Template - doesn't intersect with enter anymore
 | 
				
			||||||
 * - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
 | 
					 * - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
 | 
				
			||||||
 * - inline.completion.enter - set handler before. Otherwise, AI completion is not invoked on enter.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This rule is disabled due to VIM-3124
 | 
					 * This rule is disabled due to VIM-3124
 | 
				
			||||||
 * - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122
 | 
					 * - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122
 | 
				
			||||||
@@ -219,17 +218,13 @@ internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandle
 | 
				
			|||||||
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
					internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
				
			||||||
  override val key: String = "<Esc>"
 | 
					  override val key: String = "<Esc>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private val ideaVimSupportDialog
 | 
					 | 
				
			||||||
    get() = injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
					  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
				
			||||||
    return editor.isPrimaryEditor() ||
 | 
					    val ideaVimSupportDialog =
 | 
				
			||||||
      EditorHelper.isFileEditor(editor) && vimStateNeedsToHandleEscape(editor) ||
 | 
					      injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
 | 
				
			||||||
      ideaVimSupportDialog && vimStateNeedsToHandleEscape(editor)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun vimStateNeedsToHandleEscape(editor: Editor): Boolean {
 | 
					    return editor.isPrimaryEditor() ||
 | 
				
			||||||
    return !editor.vim.mode.inNormalMode || KeyHandler.getInstance().keyHandlerState.mappingState.hasKeys
 | 
					      EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode ||
 | 
				
			||||||
 | 
					      ideaVimSupportDialog && !editor.vim.mode.inNormalMode
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -157,19 +157,6 @@ public class EditorHelper {
 | 
				
			|||||||
    return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
 | 
					    return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Gets the number of characters that can be fit inside the output panel for an editor.
 | 
					 | 
				
			||||||
   * <p>
 | 
					 | 
				
			||||||
   * This will be greater than the approximate screen width as it also includes any gutter components in the editor.
 | 
					 | 
				
			||||||
   * </p>
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * @param editor The editor
 | 
					 | 
				
			||||||
   * @return The approximate number of columns that can fit in the output panel
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  public static int getApproximateOutputPanelWidth(final @NotNull Editor editor) {
 | 
					 | 
				
			||||||
    return (int)(editor.getComponent().getWidth() / getPlainSpaceWidthFloat(editor));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Gets the width of the space character in the editor's plain font as a float.
 | 
					   * Gets the width of the space character in the editor's plain font as a float.
 | 
				
			||||||
   * <p>
 | 
					   * <p>
 | 
				
			||||||
@@ -286,7 +273,7 @@ public class EditorHelper {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current
 | 
					    // Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current
 | 
				
			||||||
    // virtual space at the bottom of the screen
 | 
					    // virtual space at the bottom of the screen
 | 
				
			||||||
    final @NotNull VimEditor editor1 = new IjVimEditor(editor);
 | 
					    @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
				
			||||||
    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
					    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
				
			||||||
    final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y);
 | 
					    final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y);
 | 
				
			||||||
    scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset));
 | 
					    scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset));
 | 
				
			||||||
@@ -338,7 +325,7 @@ public class EditorHelper {
 | 
				
			|||||||
    final int lineHeight = editor.getLineHeight();
 | 
					    final int lineHeight = editor.getLineHeight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
 | 
					    final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
 | 
				
			||||||
    final @NotNull VimEditor editor1 = new IjVimEditor(editor);
 | 
					    @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
				
			||||||
    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
 | 
					    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
 | 
				
			||||||
    final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
 | 
					    final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -392,7 +379,7 @@ public class EditorHelper {
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static int getHorizontalScrollbarHeight(final @NotNull Editor editor) {
 | 
					  private static int getHorizontalScrollbarHeight(@NotNull final Editor editor) {
 | 
				
			||||||
    // Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured
 | 
					    // Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured
 | 
				
			||||||
    // text, or always visible, opaque and outside the content area, so we don't need to adjust for them
 | 
					    // text, or always visible, opaque and outside the content area, so we don't need to adjust for them
 | 
				
			||||||
    // Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That
 | 
					    // Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That
 | 
				
			||||||
@@ -475,7 +462,7 @@ public class EditorHelper {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) {
 | 
					  public static Pair<Boolean, Integer> scrollFullPageDown(final @NotNull Editor editor, int pages) {
 | 
				
			||||||
    final Rectangle visibleArea = getVisibleArea(editor);
 | 
					    final Rectangle visibleArea = getVisibleArea(editor);
 | 
				
			||||||
    final @NotNull VimEditor editor2 = new IjVimEditor(editor);
 | 
					    @NotNull final VimEditor editor2 = new IjVimEditor(editor);
 | 
				
			||||||
    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1;
 | 
					    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y = visibleArea.y + visibleArea.height;
 | 
					    int y = visibleArea.y + visibleArea.height;
 | 
				
			||||||
@@ -493,7 +480,7 @@ public class EditorHelper {
 | 
				
			|||||||
          caretVisualLine = lastVisualLine;
 | 
					          caretVisualLine = lastVisualLine;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
          final @NotNull VimEditor editor1 = new IjVimEditor(editor);
 | 
					          @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
				
			||||||
          caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
					          caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
				
			||||||
          completed = false;
 | 
					          completed = false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -528,7 +515,7 @@ public class EditorHelper {
 | 
				
			|||||||
  public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) {
 | 
					  public static Pair<Boolean, Integer> scrollFullPageUp(final @NotNull Editor editor, int pages) {
 | 
				
			||||||
    final Rectangle visibleArea = getVisibleArea(editor);
 | 
					    final Rectangle visibleArea = getVisibleArea(editor);
 | 
				
			||||||
    final int lineHeight = editor.getLineHeight();
 | 
					    final int lineHeight = editor.getLineHeight();
 | 
				
			||||||
    final @NotNull VimEditor editor1 = new IjVimEditor(editor);
 | 
					    @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
				
			||||||
    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
					    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y = visibleArea.y;
 | 
					    int y = visibleArea.y;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,9 +61,6 @@ internal class IjActionExecutor : VimActionExecutor {
 | 
				
			|||||||
    get() = IdeActions.ACTION_EXPAND_REGION
 | 
					    get() = IdeActions.ACTION_EXPAND_REGION
 | 
				
			||||||
  override val ACTION_EXPAND_REGION_RECURSIVELY: String
 | 
					  override val ACTION_EXPAND_REGION_RECURSIVELY: String
 | 
				
			||||||
    get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
 | 
					    get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
 | 
				
			||||||
  override val ACTION_EXPAND_COLLAPSE_TOGGLE: String
 | 
					 | 
				
			||||||
    // [VERSION UPDATE] 2024.3+ Replace raw "ExpandCollapseToggleAction" with IdeActions.ACTION_EXPAND_COLLAPSE_TOGGLE_REGION from the platform.
 | 
					 | 
				
			||||||
    get() = "ExpandCollapseToggleAction"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Execute an action
 | 
					   * Execute an action
 | 
				
			||||||
@@ -75,7 +72,7 @@ internal class IjActionExecutor : VimActionExecutor {
 | 
				
			|||||||
    val applicationEx = ApplicationManagerEx.getApplicationEx()
 | 
					    val applicationEx = ApplicationManagerEx.getApplicationEx()
 | 
				
			||||||
    if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
 | 
					    if (ProgressIndicatorUtils.isWriteActionRunningOrPending(applicationEx)) {
 | 
				
			||||||
      // This is needed for VIM-3376 and it should turn into error at soeme moment
 | 
					      // This is needed for VIM-3376 and it should turn into error at soeme moment
 | 
				
			||||||
      thisLogger().warn("Actions cannot be updated when write-action is running or pending")
 | 
					      thisLogger().warn(RuntimeException("Actions cannot be updated when write-action is running or pending", ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val ijAction = (action as IjNativeAction).action
 | 
					    val ijAction = (action as IjNativeAction).action
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import com.intellij.openapi.editor.ReadOnlyFragmentModificationException
 | 
				
			|||||||
import com.intellij.openapi.editor.VisualPosition
 | 
					import com.intellij.openapi.editor.VisualPosition
 | 
				
			||||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionManager
 | 
				
			||||||
import com.intellij.openapi.editor.ex.util.EditorUtil
 | 
					import com.intellij.openapi.editor.ex.util.EditorUtil
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.EngineEditorHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.api.EngineEditorHelperBase
 | 
					import com.maddyhome.idea.vim.api.EngineEditorHelperBase
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimRangeMarker
 | 
					import com.maddyhome.idea.vim.api.VimRangeMarker
 | 
				
			||||||
@@ -41,10 +42,6 @@ internal class IjEditorHelper : EngineEditorHelperBase() {
 | 
				
			|||||||
    return EditorHelper.getApproximateScreenWidth(editor.ij)
 | 
					    return EditorHelper.getApproximateScreenWidth(editor.ij)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun getApproximateOutputPanelWidth(editor: VimEditor): Int {
 | 
					 | 
				
			||||||
    return EditorHelper.getApproximateOutputPanelWidth(editor.ij)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) {
 | 
					  override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) {
 | 
				
			||||||
    return EditorActionManager.getInstance()
 | 
					    return EditorActionManager.getInstance()
 | 
				
			||||||
      .getReadonlyFragmentModificationHandler(editor.ij.document)
 | 
					      .getReadonlyFragmentModificationHandler(editor.ij.document)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import com.maddyhome.idea.vim.VimPlugin
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
					import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
					import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
 | 
					import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
					import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
					import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
				
			||||||
@@ -93,6 +94,6 @@ internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal fun Editor.exitInsertMode(context: DataContext) {
 | 
					internal fun Editor.exitInsertMode(context: DataContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
  VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context))
 | 
					  VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context), operatorArguments)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.VimStateMachine
 | 
				
			||||||
import kotlin.math.max
 | 
					import kotlin.math.max
 | 
				
			||||||
import kotlin.math.min
 | 
					import kotlin.math.min
 | 
				
			||||||
import kotlin.math.roundToInt
 | 
					import kotlin.math.roundToInt
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,8 +102,7 @@ private fun updateSearchHighlights(
 | 
				
			|||||||
  // Update highlights in all visible editors. We update non-visible editors when they get focus.
 | 
					  // Update highlights in all visible editors. We update non-visible editors when they get focus.
 | 
				
			||||||
  // Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles
 | 
					  // Note that this now includes all editors - main, diff windows, even toolwindows like the Commit editor and consoles
 | 
				
			||||||
  val editors = injector.editorGroup.getEditors().filter {
 | 
					  val editors = injector.editorGroup.getEditors().filter {
 | 
				
			||||||
    (injector.application.isUnitTest() || it.ij.component.isShowing)
 | 
					    injector.application.isUnitTest() || it.ij.component.isShowing
 | 
				
			||||||
      && (currentEditor == null || it.projectId == currentEditor.projectId)
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  editors.forEach {
 | 
					  editors.forEach {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,9 +14,7 @@ import com.intellij.openapi.command.CommandProcessor
 | 
				
			|||||||
import com.intellij.openapi.command.undo.UndoManager
 | 
					import com.intellij.openapi.command.undo.UndoManager
 | 
				
			||||||
import com.intellij.openapi.components.Service
 | 
					import com.intellij.openapi.components.Service
 | 
				
			||||||
import com.intellij.openapi.diagnostic.logger
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
					import com.intellij.openapi.fileEditor.TextEditor
 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditorWithPreview
 | 
					 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
 | 
					import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
import com.intellij.openapi.util.registry.Registry
 | 
					import com.intellij.openapi.util.registry.Registry
 | 
				
			||||||
@@ -32,13 +30,13 @@ import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			|||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
 | 
					import com.maddyhome.idea.vim.state.mode.inVisualMode
 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
 | 
					import com.maddyhome.idea.vim.undo.UndoRedoBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author oleg
 | 
					 * @author oleg
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
internal class UndoRedoHelper : VimTimestampBasedUndoService {
 | 
					internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    private val logger = logger<UndoRedoHelper>()
 | 
					    private val logger = logger<UndoRedoHelper>()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -46,13 +44,13 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
 | 
				
			|||||||
  override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val ijContext = context.context as DataContext
 | 
					    val ijContext = context.context as DataContext
 | 
				
			||||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
					    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
				
			||||||
    val textEditor = getTextEditor(editor.ij)
 | 
					    val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
 | 
				
			||||||
    val undoManager = UndoManager.getInstance(project)
 | 
					    val undoManager = UndoManager.getInstance(project)
 | 
				
			||||||
    if (undoManager.isUndoAvailable(textEditor)) {
 | 
					    if (undoManager.isUndoAvailable(fileEditor)) {
 | 
				
			||||||
      val scrollingModel = editor.getScrollingModel()
 | 
					      val scrollingModel = editor.getScrollingModel()
 | 
				
			||||||
      scrollingModel.accumulateViewportChanges()
 | 
					      scrollingModel.accumulateViewportChanges()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      performUndo(editor, undoManager, textEditor)
 | 
					      performUndo(editor, undoManager, fileEditor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      scrollingModel.flushViewportChanges()
 | 
					      scrollingModel.flushViewportChanges()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,15 +59,6 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
 | 
				
			|||||||
    return false
 | 
					    return false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun getTextEditor(editor: Editor): TextEditor {
 | 
					 | 
				
			||||||
    // If the Editor is hosted in a TextEditor with a preview, then TextEditorProvider will return a TextEditor for the
 | 
					 | 
				
			||||||
    // hosted instance, not for the main editor that also contains the preview. If we pass the inner TextEditor to the
 | 
					 | 
				
			||||||
    // UndoManager, it doesn't correctly restore state. Specifically, the change is undone/redone, but the caret is not
 | 
					 | 
				
			||||||
    // moved. See VIM-3671.
 | 
					 | 
				
			||||||
    val currentTextEditor = TextEditorProvider.getInstance().getTextEditor(editor)
 | 
					 | 
				
			||||||
    return TextEditorWithPreview.getParentSplitEditor(currentTextEditor) as? TextEditor ?: currentTextEditor
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun performUndo(
 | 
					  private fun performUndo(
 | 
				
			||||||
    editor: VimEditor,
 | 
					    editor: VimEditor,
 | 
				
			||||||
    undoManager: UndoManager,
 | 
					    undoManager: UndoManager,
 | 
				
			||||||
@@ -117,10 +106,10 @@ internal class UndoRedoHelper : VimTimestampBasedUndoService {
 | 
				
			|||||||
  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val ijContext = context.context as DataContext
 | 
					    val ijContext = context.context as DataContext
 | 
				
			||||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
					    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
				
			||||||
    val textEditor = getTextEditor(editor.ij)
 | 
					    val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor.ij)
 | 
				
			||||||
    val undoManager = UndoManager.getInstance(project)
 | 
					    val undoManager = UndoManager.getInstance(project)
 | 
				
			||||||
    if (undoManager.isRedoAvailable(textEditor)) {
 | 
					    if (undoManager.isRedoAvailable(fileEditor)) {
 | 
				
			||||||
      performRedo(undoManager, textEditor, editor)
 | 
					      performRedo(undoManager, fileEditor, editor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return true
 | 
					      return true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,11 +21,11 @@ import com.intellij.openapi.util.UserDataHolder
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
 | 
					import com.maddyhome.idea.vim.api.LocalMarkStorage
 | 
				
			||||||
import com.maddyhome.idea.vim.api.SelectionInfo
 | 
					import com.maddyhome.idea.vim.api.SelectionInfo
 | 
				
			||||||
import com.maddyhome.idea.vim.common.InsertSequence
 | 
					import com.maddyhome.idea.vim.common.InsertSequence
 | 
				
			||||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.VisualChange
 | 
					import com.maddyhome.idea.vim.group.visual.VisualChange
 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
 | 
					import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.VimStateMachine
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.ui.ExOutputPanel
 | 
					import com.maddyhome.idea.vim.ui.ExOutputPanel
 | 
				
			||||||
@@ -124,7 +124,6 @@ internal var Editor.vimExOutput: ExOutputModel? by userData()
 | 
				
			|||||||
internal var Editor.vimTestInputModel: TestInputModel? by userData()
 | 
					internal var Editor.vimTestInputModel: TestInputModel? by userData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal var Editor.vimChangeActionSwitchMode: Mode? by userData()
 | 
					internal var Editor.vimChangeActionSwitchMode: Mode? by userData()
 | 
				
			||||||
internal var Editor.replaceMask: VimEditorReplaceMask? by userData()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal var Caret.currentInsert: InsertSequence? by userData()
 | 
					internal var Caret.currentInsert: InsertSequence? by userData()
 | 
				
			||||||
internal val Caret.insertHistory: MutableList<InsertSequence> by userDataOr { mutableListOf() }
 | 
					internal val Caret.insertHistory: MutableList<InsertSequence> by userDataOr { mutableListOf() }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/main/java/com/maddyhome/idea/vim/key/NodesHelper.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/main/java/com/maddyhome/idea/vim/key/NodesHelper.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
 | 
				
			||||||
 | 
					  addLeafs(injector.parser.parseKeys(keys), actionHolder)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -15,6 +15,7 @@ import com.maddyhome.idea.vim.VimPlugin
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.common.EditorListener
 | 
					import com.maddyhome.idea.vim.common.EditorListener
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.inInsertMode
 | 
					import com.maddyhome.idea.vim.helper.inInsertMode
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
@@ -64,7 +65,7 @@ class IJEditorFocusListener : EditorListener {
 | 
				
			|||||||
      val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
 | 
					      val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
 | 
				
			||||||
      val mode = injector.vimState.mode
 | 
					      val mode = injector.vimState.mode
 | 
				
			||||||
      when (mode) {
 | 
					      when (mode) {
 | 
				
			||||||
        is Mode.INSERT -> editor.exitInsertMode(context)
 | 
					        is Mode.INSERT -> editor.exitInsertMode(context, OperatorArguments(false, 0, mode))
 | 
				
			||||||
        else -> {}
 | 
					        else -> {}
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -78,4 +79,3 @@ class IJEditorFocusListener : EditorListener {
 | 
				
			|||||||
    KeyHandler.getInstance().reset(editor)
 | 
					    KeyHandler.getInstance().reset(editor)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,9 +16,7 @@ import com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction
 | 
				
			|||||||
import com.intellij.codeInsight.template.Template
 | 
					import com.intellij.codeInsight.template.Template
 | 
				
			||||||
import com.intellij.codeInsight.template.TemplateEditingAdapter
 | 
					import com.intellij.codeInsight.template.TemplateEditingAdapter
 | 
				
			||||||
import com.intellij.codeInsight.template.TemplateManagerListener
 | 
					import com.intellij.codeInsight.template.TemplateManagerListener
 | 
				
			||||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
 | 
					 | 
				
			||||||
import com.intellij.codeInsight.template.impl.TemplateState
 | 
					import com.intellij.codeInsight.template.impl.TemplateState
 | 
				
			||||||
import com.intellij.codeInsight.template.impl.actions.NextVariableAction
 | 
					 | 
				
			||||||
import com.intellij.find.FindModelListener
 | 
					import com.intellij.find.FindModelListener
 | 
				
			||||||
import com.intellij.openapi.actionSystem.ActionManager
 | 
					import com.intellij.openapi.actionSystem.ActionManager
 | 
				
			||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
					import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
				
			||||||
@@ -154,10 +152,6 @@ internal object IdeaSpecifics {
 | 
				
			|||||||
            KeyHandler.getInstance().reset(it.vim)
 | 
					            KeyHandler.getInstance().reset(it.vim)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (action is NextVariableAction && TemplateManagerImpl.getTemplateState(editor) == null) {
 | 
					 | 
				
			||||||
          editor.vim.exitInsertMode(event.dataContext.vim)
 | 
					 | 
				
			||||||
          KeyHandler.getInstance().reset(editor.vim)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //endregion
 | 
					        //endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
 | 
					        if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import com.intellij.openapi.diagnostic.Logger
 | 
				
			|||||||
import com.intellij.openapi.diagnostic.trace
 | 
					import com.intellij.openapi.diagnostic.trace
 | 
				
			||||||
import com.intellij.openapi.editor.Caret
 | 
					import com.intellij.openapi.editor.Caret
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.EditorFactory
 | 
				
			||||||
import com.intellij.openapi.editor.EditorKind
 | 
					import com.intellij.openapi.editor.EditorKind
 | 
				
			||||||
import com.intellij.openapi.editor.actionSystem.TypedAction
 | 
					import com.intellij.openapi.editor.actionSystem.TypedAction
 | 
				
			||||||
import com.intellij.openapi.editor.event.CaretEvent
 | 
					import com.intellij.openapi.editor.event.CaretEvent
 | 
				
			||||||
@@ -31,10 +32,10 @@ import com.intellij.openapi.editor.event.EditorMouseMotionListener
 | 
				
			|||||||
import com.intellij.openapi.editor.event.SelectionEvent
 | 
					import com.intellij.openapi.editor.event.SelectionEvent
 | 
				
			||||||
import com.intellij.openapi.editor.event.SelectionListener
 | 
					import com.intellij.openapi.editor.event.SelectionListener
 | 
				
			||||||
import com.intellij.openapi.editor.ex.DocumentEx
 | 
					import com.intellij.openapi.editor.ex.DocumentEx
 | 
				
			||||||
import com.intellij.openapi.editor.ex.EditorEx
 | 
					import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
 | 
				
			||||||
import com.intellij.openapi.editor.ex.FocusChangeListener
 | 
					import com.intellij.openapi.editor.ex.FocusChangeListener
 | 
				
			||||||
import com.intellij.openapi.editor.impl.EditorComponentImpl
 | 
					import com.intellij.openapi.editor.impl.EditorComponentImpl
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileEditor
 | 
					import com.intellij.openapi.editor.impl.EditorImpl
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileEditorManager
 | 
					import com.intellij.openapi.fileEditor.FileEditorManager
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
					import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
 | 
					import com.intellij.openapi.fileEditor.FileEditorManagerListener
 | 
				
			||||||
@@ -44,15 +45,15 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
				
			|||||||
import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
 | 
					import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.EditorComposite
 | 
					import com.intellij.openapi.fileEditor.impl.EditorComposite
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.EditorWindow
 | 
					import com.intellij.openapi.fileEditor.impl.EditorWindow
 | 
				
			||||||
import com.intellij.openapi.observable.util.addKeyListener
 | 
					 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					 | 
				
			||||||
import com.intellij.openapi.project.ProjectManager
 | 
					import com.intellij.openapi.project.ProjectManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.rd.createLifetime
 | 
				
			||||||
 | 
					import com.intellij.openapi.rd.createNestedDisposable
 | 
				
			||||||
import com.intellij.openapi.util.Disposer
 | 
					import com.intellij.openapi.util.Disposer
 | 
				
			||||||
import com.intellij.openapi.util.Key
 | 
					import com.intellij.openapi.util.Key
 | 
				
			||||||
import com.intellij.openapi.util.removeUserData
 | 
					import com.intellij.openapi.util.removeUserData
 | 
				
			||||||
import com.intellij.openapi.vfs.VirtualFile
 | 
					import com.intellij.openapi.vfs.VirtualFile
 | 
				
			||||||
import com.intellij.util.ExceptionUtil
 | 
					import com.intellij.util.ExceptionUtil
 | 
				
			||||||
import com.intellij.util.SlowOperations
 | 
					import com.jetbrains.rd.util.lifetime.Lifetime
 | 
				
			||||||
import com.maddyhome.idea.vim.EventFacade
 | 
					import com.maddyhome.idea.vim.EventFacade
 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.VimKeyListener
 | 
					import com.maddyhome.idea.vim.VimKeyListener
 | 
				
			||||||
@@ -65,6 +66,7 @@ import com.maddyhome.idea.vim.api.coerceOffset
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
					import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
					import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
				
			||||||
import com.maddyhome.idea.vim.group.EditorGroup
 | 
					import com.maddyhome.idea.vim.group.EditorGroup
 | 
				
			||||||
import com.maddyhome.idea.vim.group.FileGroup
 | 
					import com.maddyhome.idea.vim.group.FileGroup
 | 
				
			||||||
import com.maddyhome.idea.vim.group.IjOptions
 | 
					import com.maddyhome.idea.vim.group.IjOptions
 | 
				
			||||||
@@ -105,11 +107,8 @@ import com.maddyhome.idea.vim.ui.widgets.macro.MacroWidgetListener
 | 
				
			|||||||
import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
 | 
					import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
 | 
				
			||||||
import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
 | 
					import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
 | 
				
			||||||
import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
 | 
					import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
 | 
				
			||||||
import org.jetbrains.annotations.TestOnly
 | 
					 | 
				
			||||||
import java.awt.event.MouseAdapter
 | 
					import java.awt.event.MouseAdapter
 | 
				
			||||||
import java.awt.event.MouseEvent
 | 
					import java.awt.event.MouseEvent
 | 
				
			||||||
import java.lang.ref.WeakReference
 | 
					 | 
				
			||||||
import java.util.*
 | 
					 | 
				
			||||||
import javax.swing.SwingUtilities
 | 
					import javax.swing.SwingUtilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -131,15 +130,23 @@ import javax.swing.SwingUtilities
 | 
				
			|||||||
 * Make sure the selected editor isn't the new editor, which can happen if there are no other editors open.
 | 
					 * Make sure the selected editor isn't the new editor, which can happen if there are no other editors open.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project ->
 | 
					private fun getOpeningEditor(newEditor: Editor) = newEditor.project?.let { project ->
 | 
				
			||||||
  // We can't rely on FileEditorManager.selectedTextEditor because we're trying to retrieve the selected text editor
 | 
					  // Some TextEditor implementations create a dummy Editor instance on demand, e.g., while downloading a file to edit
 | 
				
			||||||
  // while creating a text editor that is about to become the selected text editor.
 | 
					  // (see BaseRemoteFileEditor). This can cause recursion if the newly opened/created TextEditor is also the currently
 | 
				
			||||||
  // This worked fine for 2024.2, but internal changes for 2024.3 broke things. It appears that the currently selected
 | 
					  // selected TextEditor, because we will be notified of the new dummy Editor before it has finished initialisation, and
 | 
				
			||||||
  // text editor is reset to null while the soon-to-be-selected text editor is being created. We therefore track the
 | 
					  // try to get its opening editor, causing a new dummy Editor to be created and notifications sent, and so on.
 | 
				
			||||||
  // last selected editor manually.
 | 
					  // This was reported for 232 and 233 (see VIM-3066), but I can't recreate in 241. The callstack looks different, now
 | 
				
			||||||
  // Note that if we ever switch back to FileEditorManager.selectedTextEditor, be careful of recursion, because the
 | 
					  // using coroutines, so it's possible the deadlock has been broken. However, it's sensible to leave the recursion
 | 
				
			||||||
  // actual editor might be created on-demand, which would notify our initialisation method, which would call us...
 | 
					  // guard in.
 | 
				
			||||||
  VimListenerManager.VimLastSelectedEditorTracker.getLastSelectedEditor(project)?.takeUnless { it == newEditor }
 | 
					  if (openingEditorRecursionGuard) return null
 | 
				
			||||||
 | 
					  openingEditorRecursionGuard = true
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    FileEditorManager.getInstance(project).selectedTextEditor?.takeUnless { it == newEditor }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  finally {
 | 
				
			||||||
 | 
					    openingEditorRecursionGuard = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					private var openingEditorRecursionGuard = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal object VimListenerManager {
 | 
					internal object VimListenerManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,9 +156,7 @@ internal object VimListenerManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  fun turnOn() {
 | 
					  fun turnOn() {
 | 
				
			||||||
    GlobalListeners.enable()
 | 
					    GlobalListeners.enable()
 | 
				
			||||||
    SlowOperations.knownIssue("VIM-3648, VIM-3649").use {
 | 
					    EditorListeners.addAll()
 | 
				
			||||||
      EditorListeners.addAll()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    check(correctorRequester.tryEmit(Unit))
 | 
					    check(correctorRequester.tryEmit(Unit))
 | 
				
			||||||
    check(keyCheckRequests.tryEmit(Unit))
 | 
					    check(keyCheckRequests.tryEmit(Unit))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,6 +217,16 @@ internal object VimListenerManager {
 | 
				
			|||||||
      EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
 | 
					      EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
 | 
				
			||||||
      val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable)
 | 
					      val busConnection = ApplicationManager.getApplication().messageBus.connect(VimPlugin.getInstance().onOffDisposable)
 | 
				
			||||||
      busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener)
 | 
					      busConnection.subscribe(FileOpenedSyncListener.TOPIC, VimEditorFactoryListener)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Listen for focus change to update various features such as mode widget
 | 
				
			||||||
 | 
					      val eventMulticaster = EditorFactory.getInstance().eventMulticaster
 | 
				
			||||||
 | 
					      (eventMulticaster as? EditorEventMulticasterEx)?.addFocusChangeListener(
 | 
				
			||||||
 | 
					        VimFocusListener,
 | 
				
			||||||
 | 
					        VimPlugin.getInstance().onOffDisposable
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Listen for document changes to update document state such as marks
 | 
				
			||||||
 | 
					      eventMulticaster.addDocumentListener(VimDocumentListener, VimPlugin.getInstance().onOffDisposable)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun disable() {
 | 
					    fun disable() {
 | 
				
			||||||
@@ -273,52 +288,45 @@ internal object VimListenerManager {
 | 
				
			|||||||
      // TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
 | 
					      // TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
 | 
				
			||||||
      if (vimDisabled(editor)) return
 | 
					      if (vimDisabled(editor)) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val pluginLifetime = VimPlugin.getInstance().createLifetime()
 | 
				
			||||||
 | 
					      val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
 | 
				
			||||||
 | 
					      val disposable =
 | 
				
			||||||
 | 
					        Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Protect against double initialisation
 | 
					      // Protect against double initialisation
 | 
				
			||||||
      if (editor.getUserData(editorListenersDisposableKey) != null) {
 | 
					      if (editor.getUserData(editorListenersDisposableKey) != null) {
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Make sure we explicitly dispose this per-editor disposable!
 | 
					      val listenersDisposable = Disposer.newDisposable(disposable)
 | 
				
			||||||
      // Because the listeners are registered with a parent disposable, they add child disposables that have to call a
 | 
					      editor.putUserData(editorListenersDisposableKey, listenersDisposable)
 | 
				
			||||||
      // method on the editor to remove the listener. This means the disposable contains a reference to the editor (even
 | 
					 | 
				
			||||||
      // if the listener handler is a singleton that doesn't hold a reference).
 | 
					 | 
				
			||||||
      // Unless the per-editor disposable is disposed, all of these disposables sit in the disposer tree until the
 | 
					 | 
				
			||||||
      // parent disposable is disposed, which will mean we leak editor instances.
 | 
					 | 
				
			||||||
      // The per-editor disposable is explicitly disposed when the editor is released, and disposed via its parent when
 | 
					 | 
				
			||||||
      // the plugin's on/off functionality is toggled, and so also when the plugin is disabled/unloaded by the platform.
 | 
					 | 
				
			||||||
      // It doesn't matter if we explicitly remove all listeners before disposing onOffDisposable, as that will remove
 | 
					 | 
				
			||||||
      // the per-editor disposable from the disposer tree.
 | 
					 | 
				
			||||||
      val perEditorDisposable = Disposer.newDisposable(VimPlugin.getInstance().onOffDisposable)
 | 
					 | 
				
			||||||
      editor.putUserData(editorListenersDisposableKey, perEditorDisposable)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Disposer.register(perEditorDisposable) {
 | 
					      Disposer.register(listenersDisposable) {
 | 
				
			||||||
        if (VimListenerTestObject.enabled) {
 | 
					        if (VimListenerTestObject.enabled) {
 | 
				
			||||||
          VimListenerTestObject.disposedCounter += 1
 | 
					          VimListenerTestObject.disposedCounter += 1
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // This listener and several below add a reference to the editor to the disposer tree
 | 
					      editor.contentComponent.addKeyListener(VimKeyListener)
 | 
				
			||||||
      editor.contentComponent.addKeyListener(perEditorDisposable, VimKeyListener)
 | 
					      Disposer.register(listenersDisposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Initialise the local options. We MUST do this before anything has the chance to query options
 | 
					      // Initialise the local options. We MUST do this before anything has the chance to query options
 | 
				
			||||||
      val vimEditor = editor.vim
 | 
					      val vimEditor = editor.vim
 | 
				
			||||||
      VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario)
 | 
					      VimPlugin.getOptionGroup().initialiseLocalOptions(vimEditor, openingEditor, scenario)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val eventFacade = EventFacade.getInstance()
 | 
					      val eventFacade = EventFacade.getInstance()
 | 
				
			||||||
      eventFacade.addEditorMouseListener(editor, EditorMouseHandler, perEditorDisposable)
 | 
					      eventFacade.addEditorMouseListener(editor, EditorMouseHandler, listenersDisposable)
 | 
				
			||||||
      eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, perEditorDisposable)
 | 
					      eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, listenersDisposable)
 | 
				
			||||||
      eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, perEditorDisposable)
 | 
					      eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, listenersDisposable)
 | 
				
			||||||
      eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, perEditorDisposable)
 | 
					      eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, listenersDisposable)
 | 
				
			||||||
      eventFacade.addCaretListener(editor, EditorCaretHandler, perEditorDisposable)
 | 
					      eventFacade.addCaretListener(editor, EditorCaretHandler, listenersDisposable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      VimPlugin.getEditor().editorCreated(editor)
 | 
					      VimPlugin.getEditor().editorCreated(editor)
 | 
				
			||||||
      VimPlugin.getChange().editorCreated(editor, perEditorDisposable)
 | 
					      VimPlugin.getChange().editorCreated(editor, listenersDisposable)
 | 
				
			||||||
 | 
					 | 
				
			||||||
      (editor as EditorEx).addFocusListener(VimFocusListener, perEditorDisposable)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      injector.listenersNotifier.notifyEditorCreated(vimEditor)
 | 
					      injector.listenersNotifier.notifyEditorCreated(vimEditor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Disposer.register(perEditorDisposable) {
 | 
					      Disposer.register(listenersDisposable) {
 | 
				
			||||||
        VimPlugin.getEditor().editorDeinit(editor)
 | 
					        VimPlugin.getEditor().editorDeinit(editor)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -356,7 +364,7 @@ internal object VimListenerManager {
 | 
				
			|||||||
   * open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest
 | 
					   * open in non-local Code With Me guest editors, which we still want to process (e.g. to update marks when a guest
 | 
				
			||||||
   * edits a file. Updating search highlights will be a no-op if there are no open local editors)
 | 
					   * edits a file. Updating search highlights will be a no-op if there are no open local editors)
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  class VimDocumentListener : DocumentListener {
 | 
					  private object VimDocumentListener : DocumentListener {
 | 
				
			||||||
    override fun beforeDocumentChange(event: DocumentEvent) {
 | 
					    override fun beforeDocumentChange(event: DocumentEvent) {
 | 
				
			||||||
      VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event)
 | 
					      VimMarkServiceImpl.MarkUpdater.beforeDocumentChange(event)
 | 
				
			||||||
      IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event)
 | 
					      IjVimSearchGroup.DocumentSearchListener.INSTANCE.beforeDocumentChange(event)
 | 
				
			||||||
@@ -370,26 +378,6 @@ internal object VimListenerManager {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  internal object VimLastSelectedEditorTracker {
 | 
					 | 
				
			||||||
    // This stores a weak reference to an editor against a weak reference to a project, which means there is nothing
 | 
					 | 
				
			||||||
    // keeping the project or editor from being garbage collected at any time. Stale keys are automatically expunged
 | 
					 | 
				
			||||||
    // whenever the map is used.
 | 
					 | 
				
			||||||
    private val selectedEditors = WeakHashMap<Project, WeakReference<Editor>>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun getLastSelectedEditor(project: Project): Editor? = selectedEditors[project]?.get()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    internal fun setLastSelectedEditor(fileEditor: FileEditor?) {
 | 
					 | 
				
			||||||
      (fileEditor as? TextEditor)?.editor?.let { editor ->
 | 
					 | 
				
			||||||
        editor.project?.let { project -> selectedEditors[project] = WeakReference(editor) }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @TestOnly
 | 
					 | 
				
			||||||
    internal fun resetLastSelectedEditor(project: Project) {
 | 
					 | 
				
			||||||
      selectedEditors.remove(project)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the
 | 
					   * Called when the selected file editor changes. In other words, when the user selects a new tab. Used to remember the
 | 
				
			||||||
   * last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me
 | 
					   * last selected file, update search highlights in the new tab, etc. This will be called with non-local Code With Me
 | 
				
			||||||
@@ -407,15 +395,14 @@ internal object VimListenerManager {
 | 
				
			|||||||
          editor.vim.mode = Mode.NORMAL()
 | 
					          editor.vim.mode = Mode.NORMAL()
 | 
				
			||||||
          KeyHandler.getInstance().reset(editor.vim)
 | 
					          KeyHandler.getInstance().reset(editor.vim)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // Breaks relativenumber for some reason
 | 
					        injector.scroll.scrollCaretIntoView(editor.vim)
 | 
				
			||||||
//        injector.scroll.scrollCaretIntoView(editor.vim)
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      MotionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
					      MotionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      FileGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
					      FileGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
 | 
					      VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
 | 
					      OptionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
 | 
					      IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -487,21 +474,8 @@ internal object VimListenerManager {
 | 
				
			|||||||
    override fun editorReleased(event: EditorFactoryEvent) {
 | 
					    override fun editorReleased(event: EditorFactoryEvent) {
 | 
				
			||||||
      if (vimDisabled(event.editor)) return
 | 
					      if (vimDisabled(event.editor)) return
 | 
				
			||||||
      val vimEditor = event.editor.vim
 | 
					      val vimEditor = event.editor.vim
 | 
				
			||||||
      EditorListeners.remove(event.editor)
 | 
					 | 
				
			||||||
      injector.listenersNotifier.notifyEditorReleased(vimEditor)
 | 
					      injector.listenersNotifier.notifyEditorReleased(vimEditor)
 | 
				
			||||||
      injector.markService.editorReleased(vimEditor)
 | 
					      injector.markService.editorReleased(vimEditor)
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // This ticket will have a different stack trace, but it's the same problem. Originally, we tracked the last
 | 
					 | 
				
			||||||
      // editor closing based on file selection (closing an editor would select the next editor - so a null selection
 | 
					 | 
				
			||||||
      // was taken to mean that there were no more editors to select). This assumption broke in 242, so it's changed to
 | 
					 | 
				
			||||||
      // check when the editor is released.
 | 
					 | 
				
			||||||
      // However, the actions taken when the last editor closes can still be expensive/slow because we copy options, and
 | 
					 | 
				
			||||||
      // some options are backed by PSI options. E.g. 'textwidth' is mapped to
 | 
					 | 
				
			||||||
      // CodeStyle.getSettings(ijEditor).isWrapOnTyping(language)), and getting the document's PSI language is a slow
 | 
					 | 
				
			||||||
      // operation. This underlying issue still needs to be addressed, even though the method has moved
 | 
					 | 
				
			||||||
      SlowOperations.knownIssue("VIM-3658").use {
 | 
					 | 
				
			||||||
        OptionGroup.editorReleased(event.editor)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun fileOpenedSync(
 | 
					    override fun fileOpenedSync(
 | 
				
			||||||
@@ -774,7 +748,7 @@ internal object VimListenerManager {
 | 
				
			|||||||
        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
					        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
				
			||||||
        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
					        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
					        ExOutputModel.tryGetInstance(editor)?.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val caretModel = editor.caretModel
 | 
					        val caretModel = editor.caretModel
 | 
				
			||||||
        if (editor.vim.mode.selectionType != null) {
 | 
					        if (editor.vim.mode.selectionType != null) {
 | 
				
			||||||
@@ -789,16 +763,11 @@ 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> {
 | 
					          if (editor.inVisualMode) {
 | 
				
			||||||
            editor.selectionModel.hasSelection(true)
 | 
					            editor.vim.exitVisualMode()
 | 
				
			||||||
          }
 | 
					          } else if (editor.vim.inSelectMode) {
 | 
				
			||||||
          if (!hasSelection) {
 | 
					            editor.exitSelectMode(false)
 | 
				
			||||||
            if (editor.inVisualMode) {
 | 
					            KeyHandler.getInstance().reset(editor.vim)
 | 
				
			||||||
              editor.vim.exitVisualMode()
 | 
					 | 
				
			||||||
            } else if (editor.vim.inSelectMode) {
 | 
					 | 
				
			||||||
              editor.exitSelectMode(false)
 | 
					 | 
				
			||||||
              KeyHandler.getInstance().reset(editor.vim)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA &&
 | 
					      } else if (event.area != EditorMouseEventArea.ANNOTATIONS_AREA &&
 | 
				
			||||||
@@ -808,7 +777,7 @@ internal object VimListenerManager {
 | 
				
			|||||||
        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
					        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
				
			||||||
        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
					        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
					        ExOutputModel.getInstance(event.editor).close()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,13 +22,10 @@ import com.intellij.openapi.project.DumbService
 | 
				
			|||||||
import com.intellij.openapi.project.IndexNotReadyException
 | 
					import com.intellij.openapi.project.IndexNotReadyException
 | 
				
			||||||
import com.intellij.psi.PsiDocumentManager
 | 
					import com.intellij.psi.PsiDocumentManager
 | 
				
			||||||
import com.intellij.util.ui.EmptyClipboardOwner
 | 
					import com.intellij.util.ui.EmptyClipboardOwner
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimClipboardManager
 | 
					import com.maddyhome.idea.vim.api.VimClipboardManager
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getText
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.common.TextRange
 | 
					import com.maddyhome.idea.vim.common.TextRange
 | 
				
			||||||
import com.maddyhome.idea.vim.common.VimCopiedText
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.diagnostic.debug
 | 
					import com.maddyhome.idea.vim.diagnostic.debug
 | 
				
			||||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
 | 
					import com.maddyhome.idea.vim.diagnostic.vimLogger
 | 
				
			||||||
import java.awt.HeadlessException
 | 
					import java.awt.HeadlessException
 | 
				
			||||||
@@ -40,52 +37,18 @@ import java.io.IOException
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
internal class IjClipboardManager : VimClipboardManager {
 | 
					internal class IjClipboardManager : VimClipboardManager {
 | 
				
			||||||
  @Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getPrimaryTextAndTransferableData")
 | 
					 | 
				
			||||||
  override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? {
 | 
					  override fun getPrimaryTextAndTransferableData(): Pair<String, List<Any>?>? {
 | 
				
			||||||
    val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null
 | 
					    val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return null
 | 
				
			||||||
    val contents = clipboard.getContents(null) ?: return null
 | 
					    val contents = clipboard.getContents(null) ?: return null
 | 
				
			||||||
    return getTextAndTransferableData(contents)
 | 
					    return getTextAndTransferableData(contents)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun getPrimaryContent(editor: VimEditor, context: ExecutionContext): IjVimCopiedText? {
 | 
					 | 
				
			||||||
    val (text, transferableData) = getPrimaryTextAndTransferableData() ?: return null
 | 
					 | 
				
			||||||
    return IjVimCopiedText(text, transferableData ?: emptyList())
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#getClipboardTextAndTransferableData")
 | 
					 | 
				
			||||||
  override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? {
 | 
					  override fun getClipboardTextAndTransferableData(): Pair<String, List<Any>?>? {
 | 
				
			||||||
    val contents = getContents() ?: return null
 | 
					    val contents = getContents() ?: return null
 | 
				
			||||||
    return getTextAndTransferableData(contents)
 | 
					    return getTextAndTransferableData(contents)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun getClipboardContent(editor: VimEditor, context: ExecutionContext): VimCopiedText? {
 | 
					  private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<Any>?>? {
 | 
				
			||||||
    val (text, transferableData) = getClipboardTextAndTransferableData() ?: return null
 | 
					 | 
				
			||||||
    return IjVimCopiedText(text, transferableData ?: emptyList())
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun setClipboardContent(editor: VimEditor, context: ExecutionContext, textData: VimCopiedText): Boolean {
 | 
					 | 
				
			||||||
    require(textData is IjVimCopiedText)
 | 
					 | 
				
			||||||
    return handleTextSetting(textData.text, textData.text, textData.transferableData) { content -> setContents(content) } != null
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // TODO prefer methods with ranges, because they collect and preprocess for us
 | 
					 | 
				
			||||||
//  override fun createClipboardEntry(
 | 
					 | 
				
			||||||
//    editor: VimEditor,
 | 
					 | 
				
			||||||
//    context: ExecutionContext,
 | 
					 | 
				
			||||||
//    text: String,
 | 
					 | 
				
			||||||
//    range: TextRange,
 | 
					 | 
				
			||||||
//  ): ClipboardEntry {
 | 
					 | 
				
			||||||
//    val transferableData = getTransferableData(editor, range, text)
 | 
					 | 
				
			||||||
//    val preprocessedText = preprocessText(editor, range, text, transferableData)
 | 
					 | 
				
			||||||
//    return IJClipboardEntry(preprocessedText, text, transferableData)
 | 
					 | 
				
			||||||
//  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//  override fun setClipboardText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
 | 
					 | 
				
			||||||
//    require(entry is IJClipboardEntry)
 | 
					 | 
				
			||||||
//    return setClipboardText(entry.text, entry.rawText, entry.transferableData) != null
 | 
					 | 
				
			||||||
//  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun getTextAndTransferableData(trans: Transferable): Pair<String, List<TextBlockTransferableData>?>? {
 | 
					 | 
				
			||||||
    var res: String? = null
 | 
					    var res: String? = null
 | 
				
			||||||
    var transferableData: List<TextBlockTransferableData> = ArrayList()
 | 
					    var transferableData: List<TextBlockTransferableData> = ArrayList()
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
@@ -100,29 +63,10 @@ internal class IjClipboardManager : VimClipboardManager {
 | 
				
			|||||||
    return Pair(res, transferableData)
 | 
					    return Pair(res, transferableData)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setClipboardText")
 | 
					 | 
				
			||||||
  override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
 | 
					  override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
 | 
				
			||||||
    return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) }
 | 
					    return handleTextSetting(text, rawText, transferableData) { content -> setContents(content) }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun setPrimaryContent(
 | 
					 | 
				
			||||||
    editor: VimEditor,
 | 
					 | 
				
			||||||
    context: ExecutionContext,
 | 
					 | 
				
			||||||
    textData: VimCopiedText,
 | 
					 | 
				
			||||||
  ): Boolean {
 | 
					 | 
				
			||||||
    require(textData is IjVimCopiedText)
 | 
					 | 
				
			||||||
    return handleTextSetting(textData.text, textData.text, textData.transferableData) { content ->
 | 
					 | 
				
			||||||
      val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
 | 
					 | 
				
			||||||
      clipboard.setContents(content, EmptyClipboardOwner.INSTANCE)
 | 
					 | 
				
			||||||
    } != null
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//  override fun setPrimaryText(editor: VimEditor, context: ExecutionContext, entry: ClipboardEntry): Boolean {
 | 
					 | 
				
			||||||
//    require(entry is IJClipboardEntry)
 | 
					 | 
				
			||||||
//    return setPrimaryText(entry.text, entry.rawText, entry.transferableData) != null
 | 
					 | 
				
			||||||
//  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Deprecated("Please use com.maddyhome.idea.vim.api.VimClipboardManager#setPrimaryText")
 | 
					 | 
				
			||||||
  override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
 | 
					  override fun setPrimaryText(text: String, rawText: String, transferableData: List<Any>): Transferable? {
 | 
				
			||||||
    return handleTextSetting(text, rawText, transferableData) { content ->
 | 
					    return handleTextSetting(text, rawText, transferableData) { content ->
 | 
				
			||||||
      val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
 | 
					      val clipboard = Toolkit.getDefaultToolkit()?.systemSelection ?: return@handleTextSetting null
 | 
				
			||||||
@@ -130,16 +74,6 @@ internal class IjClipboardManager : VimClipboardManager {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun collectCopiedText(editor: VimEditor, context: ExecutionContext, range: TextRange, text: String): VimCopiedText {
 | 
					 | 
				
			||||||
    val transferableData = getTransferableData(editor, range)
 | 
					 | 
				
			||||||
    val preprocessedText = preprocessText(editor, range, text, transferableData)
 | 
					 | 
				
			||||||
    return IjVimCopiedText(preprocessedText, transferableData)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun dumbCopiedText(text: String): VimCopiedText {
 | 
					 | 
				
			||||||
    return IjVimCopiedText(text, emptyList())
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Suppress("UNCHECKED_CAST")
 | 
					  @Suppress("UNCHECKED_CAST")
 | 
				
			||||||
  private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? {
 | 
					  private fun handleTextSetting(text: String, rawText: String, transferableData: List<Any>, setContent: (TextBlockTransferable) -> Unit?): Transferable? {
 | 
				
			||||||
    val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList()
 | 
					    val mutableTransferableData = (transferableData as List<TextBlockTransferableData>).toMutableList()
 | 
				
			||||||
@@ -158,7 +92,7 @@ internal class IjClipboardManager : VimClipboardManager {
 | 
				
			|||||||
    return null
 | 
					    return null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange): List<TextBlockTransferableData> {
 | 
					  override fun getTransferableData(vimEditor: VimEditor, textRange: TextRange, text: String): List<Any> {
 | 
				
			||||||
    val editor = (vimEditor as IjVimEditor).editor
 | 
					    val editor = (vimEditor as IjVimEditor).editor
 | 
				
			||||||
    val transferableData: MutableList<TextBlockTransferableData> = ArrayList()
 | 
					    val transferableData: MutableList<TextBlockTransferableData> = ArrayList()
 | 
				
			||||||
    val project = editor.project ?: return emptyList()
 | 
					    val project = editor.project ?: return emptyList()
 | 
				
			||||||
@@ -183,7 +117,7 @@ internal class IjClipboardManager : VimClipboardManager {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(textRange.endOffset - textRange.startOffset)))
 | 
					    transferableData.add(CaretStateTransferableData(intArrayOf(0), intArrayOf(text.length)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with
 | 
					    // These data provided by {@link com.intellij.openapi.editor.richcopy.TextWithMarkupProcessor} doesn't work with
 | 
				
			||||||
    //   IdeaVim and I don't see a way to fix it
 | 
					    //   IdeaVim and I don't see a way to fix it
 | 
				
			||||||
@@ -241,7 +175,3 @@ internal class IjClipboardManager : VimClipboardManager {
 | 
				
			|||||||
    val logger = vimLogger<IjClipboardManager>()
 | 
					    val logger = vimLogger<IjClipboardManager>()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
data class IjVimCopiedText(override val text: String, val transferableData: List<Any>): VimCopiedText {
 | 
					 | 
				
			||||||
  override fun updateText(newText: String): VimCopiedText = IjVimCopiedText(newText, transferableData)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,27 +14,6 @@ import com.maddyhome.idea.vim.common.LiveRange
 | 
				
			|||||||
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
 | 
					internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
 | 
				
			||||||
  override val startOffset: Int
 | 
					  override val startOffset: Int
 | 
				
			||||||
    get() = marker.startOffset
 | 
					    get() = marker.startOffset
 | 
				
			||||||
 | 
					 | 
				
			||||||
  override val endOffset: Int
 | 
					 | 
				
			||||||
    get() = marker.endOffset
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun equals(other: Any?): Boolean {
 | 
					 | 
				
			||||||
    if (this === other) return true
 | 
					 | 
				
			||||||
    if (javaClass != other?.javaClass) return false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    other as IjLiveRange
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (startOffset != other.startOffset) return false
 | 
					 | 
				
			||||||
    if (endOffset != other.endOffset) return false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					 | 
				
			||||||
    var result = startOffset
 | 
					 | 
				
			||||||
    result = 31 * result + endOffset
 | 
					 | 
				
			||||||
    return result
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val RangeMarker.vim: LiveRange
 | 
					val RangeMarker.vim: LiveRange
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,6 @@ import com.maddyhome.idea.vim.api.VimCaret
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimCaretBase
 | 
					import com.maddyhome.idea.vim.api.VimCaretBase
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
					import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.common.InsertSequence
 | 
					import com.maddyhome.idea.vim.common.InsertSequence
 | 
				
			||||||
import com.maddyhome.idea.vim.common.LiveRange
 | 
					import com.maddyhome.idea.vim.common.LiveRange
 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.VisualChange
 | 
					import com.maddyhome.idea.vim.group.visual.VisualChange
 | 
				
			||||||
@@ -35,14 +34,10 @@ import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.vimLine
 | 
					import com.maddyhome.idea.vim.helper.vimLine
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
 | 
					import com.maddyhome.idea.vim.helper.vimSelectionStart
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimSelectionStartClear
 | 
					import com.maddyhome.idea.vim.helper.vimSelectionStartClear
 | 
				
			||||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
 | 
					internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override val registerStorage: VimRegisterGroup
 | 
					 | 
				
			||||||
    get() = injector.registerGroup
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
  override val markStorage: LocalMarkStorage
 | 
					  override val markStorage: LocalMarkStorage
 | 
				
			||||||
    get() {
 | 
					    get() {
 | 
				
			||||||
      var storage = this.caret.markStorage
 | 
					      var storage = this.caret.markStorage
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,12 +38,12 @@ import com.maddyhome.idea.vim.api.VimSelectionModel
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
					import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VirtualFile
 | 
					import com.maddyhome.idea.vim.api.VirtualFile
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.common.IndentConfig
 | 
					import com.maddyhome.idea.vim.common.IndentConfig
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.common.IndentConfig.Companion.create
 | 
				
			||||||
import com.maddyhome.idea.vim.common.LiveRange
 | 
					import com.maddyhome.idea.vim.common.LiveRange
 | 
				
			||||||
import com.maddyhome.idea.vim.common.ModeChangeListener
 | 
					import com.maddyhome.idea.vim.common.ModeChangeListener
 | 
				
			||||||
import com.maddyhome.idea.vim.common.TextRange
 | 
					import com.maddyhome.idea.vim.common.TextRange
 | 
				
			||||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.common.forgetAllReplaceMasks
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemBlockSelectionSilently
 | 
					import com.maddyhome.idea.vim.group.visual.vimSetSystemBlockSelectionSilently
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.StrictMode
 | 
					import com.maddyhome.idea.vim.helper.StrictMode
 | 
				
			||||||
@@ -53,15 +53,12 @@ import com.maddyhome.idea.vim.helper.fileSize
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
 | 
					import com.maddyhome.idea.vim.helper.getTopLevelEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.inExMode
 | 
					import com.maddyhome.idea.vim.helper.inExMode
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.isTemplateActive
 | 
					import com.maddyhome.idea.vim.helper.isTemplateActive
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.replaceMask
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
 | 
					import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimLastSelectionType
 | 
					import com.maddyhome.idea.vim.helper.vimLastSelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
 | 
					import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.inBlockSelection
 | 
					import com.maddyhome.idea.vim.state.mode.inBlockSelection
 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimKeyBasedUndoService
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.undo.VimTimestampBasedUndoService
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus
 | 
					import org.jetbrains.annotations.ApiStatus
 | 
				
			||||||
import java.lang.System.identityHashCode
 | 
					import java.lang.System.identityHashCode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,11 +75,6 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
				
			|||||||
  // TBH, I don't like the names. Need to think a bit more about this
 | 
					  // TBH, I don't like the names. Need to think a bit more about this
 | 
				
			||||||
  val editor = editor.getTopLevelEditor()
 | 
					  val editor = editor.getTopLevelEditor()
 | 
				
			||||||
  val originalEditor = editor
 | 
					  val originalEditor = editor
 | 
				
			||||||
  override var replaceMask: VimEditorReplaceMask?
 | 
					 | 
				
			||||||
    get() = editor.replaceMask
 | 
					 | 
				
			||||||
    set(value) {
 | 
					 | 
				
			||||||
      editor.replaceMask = value
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun updateMode(mode: Mode) {
 | 
					  override fun updateMode(mode: Mode) {
 | 
				
			||||||
    (injector.vimState as VimStateMachineImpl).mode = mode
 | 
					    (injector.vimState as VimStateMachineImpl).mode = mode
 | 
				
			||||||
@@ -99,7 +91,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
				
			|||||||
      editor.vimChangeActionSwitchMode = value
 | 
					      editor.vimChangeActionSwitchMode = value
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  override val indentConfig: VimIndentConfig
 | 
					  override val indentConfig: VimIndentConfig
 | 
				
			||||||
    get() = IndentConfig.create(editor)
 | 
					    get() = create(editor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun fileSize(): Long = editor.fileSize.toLong()
 | 
					  override fun fileSize(): Long = editor.fileSize.toLong()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,13 +134,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
 | 
					  override fun insertText(caret: VimCaret, atPosition: Int, text: CharSequence) {
 | 
				
			||||||
    if (injector.vimState.mode is Mode.INSERT) {
 | 
					    if (injector.vimState.mode is Mode.INSERT) {
 | 
				
			||||||
      val undo = injector.undo
 | 
					      injector.undo.startInsertSequence(caret, atPosition, System.nanoTime())
 | 
				
			||||||
      when (undo) {
 | 
					 | 
				
			||||||
        is VimKeyBasedUndoService -> undo.setInsertNonMergeUndoKey()
 | 
					 | 
				
			||||||
        is VimTimestampBasedUndoService -> {
 | 
					 | 
				
			||||||
          undo.startInsertSequence(caret, atPosition, System.nanoTime())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    editor.document.insertString(atPosition, text)
 | 
					    editor.document.insertString(atPosition, text)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -412,8 +398,8 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
				
			|||||||
    return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight))
 | 
					    return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun exitInsertMode(context: ExecutionContext) {
 | 
					  override fun exitInsertMode(context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
    editor.exitInsertMode(context.ij)
 | 
					    editor.exitInsertMode(context.ij, operatorArguments)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun exitSelectModeNative(adjustCaret: Boolean) {
 | 
					  override fun exitSelectModeNative(adjustCaret: Boolean) {
 | 
				
			||||||
@@ -485,7 +471,6 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
				
			|||||||
    get() = (editor as? EditorEx)?.isInsertMode ?: false
 | 
					    get() = (editor as? EditorEx)?.isInsertMode ?: false
 | 
				
			||||||
    set(value) {
 | 
					    set(value) {
 | 
				
			||||||
      (editor as? EditorEx)?.isInsertMode = value
 | 
					      (editor as? EditorEx)?.isInsertMode = value
 | 
				
			||||||
      forgetAllReplaceMasks()
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override val document: VimDocument
 | 
					  override val document: VimDocument
 | 
				
			||||||
@@ -557,7 +542,7 @@ internal class InsertTimeRecorder: ModeChangeListener {
 | 
				
			|||||||
  override fun modeChanged(editor: VimEditor, oldMode: Mode) {
 | 
					  override fun modeChanged(editor: VimEditor, oldMode: Mode) {
 | 
				
			||||||
    editor as IjVimEditor
 | 
					    editor as IjVimEditor
 | 
				
			||||||
    if (oldMode == Mode.INSERT) {
 | 
					    if (oldMode == Mode.INSERT) {
 | 
				
			||||||
      val undo = injector.undo as? VimTimestampBasedUndoService ?: return
 | 
					      val undo = injector.undo
 | 
				
			||||||
      val nanoTime = System.nanoTime()
 | 
					      val nanoTime = System.nanoTime()
 | 
				
			||||||
      editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
					      editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.api.VimApplication
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimChangeGroup
 | 
					import com.maddyhome.idea.vim.api.VimChangeGroup
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimClipboardManager
 | 
					import com.maddyhome.idea.vim.api.VimClipboardManager
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimCommandGroup
 | 
					import com.maddyhome.idea.vim.api.VimCommandGroup
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimCommandLine
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimCommandLineService
 | 
					import com.maddyhome.idea.vim.api.VimCommandLineService
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimDigraphGroup
 | 
					import com.maddyhome.idea.vim.api.VimDigraphGroup
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,11 @@ import com.intellij.openapi.editor.event.DocumentEvent
 | 
				
			|||||||
import com.intellij.openapi.editor.event.DocumentListener
 | 
					import com.intellij.openapi.editor.event.DocumentListener
 | 
				
			||||||
import com.intellij.openapi.editor.markup.RangeHighlighter
 | 
					import com.intellij.openapi.editor.markup.RangeHighlighter
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
					import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.Ref
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.Options
 | 
					import com.maddyhome.idea.vim.api.Options
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimCaret
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimSearchGroupBase
 | 
					import com.maddyhome.idea.vim.api.VimSearchGroupBase
 | 
				
			||||||
import com.maddyhome.idea.vim.api.globalOptions
 | 
					import com.maddyhome.idea.vim.api.globalOptions
 | 
				
			||||||
@@ -27,16 +30,21 @@ import com.maddyhome.idea.vim.api.injector
 | 
				
			|||||||
import com.maddyhome.idea.vim.common.Direction
 | 
					import com.maddyhome.idea.vim.common.Direction
 | 
				
			||||||
import com.maddyhome.idea.vim.common.Direction.Companion.fromInt
 | 
					import com.maddyhome.idea.vim.common.Direction.Companion.fromInt
 | 
				
			||||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
 | 
					import com.maddyhome.idea.vim.diagnostic.vimLogger
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.MessageHelper
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.TestInputModel.Companion.getInstance
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight
 | 
					import com.maddyhome.idea.vim.helper.addSubstitutionConfirmationHighlight
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.highlightSearchResults
 | 
					import com.maddyhome.idea.vim.helper.highlightSearchResults
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.isCloseKeyStroke
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.shouldIgnoreCase
 | 
					import com.maddyhome.idea.vim.helper.shouldIgnoreCase
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.updateSearchHighlights
 | 
					import com.maddyhome.idea.vim.helper.updateSearchHighlights
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimLastHighlighters
 | 
					import com.maddyhome.idea.vim.helper.vimLastHighlighters
 | 
				
			||||||
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
 | 
					import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.ui.ModalEntry
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler
 | 
					import com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler
 | 
				
			||||||
import org.jdom.Element
 | 
					import org.jdom.Element
 | 
				
			||||||
import org.jetbrains.annotations.Contract
 | 
					import org.jetbrains.annotations.Contract
 | 
				
			||||||
import org.jetbrains.annotations.TestOnly
 | 
					import org.jetbrains.annotations.TestOnly
 | 
				
			||||||
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@State(
 | 
					@State(
 | 
				
			||||||
  name = "VimSearchSettings",
 | 
					  name = "VimSearchSettings",
 | 
				
			||||||
@@ -44,7 +52,7 @@ import org.jetbrains.annotations.TestOnly
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> {
 | 
					open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Element> {
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    private val logger by lazy { vimLogger<IjVimSearchGroup>() }
 | 
					    private val logger = vimLogger<IjVimSearchGroup>()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init {
 | 
					  init {
 | 
				
			||||||
@@ -104,25 +112,27 @@ open class IjVimSearchGroup : VimSearchGroupBase(), PersistentStateComponent<Ele
 | 
				
			|||||||
    return IjSearchHighlight(ijEditor, highlighter)
 | 
					    return IjSearchHighlight(ijEditor, highlighter)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun setLatestMatch(match: String) {
 | 
				
			||||||
 | 
					    SubmatchFunctionHandler.getInstance().latestMatch = match
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun replaceString(
 | 
				
			||||||
 | 
					    editor: VimEditor,
 | 
				
			||||||
 | 
					    startOffset: Int,
 | 
				
			||||||
 | 
					    endOffset: Int,
 | 
				
			||||||
 | 
					    newString: String,
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    ApplicationManager.getApplication().runWriteAction {
 | 
				
			||||||
 | 
					      (editor as IjVimEditor).editor.document.replaceString(startOffset, endOffset, newString)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @TestOnly
 | 
					  @TestOnly
 | 
				
			||||||
  override fun resetState() {
 | 
					  override fun resetState() {
 | 
				
			||||||
    super.resetState()
 | 
					    super.resetState()
 | 
				
			||||||
    showSearchHighlight = injector.globalOptions().hlsearch
 | 
					    showSearchHighlight = injector.globalOptions().hlsearch
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun isSomeTextHighlighted(): Boolean {
 | 
					 | 
				
			||||||
    val vimEditors = injector.editorGroup.getEditors().filter {
 | 
					 | 
				
			||||||
      (injector.application.isUnitTest() || it.ij.component.isShowing)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (vimEditor in vimEditors) {
 | 
					 | 
				
			||||||
      val editor = vimEditor.ij
 | 
					 | 
				
			||||||
      if (editor.vimLastHighlighters != null) {
 | 
					 | 
				
			||||||
        return true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun setShouldShowSearchHighlights() {
 | 
					  override fun setShouldShowSearchHighlights() {
 | 
				
			||||||
    showSearchHighlight = injector.globalOptions().hlsearch
 | 
					    showSearchHighlight = injector.globalOptions().hlsearch
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										718
									
								
								src/main/java/com/maddyhome/idea/vim/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										718
									
								
								src/main/java/com/maddyhome/idea/vim/package-info.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,718 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * IdeaVim command index.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 1. Insert mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |i_CTRL-@|             {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertExitAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-A|             {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-C|             {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-D|             {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftLinesAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-E|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterBelowCursorAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-G_j|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-G_k|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-G_u|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_<BS>|               {@link com.maddyhome.idea.vim.action.editor.VimEditorBackSpace}
 | 
				
			||||||
 | 
					 * |i_digraph|            IdeaVim enter digraph
 | 
				
			||||||
 | 
					 * |i_CTRL-H|             IntelliJ editor backspace
 | 
				
			||||||
 | 
					 * |i_<Tab>|              {@link com.maddyhome.idea.vim.action.editor.VimEditorTab}
 | 
				
			||||||
 | 
					 * |i_CTRL-I|             IntelliJ editor tab
 | 
				
			||||||
 | 
					 * |i_<NL>|               {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-J|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-K|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-L|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_<CR>|               {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-M|             {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-N|             {@link com.maddyhome.idea.vim.action.window.LookupDownAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-O|             {@link com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-P|             {@link com.maddyhome.idea.vim.action.window.LookupUpAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-Q|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-R|             {@link com.maddyhome.idea.vim.action.change.insert.InsertRegisterAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-R_CTRL-R|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-R_CTRL-O|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-R_CTRL-P|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-T|             {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightLinesAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-U|             {@link com.maddyhome.idea.vim.action.change.insert.InsertDeleteInsertedTextAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-V|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-V_digit|       {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-W|             {@link com.maddyhome.idea.vim.action.change.insert.InsertDeletePreviousWordAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-X|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-Y|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterAboveCursorAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-Z|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_<Esc>|              {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-[|             {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-\_CTRL-N|      {@link com.maddyhome.idea.vim.action.ResetModeAction}
 | 
				
			||||||
 | 
					 * |i_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-]}             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-^|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_CTRL-_|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_0_CTRL-D|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_^_CTRL-D|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |i_<Del>|              {@link com.maddyhome.idea.vim.action.editor.VimEditorDelete}
 | 
				
			||||||
 | 
					 * |i_<Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<S-Left>|           {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
 | 
				
			||||||
 | 
					 * |i_<C-Left>|           {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
 | 
				
			||||||
 | 
					 * |i_<Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction}
 | 
				
			||||||
 | 
					 * |i_<S-Right>|          {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
 | 
				
			||||||
 | 
					 * |i_<C-Right>|          {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
 | 
				
			||||||
 | 
					 * |i_<Up>|               {@link com.maddyhome.idea.vim.action.editor.VimEditorUp}
 | 
				
			||||||
 | 
					 * |i_<S-Up>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<Down>|             {@link com.maddyhome.idea.vim.action.editor.VimEditorDown}
 | 
				
			||||||
 | 
					 * |i_<S-Down>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<Home>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<C-Home>|           {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstInsertAction}
 | 
				
			||||||
 | 
					 * |i_<End>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnInsertAction}
 | 
				
			||||||
 | 
					 * |i_<C-End>|            {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndInsertAction}
 | 
				
			||||||
 | 
					 * |i_<Insert>|           {@link com.maddyhome.idea.vim.action.change.insert.InsertInsertAction}
 | 
				
			||||||
 | 
					 * |i_<PageUp>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<PageDown>|         {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
 | 
				
			||||||
 | 
					 * |i_<F1>|               IntelliJ help
 | 
				
			||||||
 | 
					 * |i_<Insert>|           IntelliJ editor toggle insert/replace
 | 
				
			||||||
 | 
					 * |i_CTRL-X_index|       TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2. Normal mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |CTRL-A|               {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberIncAction}
 | 
				
			||||||
 | 
					 * |CTRL-B|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-C|               TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-D|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-E|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-F|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-G|               {@link com.maddyhome.idea.vim.action.file.FileGetFileInfoAction}
 | 
				
			||||||
 | 
					 * |<BS>|                 {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
 | 
				
			||||||
 | 
					 * |CTRL-H|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
 | 
				
			||||||
 | 
					 * |<Tab>|                TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-I|               {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpNextAction}
 | 
				
			||||||
 | 
					 * |<NL>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownNotLineWiseAction}
 | 
				
			||||||
 | 
					 * |CTRL-J|               TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-L|               not applicable
 | 
				
			||||||
 | 
					 * |<CR>|                 {@link com.maddyhome.idea.vim.action.motion.updown.EnterNormalAction}
 | 
				
			||||||
 | 
					 * |CTRL-M|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
 | 
				
			||||||
 | 
					 * |CTRL-N|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction}
 | 
				
			||||||
 | 
					 * |CTRL-O|               {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpPreviousAction}
 | 
				
			||||||
 | 
					 * |CTRL-P|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpCtrlPAction}
 | 
				
			||||||
 | 
					 * |CTRL-R|               {@link com.maddyhome.idea.vim.action.change.RedoAction}
 | 
				
			||||||
 | 
					 * |CTRL-T|               TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-U|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-V|               {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleBlockModeAction}
 | 
				
			||||||
 | 
					 * |CTRL-W|               see window commands
 | 
				
			||||||
 | 
					 * |CTRL-X|               {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberDecAction}
 | 
				
			||||||
 | 
					 * |CTRL-Y|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-Z|               TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-]|               {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
				
			||||||
 | 
					 * |CTRL-6|               {@link com.maddyhome.idea.vim.action.file.FilePreviousAction}
 | 
				
			||||||
 | 
					 * |CTRL-\CTRL-N|         {@link com.maddyhome.idea.vim.action.ResetModeAction}
 | 
				
			||||||
 | 
					 * |<Space>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionSpaceAction}
 | 
				
			||||||
 | 
					 * |!|                    {@link com.maddyhome.idea.vim.action.change.change.FilterMotionAction}
 | 
				
			||||||
 | 
					 * |!!|                   translated to !_
 | 
				
			||||||
 | 
					 * |quote|                handled by command key parser
 | 
				
			||||||
 | 
					 * |#|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordBackwardAction}
 | 
				
			||||||
 | 
					 * |$|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction}
 | 
				
			||||||
 | 
					 * |%|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionPercentOrMatchAction}
 | 
				
			||||||
 | 
					 * |&|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeLastSearchReplaceAction}
 | 
				
			||||||
 | 
					 * |'|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineAction}
 | 
				
			||||||
 | 
					 * |''|                   ?
 | 
				
			||||||
 | 
					 * ...
 | 
				
			||||||
 | 
					 * |(|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousStartAction}
 | 
				
			||||||
 | 
					 * |)|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextStartAction}
 | 
				
			||||||
 | 
					 * |star|                 {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction}
 | 
				
			||||||
 | 
					 * |+|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
 | 
				
			||||||
 | 
					 * |,|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharReverseAction}
 | 
				
			||||||
 | 
					 * |-|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpFirstNonSpaceAction}
 | 
				
			||||||
 | 
					 * |.|                    {@link com.maddyhome.idea.vim.action.change.RepeatChangeAction}
 | 
				
			||||||
 | 
					 * |/|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction}
 | 
				
			||||||
 | 
					 * |:|                    {@link com.maddyhome.idea.vim.action.ex.ExEntryAction}
 | 
				
			||||||
 | 
					 * |;|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharAction}
 | 
				
			||||||
 | 
					 * |<|                    {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftMotionAction}
 | 
				
			||||||
 | 
					 * |<<|                   translated to <_
 | 
				
			||||||
 | 
					 * |=|                    {@link com.maddyhome.idea.vim.action.change.shift.AutoIndentMotionAction}
 | 
				
			||||||
 | 
					 * |==|                   translated to =_
 | 
				
			||||||
 | 
					 * |>|                    {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightMotionAction}
 | 
				
			||||||
 | 
					 * |>>|                   translated to >_
 | 
				
			||||||
 | 
					 * |?|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction}
 | 
				
			||||||
 | 
					 * |@|                    {@link com.maddyhome.idea.vim.action.macro.PlaybackRegisterAction}
 | 
				
			||||||
 | 
					 * |A|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterLineEndAction}
 | 
				
			||||||
 | 
					 * |B|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordLeftAction}
 | 
				
			||||||
 | 
					 * |C|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction}
 | 
				
			||||||
 | 
					 * |D|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteEndOfLineAction}
 | 
				
			||||||
 | 
					 * |E|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndRightAction}
 | 
				
			||||||
 | 
					 * |F|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftMatchCharAction}
 | 
				
			||||||
 | 
					 * |G|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastAction}
 | 
				
			||||||
 | 
					 * |H|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionFirstScreenLineAction}
 | 
				
			||||||
 | 
					 * |H|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingFirstScreenLineAction}
 | 
				
			||||||
 | 
					 * |I|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeFirstNonBlankAction}
 | 
				
			||||||
 | 
					 * |J|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction}
 | 
				
			||||||
 | 
					 * |K|                    {@link com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc}
 | 
				
			||||||
 | 
					 * |L|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionLastScreenLineAction}
 | 
				
			||||||
 | 
					 * |L|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingLastScreenLineAction}
 | 
				
			||||||
 | 
					 * |M|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionMiddleScreenLineAction}
 | 
				
			||||||
 | 
					 * |N|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainPreviousAction}
 | 
				
			||||||
 | 
					 * |O|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineAboveAction}
 | 
				
			||||||
 | 
					 * |P|                    {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorAction}
 | 
				
			||||||
 | 
					 * |Q|                    TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |R|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeReplaceAction}
 | 
				
			||||||
 | 
					 * |S|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeLineAction}
 | 
				
			||||||
 | 
					 * |T|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftTillMatchCharAction}
 | 
				
			||||||
 | 
					 * |U|                    ?
 | 
				
			||||||
 | 
					 * |V|                    {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleLineModeAction}
 | 
				
			||||||
 | 
					 * |W|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordRightAction}
 | 
				
			||||||
 | 
					 * |X|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterLeftAction}
 | 
				
			||||||
 | 
					 * |Y|                    {@link com.maddyhome.idea.vim.action.copy.YankLineAction}
 | 
				
			||||||
 | 
					 * |ZZ|                   {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
 | 
				
			||||||
 | 
					 * |ZQ|                   {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
 | 
				
			||||||
 | 
					 * |[|                    see bracket commands
 | 
				
			||||||
 | 
					 * |]|                    see bracket commands
 | 
				
			||||||
 | 
					 * |^|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstNonSpaceAction}
 | 
				
			||||||
 | 
					 * |_|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction}
 | 
				
			||||||
 | 
					 * |`|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkAction}
 | 
				
			||||||
 | 
					 * |``|                   ?
 | 
				
			||||||
 | 
					 * ...
 | 
				
			||||||
 | 
					 * |0|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnAction}
 | 
				
			||||||
 | 
					 * |a|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterCursorAction}
 | 
				
			||||||
 | 
					 * |b|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
 | 
				
			||||||
 | 
					 * |c|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeMotionAction}
 | 
				
			||||||
 | 
					 * |cc|                   translated to c_
 | 
				
			||||||
 | 
					 * |d|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteMotionAction}
 | 
				
			||||||
 | 
					 * |dd|                   translated to d_
 | 
				
			||||||
 | 
					 * |do|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |dp|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |e|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndRightAction}
 | 
				
			||||||
 | 
					 * |f|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction}
 | 
				
			||||||
 | 
					 * |g|                    see commands starting with 'g'
 | 
				
			||||||
 | 
					 * |h|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction}
 | 
				
			||||||
 | 
					 * |i|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
 | 
				
			||||||
 | 
					 * |j|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownAction}
 | 
				
			||||||
 | 
					 * |k|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpAction}
 | 
				
			||||||
 | 
					 * |l|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction}
 | 
				
			||||||
 | 
					 * |m|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionMarkAction}
 | 
				
			||||||
 | 
					 * |n|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainNextAction}
 | 
				
			||||||
 | 
					 * |o|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineBelowAction}
 | 
				
			||||||
 | 
					 * |p|                    {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorAction}
 | 
				
			||||||
 | 
					 * |q|                    {@link com.maddyhome.idea.vim.action.macro.ToggleRecordingAction}
 | 
				
			||||||
 | 
					 * |r|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction}
 | 
				
			||||||
 | 
					 * |s|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction}
 | 
				
			||||||
 | 
					 * |t|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction}
 | 
				
			||||||
 | 
					 * |u|                    {@link com.maddyhome.idea.vim.action.change.UndoAction}
 | 
				
			||||||
 | 
					 * |v|                    {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction}
 | 
				
			||||||
 | 
					 * |w|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
 | 
				
			||||||
 | 
					 * |x|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterRightAction}
 | 
				
			||||||
 | 
					 * |y|                    {@link com.maddyhome.idea.vim.action.copy.YankMotionAction}
 | 
				
			||||||
 | 
					 * |yy|                   translated to y_
 | 
				
			||||||
 | 
					 * |z|                    see commands starting with 'z'
 | 
				
			||||||
 | 
					 * |{|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphPreviousAction}
 | 
				
			||||||
 | 
					 * |bar|                  {@link com.maddyhome.idea.vim.action.motion.leftright.MotionColumnAction}
 | 
				
			||||||
 | 
					 * |}|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphNextAction}
 | 
				
			||||||
 | 
					 * |~|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction}
 | 
				
			||||||
 | 
					 * |<C-End>|              {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndAction}
 | 
				
			||||||
 | 
					 * |<C-Home>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
 | 
				
			||||||
 | 
					 * |<C-Left>|             {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
 | 
				
			||||||
 | 
					 * |<C-Right>|            {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
 | 
				
			||||||
 | 
					 * |<C-Down>|             {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlDownAction}
 | 
				
			||||||
 | 
					 * |<C-Up>|               {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlUpAction}
 | 
				
			||||||
 | 
					 * |<Del>|                {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction}
 | 
				
			||||||
 | 
					 * |<Down>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
 | 
				
			||||||
 | 
					 * |<End>|                {@link com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction}
 | 
				
			||||||
 | 
					 * |<F1>|                 IntelliJ help
 | 
				
			||||||
 | 
					 * |<Home>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction}
 | 
				
			||||||
 | 
					 * |<Insert>|             {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
 | 
				
			||||||
 | 
					 * |<Left>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction}
 | 
				
			||||||
 | 
					 * |<PageDown>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
 | 
				
			||||||
 | 
					 * |<PageUp>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
 | 
				
			||||||
 | 
					 * |<Right>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction}
 | 
				
			||||||
 | 
					 * |<S-Down>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
 | 
				
			||||||
 | 
					 * |<S-Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
 | 
				
			||||||
 | 
					 * |<S-Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
 | 
				
			||||||
 | 
					 * |<S-Up>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
 | 
				
			||||||
 | 
					 * |<S-Home>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction}
 | 
				
			||||||
 | 
					 * |<S-End>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction}
 | 
				
			||||||
 | 
					 * |<Up>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2.1. Text objects
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Text object commands are listed in the visual mode section.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2.2. Window commands
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |CTRL-W_+|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_-|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_<|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_=|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_>|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_H|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_J|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_K|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_L|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_P|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_R|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_S|             {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_T|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_W|             {@link com.maddyhome.idea.vim.action.window.WindowPrevAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_]|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_^|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W__|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_b|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_c|             {@link com.maddyhome.idea.vim.action.window.CloseWindowAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_d|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_f|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W-F|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W-g]|            TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W-g}|            TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W-gf|            TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W-gF|            TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_h|             {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_i|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_j|             {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_k|             {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_l|             {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_n|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_o|             {@link com.maddyhome.idea.vim.action.window.WindowOnlyAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_p|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_q|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_r|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_s|             {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_t|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_v|             {@link com.maddyhome.idea.vim.action.window.VerticalSplitAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_w|             {@link com.maddyhome.idea.vim.action.window.WindowNextAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_x|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_z|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_bar|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_}|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |CTRL-W_<Down>|        {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_<Up>|          {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_<Left>|        {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_<Right>|       {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_CTRL-H|        {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_CTRL-J|        {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_CTRL-K|        {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
				
			||||||
 | 
					 * |CTRL-W_CTRL-L|        {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2.3. Square bracket commands
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * |[_CTRL-D|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[_CTRL-I|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[#|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |['|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[(|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenOpenAction}
 | 
				
			||||||
 | 
					 * |[star|                TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[`|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[/|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[D|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[I|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[M|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousEndAction}
 | 
				
			||||||
 | 
					 * |[P|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |[P|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |[[|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardStartAction}
 | 
				
			||||||
 | 
					 * |[]|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardEndAction}
 | 
				
			||||||
 | 
					 * |[c|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[d|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[f|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[i|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
 | 
				
			||||||
 | 
					 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |[s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
 | 
				
			||||||
 | 
					 * |[z|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |[{|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
 | 
				
			||||||
 | 
					 * |]_CTRL-D|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]_CTRL-I|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]#|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]'|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |])|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenCloseAction}
 | 
				
			||||||
 | 
					 * |]star|                TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]`|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]/|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]D|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]I|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]M|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction}
 | 
				
			||||||
 | 
					 * |]P|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |]P|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |][|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardEndAction}
 | 
				
			||||||
 | 
					 * |]]|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardStartAction}
 | 
				
			||||||
 | 
					 * |]c|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]d|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]f|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]i|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
 | 
				
			||||||
 | 
					 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
				
			||||||
 | 
					 * |]s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
 | 
				
			||||||
 | 
					 * |]z|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |]}|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2.4. Commands starting with 'g'
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |g_CTRL-A|             not applicable
 | 
				
			||||||
 | 
					 * |g_CTRL-G|             {@link com.maddyhome.idea.vim.action.file.FileGetLocationInfoAction}
 | 
				
			||||||
 | 
					 * |g_CTRL-H|             {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableBlockModeAction}
 | 
				
			||||||
 | 
					 * |g_CTRL-]|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g#|                   {@link com.maddyhome.idea.vim.action.motion.search.SearchWordBackwardAction}
 | 
				
			||||||
 | 
					 * |g$|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
 | 
				
			||||||
 | 
					 * |g&|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeLastGlobalSearchReplaceAction}
 | 
				
			||||||
 | 
					 * |v_g'|                 {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineNoSaveJumpAction}
 | 
				
			||||||
 | 
					 * |g'|                   {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineNoSaveJumpAction}
 | 
				
			||||||
 | 
					 * |g`|                   {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkNoSaveJumpAction}
 | 
				
			||||||
 | 
					 * |gstar|                {@link com.maddyhome.idea.vim.action.motion.search.SearchWordForwardAction}
 | 
				
			||||||
 | 
					 * |g+|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g,|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g-|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g0|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
 | 
				
			||||||
 | 
					 * |g8|                   {@link com.maddyhome.idea.vim.action.file.FileGetHexAction}
 | 
				
			||||||
 | 
					 * |g;|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g<|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g?|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g?g?|                 TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gD|                   {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
				
			||||||
 | 
					 * |gE|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndLeftAction}
 | 
				
			||||||
 | 
					 * |gF|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gH|                   {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableLineModeAction}
 | 
				
			||||||
 | 
					 * |gI|                   {@link com.maddyhome.idea.vim.action.change.insert.InsertLineStartAction}
 | 
				
			||||||
 | 
					 * |gJ|                   {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction}
 | 
				
			||||||
 | 
					 * |gN|                   {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch}
 | 
				
			||||||
 | 
					 * |gN|                   {@link com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject}
 | 
				
			||||||
 | 
					 * |gP|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorMoveCursorAction}
 | 
				
			||||||
 | 
					 * |gP|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorActionMoveCursor}
 | 
				
			||||||
 | 
					 * |gQ|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gR|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gT|                   {@link com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction}
 | 
				
			||||||
 | 
					 * |gU|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction}
 | 
				
			||||||
 | 
					 * |gV|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g]|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g^|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenNonSpaceAction}
 | 
				
			||||||
 | 
					 * |g_|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastNonSpaceAction}
 | 
				
			||||||
 | 
					 * |ga|                   {@link com.maddyhome.idea.vim.action.file.FileGetAsciiAction}
 | 
				
			||||||
 | 
					 * |gd|                   {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
				
			||||||
 | 
					 * |ge|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndLeftAction}
 | 
				
			||||||
 | 
					 * |gf|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gg|                   {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
 | 
				
			||||||
 | 
					 * |gh|                   {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableCharacterModeAction}
 | 
				
			||||||
 | 
					 * |gi|                   {@link com.maddyhome.idea.vim.action.change.insert.InsertAtPreviousInsertAction}
 | 
				
			||||||
 | 
					 * |gj|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gk|                   {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
 | 
				
			||||||
 | 
					 * |gn|                   {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch}
 | 
				
			||||||
 | 
					 * |gn|                   {@link com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject}
 | 
				
			||||||
 | 
					 * |gm|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionMiddleColumnAction}
 | 
				
			||||||
 | 
					 * |go|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionNthCharacterAction}
 | 
				
			||||||
 | 
					 * |gp|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorMoveCursorAction}
 | 
				
			||||||
 | 
					 * |gp|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorActionMoveCursor}
 | 
				
			||||||
 | 
					 * |gq|                   {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeMotionAction}
 | 
				
			||||||
 | 
					 * |gr|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gs|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |gt|                   {@link com.maddyhome.idea.vim.action.window.tabs.NextTabAction}
 | 
				
			||||||
 | 
					 * |gu|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction}
 | 
				
			||||||
 | 
					 * |gv|                   {@link com.maddyhome.idea.vim.action.motion.visual.VisualSelectPreviousAction}
 | 
				
			||||||
 | 
					 * |gw|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g@|                   {@link com.maddyhome.idea.vim.action.change.OperatorAction}
 | 
				
			||||||
 | 
					 * |g~|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction}
 | 
				
			||||||
 | 
					 * |g<Down>|              TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |g<End>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
 | 
				
			||||||
 | 
					 * |g<Home>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
 | 
				
			||||||
 | 
					 * |g<Up>|                {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 2.5. Commands starting with 'z'
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * |z<CR>|                {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineStartAction}
 | 
				
			||||||
 | 
					 * |z+|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLinePageStartAction}
 | 
				
			||||||
 | 
					 * |z-|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineStartAction}
 | 
				
			||||||
 | 
					 * |z.|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineStartAction}
 | 
				
			||||||
 | 
					 * |z=|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zA|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zC|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegionRecursively}
 | 
				
			||||||
 | 
					 * |zD|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zE|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zF|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zG|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zH|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction}
 | 
				
			||||||
 | 
					 * |zL|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction}
 | 
				
			||||||
 | 
					 * |zM|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseAllRegions}
 | 
				
			||||||
 | 
					 * |zN|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zO|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandRegionRecursively}
 | 
				
			||||||
 | 
					 * |zR|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandAllRegions}
 | 
				
			||||||
 | 
					 * |zW|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zX|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |z^|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLinePageStartAction}
 | 
				
			||||||
 | 
					 * |za|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zb|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineAction}
 | 
				
			||||||
 | 
					 * |zc|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegion}
 | 
				
			||||||
 | 
					 * |zd|                   not applicable
 | 
				
			||||||
 | 
					 * |ze|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenColumnAction}
 | 
				
			||||||
 | 
					 * |zf|                   not applicable
 | 
				
			||||||
 | 
					 * |zg|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zh|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
 | 
				
			||||||
 | 
					 * |zi|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zj|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zk|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zl|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
 | 
				
			||||||
 | 
					 * |zm|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zn|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zo|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandRegion}
 | 
				
			||||||
 | 
					 * |zr|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zs|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenColumnAction}
 | 
				
			||||||
 | 
					 * |zt|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineAction}
 | 
				
			||||||
 | 
					 * |zv|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zw|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zx|                   TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |zz|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineAction}
 | 
				
			||||||
 | 
					 * |z<Left>|              {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
 | 
				
			||||||
 | 
					 * |z<Right>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 3. Visual mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |v_CTRL-\_CTRL-N|      {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
				
			||||||
 | 
					 * |v_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |v_CTRL-A|             {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberIncAction}
 | 
				
			||||||
 | 
					 * |v_CTRL-C|             {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
				
			||||||
 | 
					 * |v_CTRL-G|             {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
 | 
				
			||||||
 | 
					 * |v_<BS>|               NVO mapping
 | 
				
			||||||
 | 
					 * |v_CTRL-H|             NVO mapping
 | 
				
			||||||
 | 
					 * |v_CTRL-O|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |v_CTRL-V|             NVO mapping
 | 
				
			||||||
 | 
					 * |v_<Esc>|              {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
				
			||||||
 | 
					 * |v_CTRL-X|             {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberDecAction}
 | 
				
			||||||
 | 
					 * |v_CTRL-]|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |v_!|                  {@link com.maddyhome.idea.vim.action.change.change.FilterVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_:|                  NVO mapping
 | 
				
			||||||
 | 
					 * |v_<|                  {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftVisualAction}
 | 
				
			||||||
 | 
					 * |v_=|                  {@link com.maddyhome.idea.vim.action.change.change.AutoIndentLinesVisualAction}
 | 
				
			||||||
 | 
					 * |v_>|                  {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightVisualAction}
 | 
				
			||||||
 | 
					 * |v_b_A|                {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction}
 | 
				
			||||||
 | 
					 * |v_C|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesEndAction}
 | 
				
			||||||
 | 
					 * |v_D|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesEndAction}
 | 
				
			||||||
 | 
					 * |v_b_I|                {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction}
 | 
				
			||||||
 | 
					 * |v_J|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction}
 | 
				
			||||||
 | 
					 * |v_K|                  TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |v_O|                  {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsBlockAction}
 | 
				
			||||||
 | 
					 * |v_P|                  {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorAction}
 | 
				
			||||||
 | 
					 * |v_R|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_S|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_U|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction}
 | 
				
			||||||
 | 
					 * |v_V|                  NV mapping
 | 
				
			||||||
 | 
					 * |v_X|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_Y|                  {@link com.maddyhome.idea.vim.action.copy.YankVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_aquote|             {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockDoubleQuoteAction}
 | 
				
			||||||
 | 
					 * |v_a'|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockSingleQuoteAction}
 | 
				
			||||||
 | 
					 * |v_a(|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_a)|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_a<|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
 | 
				
			||||||
 | 
					 * |v_a>|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
 | 
				
			||||||
 | 
					 * |v_aB|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_aW|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction}
 | 
				
			||||||
 | 
					 * |v_a[|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
 | 
				
			||||||
 | 
					 * |v_a]|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
 | 
				
			||||||
 | 
					 * |v_a`|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBackQuoteAction}
 | 
				
			||||||
 | 
					 * |v_ab|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_ap|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterParagraphAction}
 | 
				
			||||||
 | 
					 * |v_as|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterSentenceAction}
 | 
				
			||||||
 | 
					 * |v_at|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockTagAction}
 | 
				
			||||||
 | 
					 * |v_aw|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction}
 | 
				
			||||||
 | 
					 * |v_a{|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_a}|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_c|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
 | 
				
			||||||
 | 
					 * |v_d|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
 | 
				
			||||||
 | 
					 * |v_gCTRL-A|            {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheIncAction}
 | 
				
			||||||
 | 
					 * |v_gCTRL-X|            {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheDecAction}
 | 
				
			||||||
 | 
					 * |v_gJ|                 {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction}
 | 
				
			||||||
 | 
					 * |v_gq|                 {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeVisualAction}
 | 
				
			||||||
 | 
					 * |v_gv|                 {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapSelectionsAction}
 | 
				
			||||||
 | 
					 * |v_g`|                 {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkNoSaveJumpAction}
 | 
				
			||||||
 | 
					 * |v_g@|                 {@link com.maddyhome.idea.vim.action.change.VisualOperatorAction}
 | 
				
			||||||
 | 
					 * |v_iquote|             {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockDoubleQuoteAction}
 | 
				
			||||||
 | 
					 * |v_i'|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockSingleQuoteAction}
 | 
				
			||||||
 | 
					 * |v_i(|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_i)|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_i<|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
 | 
				
			||||||
 | 
					 * |v_i>|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
 | 
				
			||||||
 | 
					 * |v_iB|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_iW|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBigWordAction}
 | 
				
			||||||
 | 
					 * |v_i[|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
 | 
				
			||||||
 | 
					 * |v_i]|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
 | 
				
			||||||
 | 
					 * |v_i`|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBackQuoteAction}
 | 
				
			||||||
 | 
					 * |v_ib|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
				
			||||||
 | 
					 * |v_ip|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerParagraphAction}
 | 
				
			||||||
 | 
					 * |v_is|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerSentenceAction}
 | 
				
			||||||
 | 
					 * |v_it|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockTagAction}
 | 
				
			||||||
 | 
					 * |v_iw|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerWordAction}
 | 
				
			||||||
 | 
					 * |v_i{|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_i}|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
				
			||||||
 | 
					 * |v_o|                  {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsAction}
 | 
				
			||||||
 | 
					 * |v_p|                  {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorAction}
 | 
				
			||||||
 | 
					 * |v_r|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction}
 | 
				
			||||||
 | 
					 * |v_s|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
 | 
				
			||||||
 | 
					 * |v_u|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction}
 | 
				
			||||||
 | 
					 * |v_v|                  NV mapping
 | 
				
			||||||
 | 
					 * |v_x|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
 | 
				
			||||||
 | 
					 * |v_y|                  {@link com.maddyhome.idea.vim.action.copy.YankVisualAction}
 | 
				
			||||||
 | 
					 * |v_~|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction}
 | 
				
			||||||
 | 
					 * |v_`|                  {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkAction}
 | 
				
			||||||
 | 
					 * |v_'|                  {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 4. Select mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * |<BS>|                 {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
 | 
				
			||||||
 | 
					 * |<CR>|                 {@link com.maddyhome.idea.vim.action.motion.select.SelectEnterAction}
 | 
				
			||||||
 | 
					 * |<DEL>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
 | 
				
			||||||
 | 
					 * |<ESC>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectEscapeAction}
 | 
				
			||||||
 | 
					 * |<C-G>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
 | 
				
			||||||
 | 
					 * |<S-Down>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
 | 
				
			||||||
 | 
					 * |<S-Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
 | 
				
			||||||
 | 
					 * |<S-Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
 | 
				
			||||||
 | 
					 * |<S-Up>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
 | 
				
			||||||
 | 
					 * |<Down>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
 | 
				
			||||||
 | 
					 * |<Left>|               {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction}
 | 
				
			||||||
 | 
					 * |<Right>|              {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction}
 | 
				
			||||||
 | 
					 * |<Up>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 5. Command line editing
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    action
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |c_CTRL-A|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-B|             {@link javax.swing.text.DefaultEditorKit#beginLineAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-C|             {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-D|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-E|             {@link javax.swing.text.DefaultEditorKit#endLineAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-G|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-H|             {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-I|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-J|             {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-K|             Handled by KeyHandler
 | 
				
			||||||
 | 
					 * |c_CTRL-L|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-M|             {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-N|             {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-P|             {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-Q|             Handled by KeyHandler
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-A|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-F|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-L|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-O|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-P|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-R|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-R_CTRL-W|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-T|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-U|             {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-V|             Handled by KeyHandler
 | 
				
			||||||
 | 
					 * |c_CTRL-W|             {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
 | 
				
			||||||
 | 
					 * |c_CTRL-Y|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-\_e|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-\_CTRL-N|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-_|             not applicable
 | 
				
			||||||
 | 
					 * |c_CTRL-^|             not applicable
 | 
				
			||||||
 | 
					 * |c_CTRL-]|             TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_CTRL-[|             {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
 | 
				
			||||||
 | 
					 * |c_<BS>|               {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
 | 
				
			||||||
 | 
					 * |c_<CR>|               {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
				
			||||||
 | 
					 * |c_<C-Left>|           {@link javax.swing.text.DefaultEditorKit#previousWordAction}
 | 
				
			||||||
 | 
					 * |c_<C-Right>|          {@link javax.swing.text.DefaultEditorKit#nextWordAction}
 | 
				
			||||||
 | 
					 * |c_<Del>|              {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
 | 
				
			||||||
 | 
					 * |c_<Down>|             {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
 | 
				
			||||||
 | 
					 * |c_<End>|              {@link javax.swing.text.DefaultEditorKit#endLineAction}
 | 
				
			||||||
 | 
					 * |c_<Esc>|              {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
 | 
				
			||||||
 | 
					 * |c_<Home>|             {@link javax.swing.text.DefaultEditorKit#beginLineAction}
 | 
				
			||||||
 | 
					 * |c_<Insert>|           {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
 | 
				
			||||||
 | 
					 * |c_<Left>|             {@link javax.swing.text.DefaultEditorKit#backwardAction}
 | 
				
			||||||
 | 
					 * |c_<LeftMouse>|        not applicable
 | 
				
			||||||
 | 
					 * |c_<MiddleMouse>|      TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_<NL>|               {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
				
			||||||
 | 
					 * |c_<PageUp>|           {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
				
			||||||
 | 
					 * |c_<PageDown>|         {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
				
			||||||
 | 
					 * |c_<Right>|            {@link javax.swing.text.DefaultEditorKit#forwardAction}
 | 
				
			||||||
 | 
					 * |c_<S-Down>|           {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
				
			||||||
 | 
					 * |c_<S-Left>|           {@link javax.swing.text.DefaultEditorKit#previousWordAction}
 | 
				
			||||||
 | 
					 * |c_<S-Right>|          {@link javax.swing.text.DefaultEditorKit#nextWordAction}
 | 
				
			||||||
 | 
					 * |c_<S-Tab>|            TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_<S-Up>|             {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
				
			||||||
 | 
					 * |c_<Tab>|              TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |c_<Up>|               {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
 | 
				
			||||||
 | 
					 * |c_digraph|            {char1} <BS> {char2}
 | 
				
			||||||
 | 
					 * |c_wildchar|           TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 * |'cedit'|              TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 6. Ex commands
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    handler
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * |:map|                 {@link com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand}
 | 
				
			||||||
 | 
					 * |:nmap|                ...
 | 
				
			||||||
 | 
					 * |:vmap|                ...
 | 
				
			||||||
 | 
					 * |:omap|                ...
 | 
				
			||||||
 | 
					 * |:imap|                ...
 | 
				
			||||||
 | 
					 * |:cmap|                ...
 | 
				
			||||||
 | 
					 * |:noremap|             ...
 | 
				
			||||||
 | 
					 * |:nnoremap|            ...
 | 
				
			||||||
 | 
					 * |:vnoremap|            ...
 | 
				
			||||||
 | 
					 * |:onoremap|            ...
 | 
				
			||||||
 | 
					 * |:inoremap|            ...
 | 
				
			||||||
 | 
					 * |:cnoremap|            ...
 | 
				
			||||||
 | 
					 * |:shell|               {@link com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand}
 | 
				
			||||||
 | 
					 * |:sort|                {@link com.maddyhome.idea.vim.vimscript.model.commands.SortCommand}
 | 
				
			||||||
 | 
					 * |:source|              {@link com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand}
 | 
				
			||||||
 | 
					 * |:qall|                {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
				
			||||||
 | 
					 * |:quitall|             {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
				
			||||||
 | 
					 * |:quitall|             {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
				
			||||||
 | 
					 * |:wqall|               {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
				
			||||||
 | 
					 * |:xall|                {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
				
			||||||
 | 
					 * |:command|             {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand}
 | 
				
			||||||
 | 
					 * |:delcommand|          {@link com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand}
 | 
				
			||||||
 | 
					 * |:comclear|            {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand}
 | 
				
			||||||
 | 
					 * ...
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The list of supported Ex commands is incomplete.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A. Misc commands
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * tag                    handler
 | 
				
			||||||
 | 
					 * -------------------------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * |]b|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndLeftAction}
 | 
				
			||||||
 | 
					 * |]w|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndRightAction}
 | 
				
			||||||
 | 
					 * |[b|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelLeftAction}
 | 
				
			||||||
 | 
					 * |[w|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelRightAction}
 | 
				
			||||||
 | 
					 * |g(|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousEndAction}
 | 
				
			||||||
 | 
					 * |g)|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextEndAction}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * See also :help index.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author vlan
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim;
 | 
				
			||||||
@@ -32,9 +32,9 @@ internal class Troubleshooter {
 | 
				
			|||||||
  fun findIncorrectMappings(): List<Problem> {
 | 
					  fun findIncorrectMappings(): List<Problem> {
 | 
				
			||||||
    val problems = ArrayList<Problem>()
 | 
					    val problems = ArrayList<Problem>()
 | 
				
			||||||
    MappingMode.entries.forEach { mode ->
 | 
					    MappingMode.entries.forEach { mode ->
 | 
				
			||||||
      injector.keyGroup.getKeyMapping(mode).getAllByOwner(MappingOwner.IdeaVim.InitScript).forEach { entry ->
 | 
					      injector.keyGroup.getKeyMapping(mode).getByOwner(MappingOwner.IdeaVim.InitScript).forEach { (_, to) ->
 | 
				
			||||||
        (entry.mappingInfo as? ToKeysMappingInfo)?.let { mappingInfo ->
 | 
					        if (to is ToKeysMappingInfo) {
 | 
				
			||||||
          if (":action" in mappingInfo.toKeys.joinToString { it.keyChar.toString() }) {
 | 
					          if (":action" in to.toKeys.joinToString { it.keyChar.toString() }) {
 | 
				
			||||||
            problems += Problem("Mappings contain `:action` call")
 | 
					            problems += Problem("Mappings contain `:action` call")
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -192,13 +192,6 @@ private object VimActionsPopup {
 | 
				
			|||||||
        null,
 | 
					        null,
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    actionGroup.add(
 | 
					 | 
				
			||||||
      HelpLink(
 | 
					 | 
				
			||||||
        "Take Survey ↗",
 | 
					 | 
				
			||||||
        "https://surveys.jetbrains.com/s3/ideavim-usage-survey",
 | 
					 | 
				
			||||||
        AllIcons.Actions.IntentionBulb,
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    actionGroup.addSeparator(MessageHelper.message("action.eap.choice.active.text"))
 | 
					    actionGroup.addSeparator(MessageHelper.message("action.eap.choice.active.text"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    actionGroup.add(JoinEap)
 | 
					    actionGroup.add(JoinEap)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										263
									
								
								src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								src/main/java/com/maddyhome/idea/vim/ui/ex/ExActions.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,263 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.ui.ex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.LocalOptionInitialisationScenario
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import java.awt.event.ActionEvent
 | 
				
			||||||
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
 | 
					import javax.swing.Action
 | 
				
			||||||
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					import javax.swing.text.BadLocationException
 | 
				
			||||||
 | 
					import javax.swing.text.DefaultEditorKit
 | 
				
			||||||
 | 
					import javax.swing.text.Document
 | 
				
			||||||
 | 
					import javax.swing.text.TextAction
 | 
				
			||||||
 | 
					import kotlin.math.abs
 | 
				
			||||||
 | 
					import kotlin.math.min
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal interface MultiStepAction : Action {
 | 
				
			||||||
 | 
					  fun reset()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class HistoryUpAction : TextAction(ExEditorKit.HistoryUp) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(actionEvent) as ExTextField
 | 
				
			||||||
 | 
					    target.selectHistory(true, false)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class HistoryDownAction : TextAction(ExEditorKit.HistoryDown) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(actionEvent) as ExTextField
 | 
				
			||||||
 | 
					    target.selectHistory(false, false)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class HistoryUpFilterAction : TextAction(ExEditorKit.HistoryUpFilter) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(actionEvent) as ExTextField
 | 
				
			||||||
 | 
					    target.selectHistory(true, true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class HistoryDownFilterAction : TextAction(ExEditorKit.HistoryDownFilter) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(actionEvent) as ExTextField
 | 
				
			||||||
 | 
					    target.selectHistory(false, true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class CompleteEntryAction : TextAction(ExEditorKit.CompleteEntry) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
				
			||||||
 | 
					    logger.debug("complete entry")
 | 
				
			||||||
 | 
					    val stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
 | 
				
			||||||
 | 
					    // We do this for a couple of reasons:
 | 
				
			||||||
 | 
					    // * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
 | 
				
			||||||
 | 
					    //   write action
 | 
				
			||||||
 | 
					    // * The key handler routines get the chance to clean up and reset state
 | 
				
			||||||
 | 
					    val entry = ExEntryPanel.getInstance().entry
 | 
				
			||||||
 | 
					    val keyHandler = KeyHandler.getInstance()
 | 
				
			||||||
 | 
					    keyHandler.handleKey(entry.editor!!.vim, stroke, entry.context.vim, keyHandler.keyHandlerState)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    private val logger = logger<CompleteEntryAction>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class CancelEntryAction : TextAction(ExEditorKit.CancelEntry) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.cancel()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class EscapeCharAction : TextAction(ExEditorKit.EscapeChar) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.escape()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal abstract class DeleteCharAction internal constructor(name: String?) : TextAction(name) {
 | 
				
			||||||
 | 
					  @kotlin.jvm.Throws(BadLocationException::class)
 | 
				
			||||||
 | 
					  fun deleteSelection(doc: Document, dot: Int, mark: Int): Boolean {
 | 
				
			||||||
 | 
					    if (dot != mark) {
 | 
				
			||||||
 | 
					      doc.remove(min(dot, mark), abs(dot - mark))
 | 
				
			||||||
 | 
					      return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @kotlin.jvm.Throws(BadLocationException::class)
 | 
				
			||||||
 | 
					  fun deleteNextChar(doc: Document, dot: Int): Boolean {
 | 
				
			||||||
 | 
					    if (dot < doc.length) {
 | 
				
			||||||
 | 
					      var delChars = 1
 | 
				
			||||||
 | 
					      if (dot < doc.length - 1) {
 | 
				
			||||||
 | 
					        val dotChars = doc.getText(dot, 2)
 | 
				
			||||||
 | 
					        val c0 = dotChars[0]
 | 
				
			||||||
 | 
					        val c1 = dotChars[1]
 | 
				
			||||||
 | 
					        if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
 | 
				
			||||||
 | 
					          delChars = 2
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      doc.remove(dot, delChars)
 | 
				
			||||||
 | 
					      return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @kotlin.jvm.Throws(BadLocationException::class)
 | 
				
			||||||
 | 
					  fun deletePrevChar(doc: Document, dot: Int): Boolean {
 | 
				
			||||||
 | 
					    if (dot > 0) {
 | 
				
			||||||
 | 
					      var delChars = 1
 | 
				
			||||||
 | 
					      if (dot > 1) {
 | 
				
			||||||
 | 
					        val dotChars = doc.getText(dot - 2, 2)
 | 
				
			||||||
 | 
					        val c0 = dotChars[0]
 | 
				
			||||||
 | 
					        val c1 = dotChars[1]
 | 
				
			||||||
 | 
					        if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
 | 
				
			||||||
 | 
					          delChars = 2
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      doc.remove(dot - delChars, delChars)
 | 
				
			||||||
 | 
					      return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class DeleteNextCharAction : DeleteCharAction(DefaultEditorKit.deleteNextCharAction) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.saveLastEntry()
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      val doc = target.document
 | 
				
			||||||
 | 
					      val caret = target.caret
 | 
				
			||||||
 | 
					      val dot = caret.dot
 | 
				
			||||||
 | 
					      val mark = caret.mark
 | 
				
			||||||
 | 
					      if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
 | 
				
			||||||
 | 
					        target.cancel()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (ex: BadLocationException) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class DeletePreviousCharAction : DeleteCharAction(DefaultEditorKit.deletePrevCharAction) {
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.saveLastEntry()
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      val doc = target.document
 | 
				
			||||||
 | 
					      val caret = target.caret
 | 
				
			||||||
 | 
					      val dot = caret.dot
 | 
				
			||||||
 | 
					      val mark = caret.mark
 | 
				
			||||||
 | 
					      if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
 | 
				
			||||||
 | 
					        if (dot == 0 && doc.length == 0) {
 | 
				
			||||||
 | 
					          target.cancel()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (bl: BadLocationException) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class DeletePreviousWordAction : TextAction(DefaultEditorKit.deletePrevWordAction) {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Invoked when an action occurs.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.saveLastEntry()
 | 
				
			||||||
 | 
					    val doc = target.document
 | 
				
			||||||
 | 
					    val caret = target.caret
 | 
				
			||||||
 | 
					    val project = target.editor!!.project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create a VimEditor instance on the Swing text field which we can pass to the search helpers. We need an editor
 | 
				
			||||||
 | 
					    // rather than just working on a buffer because the search helpers need local options (specifically the local to
 | 
				
			||||||
 | 
					    // buffer 'iskeyword'). We use the CMD_LINE scenario to initialise local options from the main editor. The options
 | 
				
			||||||
 | 
					    // service will copy all local-to-buffer and local-to-window options, effectively cloning the options.
 | 
				
			||||||
 | 
					    // TODO: Over time, we should migrate all ex actions to be based on VimEditor
 | 
				
			||||||
 | 
					    // This will mean we always have an editor that has been initialised for options, etc. But also means that we can
 | 
				
			||||||
 | 
					    // share the command line entry actions between IdeaVim implementations
 | 
				
			||||||
 | 
					    val editor = TextComponentEditorImpl(project, target).vim
 | 
				
			||||||
 | 
					    injector.optionGroup.initialiseLocalOptions(editor, target.editor!!.vim, LocalOptionInitialisationScenario.CMD_LINE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val offset = injector.searchHelper.findNextWord(editor, caret.dot, -1, bigWord = false, spaceWords = false)
 | 
				
			||||||
 | 
					    if (logger.isDebugEnabled) logger.debug("offset=$offset")
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      val pos = caret.dot
 | 
				
			||||||
 | 
					      doc.remove(offset, pos - offset)
 | 
				
			||||||
 | 
					    } catch (ex: BadLocationException) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    private val logger = logger<DeletePreviousWordAction>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class DeleteToCursorAction : TextAction(ExEditorKit.DeleteToCursor) {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Invoked when an action occurs.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.saveLastEntry()
 | 
				
			||||||
 | 
					    val doc = target.document
 | 
				
			||||||
 | 
					    val caret = target.caret
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      doc.remove(0, caret.dot)
 | 
				
			||||||
 | 
					    } catch (ex: BadLocationException) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
 | 
					internal class ToggleInsertReplaceAction : TextAction(ExEditorKit.ToggleInsertReplace) {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Invoked when an action occurs.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
 | 
					    logger.debug("actionPerformed")
 | 
				
			||||||
 | 
					    val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					    target.toggleInsertReplace()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init {
 | 
				
			||||||
 | 
					    logger.debug("ToggleInsertReplaceAction()")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    private val logger = logger<ToggleInsertReplaceAction>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -34,7 +34,7 @@ public class ExDocument extends PlainDocument {
 | 
				
			|||||||
  void toggleInsertReplace() {
 | 
					  void toggleInsertReplace() {
 | 
				
			||||||
    VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
 | 
					    VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
 | 
				
			||||||
    if (commandLine != null) {
 | 
					    if (commandLine != null) {
 | 
				
			||||||
      ((ExEntryPanel) commandLine).isReplaceMode = !((ExEntryPanel)commandLine).isReplaceMode;
 | 
					      commandLine.toggleReplaceMode();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    overwrite = !overwrite;
 | 
					    overwrite = !overwrite;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,18 +7,58 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.ui.ex
 | 
					package com.maddyhome.idea.vim.ui.ex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.debug
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import org.jetbrains.annotations.NonNls
 | 
					import org.jetbrains.annotations.NonNls
 | 
				
			||||||
import java.awt.event.ActionEvent
 | 
					import java.awt.event.ActionEvent
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
 | 
					import javax.swing.Action
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
import javax.swing.text.DefaultEditorKit
 | 
					import javax.swing.text.DefaultEditorKit
 | 
				
			||||||
import javax.swing.text.Document
 | 
					import javax.swing.text.Document
 | 
				
			||||||
 | 
					import javax.swing.text.TextAction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
					@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
				
			||||||
internal object ExEditorKit : DefaultEditorKit() {
 | 
					internal object ExEditorKit : DefaultEditorKit() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val CancelEntry: String = "cancel-entry"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val CompleteEntry: String = "complete-entry"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val EscapeChar: String = "escape"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val DeleteToCursor: String = "delete-to-cursor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val ToggleInsertReplace: String = "toggle-insert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val HistoryUp: String = "history-up"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val HistoryDown: String = "history-down"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val HistoryUpFilter: String = "history-up-filter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val HistoryDownFilter: String = "history-down-filter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val StartDigraph: String = "start-digraph"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NonNls
 | 
				
			||||||
 | 
					  val StartLiteral: String = "start-literal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val logger = logger<ExEditorKit>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Gets the MIME type of the data that this
 | 
					   * Gets the MIME type of the data that this
 | 
				
			||||||
   * kit represents support for.
 | 
					   * kit represents support for.
 | 
				
			||||||
@@ -30,6 +70,19 @@ internal object ExEditorKit : DefaultEditorKit() {
 | 
				
			|||||||
    return "text/ideavim"
 | 
					    return "text/ideavim"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Fetches the set of commands that can be used
 | 
				
			||||||
 | 
					   * on a text component that is using a model and
 | 
				
			||||||
 | 
					   * view produced by this kit.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @return the set of actions
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  override fun getActions(): Array<Action> {
 | 
				
			||||||
 | 
					    val res = TextAction.augmentList(super.getActions(), exActions)
 | 
				
			||||||
 | 
					    logger.debug { "res.length=${res.size}" }
 | 
				
			||||||
 | 
					    return res
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Creates an uninitialized text storage model
 | 
					   * Creates an uninitialized text storage model
 | 
				
			||||||
   * that is appropriate for this type of editor.
 | 
					   * that is appropriate for this type of editor.
 | 
				
			||||||
@@ -40,29 +93,48 @@ internal object ExEditorKit : DefaultEditorKit() {
 | 
				
			|||||||
    return ExDocument()
 | 
					    return ExDocument()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val exActions = arrayOf<Action>(
 | 
				
			||||||
 | 
					    CancelEntryAction(),
 | 
				
			||||||
 | 
					    CompleteEntryAction(),
 | 
				
			||||||
 | 
					    EscapeCharAction(),
 | 
				
			||||||
 | 
					    DeleteNextCharAction(),
 | 
				
			||||||
 | 
					    DeletePreviousCharAction(),
 | 
				
			||||||
 | 
					    DeletePreviousWordAction(),
 | 
				
			||||||
 | 
					    DeleteToCursorAction(),
 | 
				
			||||||
 | 
					    HistoryUpAction(),
 | 
				
			||||||
 | 
					    HistoryDownAction(),
 | 
				
			||||||
 | 
					    HistoryUpFilterAction(),
 | 
				
			||||||
 | 
					    HistoryDownFilterAction(),
 | 
				
			||||||
 | 
					    ToggleInsertReplaceAction(),
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class DefaultExKeyHandler : DefaultKeyTypedAction() {
 | 
					  class DefaultExKeyHandler : DefaultKeyTypedAction() {
 | 
				
			||||||
    override fun actionPerformed(e: ActionEvent) {
 | 
					    override fun actionPerformed(e: ActionEvent) {
 | 
				
			||||||
      val target = getTextComponent(e) as ExTextField
 | 
					      val target = getTextComponent(e) as ExTextField
 | 
				
			||||||
 | 
					      val currentAction = target.currentAction
 | 
				
			||||||
      val key = convert(e)
 | 
					      if (currentAction != null) {
 | 
				
			||||||
      if (key != null) {
 | 
					        currentAction.actionPerformed(e)
 | 
				
			||||||
        val c = key.keyChar
 | 
					      } else {
 | 
				
			||||||
        if (c.code > 0) {
 | 
					        val key = convert(e)
 | 
				
			||||||
          if (target.useHandleKeyFromEx) {
 | 
					        if (key != null) {
 | 
				
			||||||
            val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
 | 
					          val c = key.keyChar
 | 
				
			||||||
            val entry = panel.entry
 | 
					          if (c.code > 0) {
 | 
				
			||||||
            val editor = entry.editor
 | 
					            if (target.useHandleKeyFromEx) {
 | 
				
			||||||
            val keyHandler = KeyHandler.getInstance()
 | 
					              val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
 | 
				
			||||||
            keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
 | 
					              val entry = panel.entry
 | 
				
			||||||
          } else {
 | 
					              val editor = entry.editor
 | 
				
			||||||
            val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
 | 
					              val keyHandler = KeyHandler.getInstance()
 | 
				
			||||||
            super.actionPerformed(event)
 | 
					              keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
 | 
				
			||||||
 | 
					              super.actionPerformed(event)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            target.saveLastEntry()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          super.actionPerformed(e)
 | 
				
			||||||
          target.saveLastEntry()
 | 
					          target.saveLastEntry()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        super.actionPerformed(e)
 | 
					 | 
				
			||||||
        target.saveLastEntry()
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,7 @@ import com.maddyhome.idea.vim.EventFacade;
 | 
				
			|||||||
import com.maddyhome.idea.vim.KeyHandler;
 | 
					import com.maddyhome.idea.vim.KeyHandler;
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
					import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimCommandLine;
 | 
					import com.maddyhome.idea.vim.api.*;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.ex.ranges.LineRange;
 | 
					import com.maddyhome.idea.vim.ex.ranges.LineRange;
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
 | 
					import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.UiHelper;
 | 
					import com.maddyhome.idea.vim.helper.UiHelper;
 | 
				
			||||||
@@ -63,7 +60,7 @@ import static com.maddyhome.idea.vim.group.KeyGroup.toShortcutSet;
 | 
				
			|||||||
public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
					public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			||||||
  public static ExEntryPanel instance;
 | 
					  public static ExEntryPanel instance;
 | 
				
			||||||
  public static ExEntryPanel instanceWithoutShortcuts;
 | 
					  public static ExEntryPanel instanceWithoutShortcuts;
 | 
				
			||||||
  public boolean isReplaceMode = false;
 | 
					  private boolean isReplaceMode = false;
 | 
				
			||||||
  private WeakReference<Editor> weakEditor = null;
 | 
					  private WeakReference<Editor> weakEditor = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private VimInputInterceptor myInputInterceptor = null;
 | 
					  private VimInputInterceptor myInputInterceptor = null;
 | 
				
			||||||
@@ -344,14 +341,14 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get a snapshot of the count for the in progress command, and coerce it to 1. This value will include all
 | 
					        // Get the current count from the command builder. This value is coerced to at least 1, so will always be valid.
 | 
				
			||||||
        // count components - selecting register(s), operator and motions. E.g. `2"a3"b4"c5d6/` will return 720.
 | 
					        // The aggregated value includes any counts for operator and register selections, and the uncommitted count for
 | 
				
			||||||
        // If we're showing highlights for an Ex command like `:s`, the command builder will be empty, but we'll still
 | 
					        // the search command (`/` or `?`). E.g., `2"a3"b4"c5d6/` would return 720.
 | 
				
			||||||
        // get a valid value.
 | 
					        // If we're showing highlights for an ex command like `:s`, there won't be a command, but the value is already
 | 
				
			||||||
        int count1 = Math.max(1, KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder()
 | 
					        // coerced to at least 1.
 | 
				
			||||||
          .calculateCount0Snapshot());
 | 
					        int count1 = KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder().getAggregatedUncommittedCount();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((labelText.equals("/") || labelText.equals("?") || searchCommand) && !injector.getMacro().isExecutingMacro()) {
 | 
					        if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
 | 
				
			||||||
          final boolean forwards = !labelText.equals("?");  // :s, :g, :v are treated as forwards
 | 
					          final boolean forwards = !labelText.equals("?");  // :s, :g, :v are treated as forwards
 | 
				
			||||||
          int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
 | 
					          int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
 | 
				
			||||||
          final String pattern = searchText.substring(0, pattenEnd);
 | 
					          final String pattern = searchText.substring(0, pattenEnd);
 | 
				
			||||||
@@ -405,7 +402,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public void toggleReplaceMode() {
 | 
					  public void toggleReplaceMode() {
 | 
				
			||||||
    entry.toggleInsertReplace();
 | 
					    isReplaceMode = !isReplaceMode;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@@ -531,17 +528,17 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private static final Logger logger = Logger.getInstance(ExEntryPanel.class.getName());
 | 
					  private static final Logger logger = Logger.getInstance(ExEntryPanel.class.getName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @NotNull
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public @NotNull VimCommandLineCaret getCaret() {
 | 
					  public VimCommandLineCaret getCaret() {
 | 
				
			||||||
    return (VimCommandLineCaret) entry.getCaret();
 | 
					    return (VimCommandLineCaret) entry.getCaret();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public void setText(@NotNull String string, boolean updateLastEntry) {
 | 
					  public void setText(@NotNull String string) {
 | 
				
			||||||
    // It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
 | 
					    // It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
 | 
				
			||||||
    int offset = getCaret().getOffset();
 | 
					    int offset = getCaret().getOffset();
 | 
				
			||||||
    entry.updateText(string);
 | 
					    entry.updateText(string);
 | 
				
			||||||
    if (updateLastEntry) entry.saveLastEntry();
 | 
					 | 
				
			||||||
    getCaret().setOffset(Math.min(offset, getVisibleText().length()));
 | 
					    getCaret().setOffset(Math.min(offset, getVisibleText().length()));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -550,8 +547,9 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
    entry.clearCurrentAction();
 | 
					    entry.clearCurrentAction();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Nullable
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public @Nullable Integer getPromptCharacterOffset() {
 | 
					  public Integer getPromptCharacterOffset() {
 | 
				
			||||||
    int offset = entry.currentActionPromptCharacterOffset;
 | 
					    int offset = entry.currentActionPromptCharacterOffset;
 | 
				
			||||||
    return offset == -1 ? null : offset;
 | 
					    return offset == -1 ? null : offset;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -571,7 +569,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
    IdeFocusManager.findInstance().requestFocus(entry, true);
 | 
					    IdeFocusManager.findInstance().requestFocus(entry, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public @Nullable VimInputInterceptor<?> getInputInterceptor() {
 | 
					  @Nullable
 | 
				
			||||||
 | 
					  public VimInputInterceptor<?> getInputInterceptor() {
 | 
				
			||||||
    return myInputInterceptor;
 | 
					    return myInputInterceptor;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -584,37 +583,18 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
				
			|||||||
    myInputInterceptor = vimInputInterceptor;
 | 
					    myInputInterceptor = vimInputInterceptor;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Nullable
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public @Nullable Function1<String, Unit> getInputProcessing() {
 | 
					  public Function1<String, Unit> getInputProcessing() {
 | 
				
			||||||
    return inputProcessing;
 | 
					    return inputProcessing;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Nullable
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public @Nullable Character getFinishOn() {
 | 
					  public Character getFinishOn() {
 | 
				
			||||||
    return finishOn;
 | 
					    return finishOn;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					 | 
				
			||||||
  public int getHistIndex() {
 | 
					 | 
				
			||||||
    return entry.histIndex;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Override
 | 
					 | 
				
			||||||
  public void setHistIndex(int i) {
 | 
					 | 
				
			||||||
    entry.histIndex = i;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @NotNull
 | 
					 | 
				
			||||||
  @Override
 | 
					 | 
				
			||||||
  public String getLastEntry() {
 | 
					 | 
				
			||||||
    return entry.lastEntry;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Override
 | 
					 | 
				
			||||||
  public void setLastEntry(@NotNull String s) {
 | 
					 | 
				
			||||||
    entry.lastEntry = s;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public static class LafListener implements LafManagerListener {
 | 
					  public static class LafListener implements LafManagerListener {
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void lookAndFeelChanged(@NotNull LafManager source) {
 | 
					    public void lookAndFeelChanged(@NotNull LafManager source) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,57 @@ internal object ExKeyBindings {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  val bindings: Array<KeyBinding> by lazy {
 | 
					  val bindings: Array<KeyBinding> by lazy {
 | 
				
			||||||
    arrayOf(
 | 
					    arrayOf(
 | 
				
			||||||
 | 
					      // Escape will cancel a pending insert digraph/register before cancelling
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ExEditorKit.EscapeChar),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.EscapeChar),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Cancel entry, ignoring any pending actions such as digraph/registry entry
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CancelEntry),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ExEditorKit.CompleteEntry),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(0x02.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), DefaultEditorKit.beginLineAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(0x05.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), DefaultEditorKit.endLineAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.deletePrevCharAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(0x08.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DefaultEditorKit.deleteNextCharAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevWordAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.DeleteToCursor),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ExEditorKit.HistoryUpFilter),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryUp),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ExEditorKit.HistoryUp),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryUp),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ExEditorKit.HistoryDownFilter),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryDown),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ExEditorKit.HistoryDown),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryDown),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), ExEditorKit.ToggleInsertReplace),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.previousWordAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.previousWordAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), DefaultEditorKit.forwardAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.nextWordAction),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.nextWordAction),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartDigraph),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
 | 
				
			||||||
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // These appear to be non-Vim shortcuts
 | 
					      // These appear to be non-Vim shortcuts
 | 
				
			||||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
				
			||||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
					      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,45 +59,9 @@ internal class ExShortcutKeyAction(private val exEntryPanel: ExEntryPanel) : Dum
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun registerCustomShortcutSet() {
 | 
					  fun registerCustomShortcutSet() {
 | 
				
			||||||
    val shortcuts = listOf(
 | 
					    val shortcuts = ExKeyBindings.bindings.map {
 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
 | 
					      KeyboardShortcut(it.key, null)
 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK),
 | 
					    }.toTypedArray()
 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK),
 | 
					 | 
				
			||||||
        KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
      .map { KeyboardShortcut(it, null) }
 | 
					 | 
				
			||||||
      .toTypedArray()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    registerCustomShortcutSet({ shortcuts }, exEntryPanel)
 | 
					    registerCustomShortcutSet({ shortcuts }, exEntryPanel)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user