mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-10-31 11:17:13 +01:00 
			
		
		
		
	Compare commits
	
		
			184 Commits
		
	
	
		
			edb9b194bb
			...
			customized
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9f469d0eb2 | |||
| f59d2f769c | |||
| dc00b59733 | |||
| bc20e6af9c | |||
| c40f07714a | |||
| fa68842c2d | |||
| eca9258607 | |||
| 46fb030977 | |||
|   | da3d83ecc6 | ||
|   | 4af8e574c4 | ||
|   | bdcb5c4f33 | ||
|   | 013f7a42c2 | ||
|   | d03398f3e8 | ||
|   | 7a26307a2b | ||
|   | fa6a0369b8 | ||
|   | ad8cb0ba09 | ||
|   | 8125ce5072 | ||
|   | 6c0cc7285f | ||
|   | d3424021c8 | ||
|   | 623aa40acd | ||
|   | c131cb338e | ||
|   | 14d242a233 | ||
|   | a131b7d29a | ||
|   | 85a1fbe89e | ||
|   | 142550a1f8 | ||
|   | e3d3b73903 | ||
|   | 45f18ff91c | ||
|   | 2103163207 | ||
|   | 19dd49670c | ||
|   | e738a1a821 | ||
|   | 6e0f301fb8 | ||
|   | c76b8db293 | ||
|   | 9fa4ca8fb3 | ||
|   | 871b60fe8d | ||
|   | 6715a5b61f | ||
|   | d7d91f1cc5 | ||
|   | 9f00dbd6f4 | ||
|   | f95cf3d671 | ||
|   | 7fbc17624f | ||
|   | b9c2ea37cb | ||
|   | ca0db15e01 | ||
|   | c32c62eacc | ||
|   | 43a79dbad4 | ||
|   | 2829a13187 | ||
|   | efc8c9207d | ||
|   | 183ed10592 | ||
|   | 926b47a31e | ||
|   | d272c919ea | ||
|   | f6e7d04fd5 | ||
|   | ccdff4f087 | ||
|   | ff14303e88 | ||
|   | 48a592340b | ||
|   | da8f5f3231 | ||
|   | f8fa8b73fa | ||
|   | aee126b625 | ||
|   | 396ac86939 | ||
|   | 81816f903f | ||
|   | 06a85b784b | ||
|   | 7f1e3bb155 | ||
|   | 241f554133 | ||
|   | 9498d0779c | ||
|   | b12fd5100f | ||
|   | 92f622430d | ||
|   | ef518f5b23 | ||
|   | 7acb17ebdb | ||
|   | 479a7dbbaf | ||
|   | 4fd1a25557 | ||
|   | f32d42e625 | ||
|   | 362b9a5c3a | ||
|   | e42b4d0ea3 | ||
|   | 43767b8500 | ||
|   | d05098c870 | ||
|   | 505f485568 | ||
|   | 86f512fb91 | ||
|   | 12903066b9 | ||
|   | 118d0433cb | ||
|   | eb781c3679 | ||
|   | 3c6bffba03 | ||
|   | 89623b04d6 | ||
|   | 444a96132c | ||
|   | c008553127 | ||
|   | 162d7b021f | ||
|   | c82364c1dd | ||
|   | 977402c6b0 | ||
|   | b14e59ab5b | ||
|   | 47dcefcfbf | ||
|   | 2b299cb422 | ||
|   | d0ccbb4620 | ||
|   | 187b207271 | ||
|   | a3e22c844c | ||
|   | f8384b2732 | ||
|   | 2dae43258c | ||
|   | 48033ecb85 | ||
|   | ad8df027ac | ||
|   | 91f580771d | ||
|   | 9c6f0981f5 | ||
|   | 2212569688 | ||
|   | 6711f1dbab | ||
|   | 0b7a883efb | ||
|   | 8ae84c62c0 | ||
|   | 0d168c8115 | ||
| c7b51b7fa5 | |||
|   | 86bf723791 | ||
|   | 71f2e9de4a | ||
|   | 33d3f270a3 | ||
|   | da94edd386 | ||
|   | 90dfaefd11 | ||
|   | 8bc616cc55 | ||
|   | a9e79d62c5 | ||
|   | 1998221a0b | ||
|   | a9b1625749 | ||
|   | b411836570 | ||
|   | df7e0221a8 | ||
|   | 8ff8f2b685 | ||
|   | 65dea7e3f7 | ||
|   | 1942f86633 | ||
|   | ee4ce5033a | ||
|   | 040fe806c8 | ||
|   | 97f5c9225e | ||
|   | 09b86c15f9 | ||
|   | 8f34285d8c | ||
|   | d3c3b71e3e | ||
|   | aa6f49c9b1 | ||
|   | c011628420 | ||
|   | 1c9fa9d662 | ||
|   | 7b9bc64364 | ||
|   | 729062bfdd | ||
|   | bc6c726a45 | ||
|   | dfc3df713e | ||
|   | 42eca1d5f2 | ||
|   | 66245e2730 | ||
|   | d44b82c1d1 | ||
|   | 5440e48fa3 | ||
|   | 1c513cf8aa | ||
|   | a17c4b8d43 | ||
|   | 15eb4ac278 | ||
|   | 0d9b81eab3 | ||
|   | f02e1a20c7 | ||
|   | a11991dad7 | ||
|   | 1238828bfd | ||
|   | ba409cb24c | ||
|   | d597670275 | ||
|   | d8540e95f8 | ||
|   | d35ebf00dd | ||
|   | 2b32cb26b1 | ||
|   | ca95fcb658 | ||
|   | cc18bbd168 | ||
|   | 8c8ea800cb | ||
|   | 0746dcc686 | ||
|   | 930650be9d | ||
|   | 4e3a9ffa40 | ||
|   | 3bf68a2bb8 | ||
|   | a80f6feab0 | ||
|   | 3cf8ae52ed | ||
|   | 62632a4514 | ||
|   | 249bd3778a | ||
|   | ab9e5d7a4a | ||
|   | 083b7dc952 | ||
|   | 1791692d92 | ||
|   | ba23c9ab5e | ||
|   | f96ab37bcb | ||
|   | 0da34bbb34 | ||
|   | 51e7c745ea | ||
|   | 8347251572 | ||
|   | ce8512f4e0 | ||
|   | a724a19d00 | ||
|   | 7eae7a98e8 | ||
|   | fe9566eebd | ||
|   | b69756730f | ||
|   | 6cd1a60b53 | ||
|   | 9d935e47b5 | ||
|   | a7d5372d06 | ||
|   | a575942c81 | ||
|   | 3cf6c53a8e | ||
|   | 91d86680de | ||
|   | d1d082fb99 | ||
|   | 2c634d1bf0 | ||
|   | 02a6fe4dc9 | ||
|   | 223d681526 | ||
|   | f42ef1c2fc | ||
|   | f4817b2111 | ||
|   | 6f5def0abf | ||
|   | f0fcd7f133 | ||
|   | 6115adb72e | 
							
								
								
									
										3
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ | |||||||
| name: Update Changelog On PR | name: Update Changelog On PR | ||||||
|  |  | ||||||
| on: | on: | ||||||
|  |   workflow_dispatch: | ||||||
|   pull_request: |   pull_request: | ||||||
|     types: [ closed ] |     types: [ closed ] | ||||||
|  |  | ||||||
| @@ -29,7 +30,7 @@ jobs: | |||||||
|         id: update_authors |         id: update_authors | ||||||
|         run: ./gradlew updateMergedPr -PprId=${{ github.event.number }} |         run: ./gradlew updateMergedPr -PprId=${{ github.event.number }} | ||||||
|         env: |         env: | ||||||
|           GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }} |           GITHUB_OAUTH: ${{ secrets.MERGE_PR }} | ||||||
|  |  | ||||||
|       - name: Commit changes |       - name: Commit changes | ||||||
|         uses: stefanzweifel/git-auto-commit-action@v4 |         uses: stefanzweifel/git-auto-commit-action@v4 | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								.github/workflows/mergePrTest.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								.github/workflows/mergePrTest.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | # This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created | ||||||
|  | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle | ||||||
|  |  | ||||||
|  | name: Update Changelog On PR (Test) | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   workflow_dispatch: | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |  | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v2 | ||||||
|  |         with: | ||||||
|  |           fetch-depth: 50 | ||||||
|  |       - name: Set up JDK 11 | ||||||
|  |         uses: actions/setup-java@v2 | ||||||
|  |         with: | ||||||
|  |           java-version: '11' | ||||||
|  |           distribution: 'adopt' | ||||||
|  |           server-id: github # Value of the distributionManagement/repository/id field of the pom.xml | ||||||
|  |           settings-path: ${{ github.workspace }} # location for the settings.xml file | ||||||
|  |  | ||||||
|  |       - name: Update authors | ||||||
|  |         id: update_authors | ||||||
|  |         run: ./gradlew updateMergedPr -PprId=525 | ||||||
|  |         env: | ||||||
|  |           GITHUB_OAUTH: ${{ secrets.MERGE_PR }} | ||||||
|  |  | ||||||
|  | #      - name: Commit changes | ||||||
|  | #        uses: stefanzweifel/git-auto-commit-action@v4 | ||||||
|  | #        with: | ||||||
|  | #          branch: master | ||||||
|  | #          commit_message: Update changelog  after merging PR | ||||||
|  | #          commit_user_name: Alex Plate | ||||||
|  | #          commit_user_email: aleksei.plate@jetbrains.com | ||||||
|  | #          commit_author: Alex Plate <aleksei.plate@jetbrains.com> | ||||||
|  | #          file_pattern: CHANGES.md | ||||||
							
								
								
									
										2
									
								
								.github/workflows/updateAuthors.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/updateAuthors.yml
									
									
									
									
										vendored
									
									
								
							| @@ -37,7 +37,7 @@ jobs: | |||||||
|         run: ./gradlew updateAuthors --stacktrace |         run: ./gradlew updateAuthors --stacktrace | ||||||
|         env: |         env: | ||||||
|           SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }} |           SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }} | ||||||
|           GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }} |           GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |  | ||||||
|       - name: Commit changes |       - name: Commit changes | ||||||
|         uses: stefanzweifel/git-auto-commit-action@v4 |         uses: stefanzweifel/git-auto-commit-action@v4 | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							| @@ -5,19 +5,16 @@ object Constants { | |||||||
|   const val EAP_CHANNEL = "eap" |   const val EAP_CHANNEL = "eap" | ||||||
|   const val DEV_CHANNEL = "Dev" |   const val DEV_CHANNEL = "Dev" | ||||||
|  |  | ||||||
|   const val VERSION = "1.10.3" |   const val VERSION = "1.11.1" | ||||||
|   const val DEV_VERSION = "1.11.0" |   const val DEV_VERSION = "1.12.0" | ||||||
|  |  | ||||||
|   const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT" |   const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT" | ||||||
|   const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT" |   const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT" | ||||||
|   const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT" |   const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT" | ||||||
|   const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT" |   const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT" | ||||||
|   const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT" |   const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT" | ||||||
|   const val RELEASE = "2022.1.3" |   const val RELEASE = "LATEST-EAP-SNAPSHOT" | ||||||
|  |  | ||||||
|  |   const val RELEASE_DEV = "LATEST-EAP-SNAPSHOT" | ||||||
|   // Use LATEST-EAP-SNAPSHOT only when we'll update the minimum version of IJ to 222+ |   const val RELEASE_EAP = "LATEST-EAP-SNAPSHOT" | ||||||
|   // Because of some API inconcistincies, IdeaVim built on 2022+ won't run on older versions of IJ |  | ||||||
|   const val RELEASE_DEV = "2022.1.3" |  | ||||||
|   const val RELEASE_EAP = "2022.1.3" |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,13 @@ | |||||||
| package _Self | package _Self | ||||||
|  |  | ||||||
| import _Self.buildTypes.* | import _Self.buildTypes.Compatibility | ||||||
|  | import _Self.buildTypes.LongRunning | ||||||
|  | import _Self.buildTypes.Nvim | ||||||
|  | import _Self.buildTypes.PluginVerifier | ||||||
|  | import _Self.buildTypes.PropertyBased | ||||||
|  | import _Self.buildTypes.Qodana | ||||||
|  | import _Self.buildTypes.TestsForIntelliJ20222 | ||||||
|  | import _Self.buildTypes.TestsForIntelliJEAP | ||||||
| import _Self.subprojects.GitHub | import _Self.subprojects.GitHub | ||||||
| import _Self.subprojects.OldTests | import _Self.subprojects.OldTests | ||||||
| import _Self.subprojects.Releases | import _Self.subprojects.Releases | ||||||
| @@ -10,6 +17,7 @@ import _Self.vcsRoots.Branch_191_193 | |||||||
| import _Self.vcsRoots.Branch_201 | import _Self.vcsRoots.Branch_201 | ||||||
| import _Self.vcsRoots.Branch_202 | import _Self.vcsRoots.Branch_202 | ||||||
| import _Self.vcsRoots.Branch_203_212 | import _Self.vcsRoots.Branch_203_212 | ||||||
|  | import _Self.vcsRoots.Branch_213_221 | ||||||
| import _Self.vcsRoots.Branch_Release | import _Self.vcsRoots.Branch_Release | ||||||
| import _Self.vcsRoots.GitHubPullRequest | import _Self.vcsRoots.GitHubPullRequest | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.Project | import jetbrains.buildServer.configs.kotlin.v2019_2.Project | ||||||
| @@ -26,18 +34,20 @@ object Project : Project({ | |||||||
|   vcsRoot(Branch_201) |   vcsRoot(Branch_201) | ||||||
|   vcsRoot(Branch_202) |   vcsRoot(Branch_202) | ||||||
|   vcsRoot(Branch_203_212) |   vcsRoot(Branch_203_212) | ||||||
|  |   vcsRoot(Branch_213_221) | ||||||
|   vcsRoot(Branch_Release) |   vcsRoot(Branch_Release) | ||||||
|   vcsRoot(GitHubPullRequest) |   vcsRoot(GitHubPullRequest) | ||||||
|  |  | ||||||
|   // Builds |   // Builds | ||||||
|   buildType(TestsForIntelliJ20213) |  | ||||||
|   buildType(TestsForIntelliJEAP) |   buildType(TestsForIntelliJEAP) | ||||||
|  |   buildType(TestsForIntelliJ20222) | ||||||
|  |  | ||||||
|   buildType(PropertyBased) |   buildType(PropertyBased) | ||||||
|   buildType(LongRunning) |   buildType(LongRunning) | ||||||
|  |  | ||||||
|   buildType(Nvim) |   buildType(Nvim) | ||||||
|   buildType(PluginVerifier) |   buildType(PluginVerifier) | ||||||
|  |   buildType(Compatibility) | ||||||
|  |  | ||||||
|   buildType(Qodana) |   buildType(Qodana) | ||||||
|  |  | ||||||
| @@ -47,7 +57,7 @@ object Project : Project({ | |||||||
|       type = "CloudImage" |       type = "CloudImage" | ||||||
|       id = "PROJECT_EXT_768" |       id = "PROJECT_EXT_768" | ||||||
|       param("agent_pool_id", "41") |       param("agent_pool_id", "41") | ||||||
|       param("amazon-id", "ami-0d1a6a32faa92923e") |       param("amazon-id", "ami-0fa17ce8238eb8868") | ||||||
|       param("ebs-optimized", "false") |       param("ebs-optimized", "false") | ||||||
|       param("image-instances-limit", "") |       param("image-instances-limit", "") | ||||||
|       param("image-name-prefix", "BuildAgentsIdeaVim") |       param("image-name-prefix", "BuildAgentsIdeaVim") | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.teamcity/_Self/buildTypes/ActiveTests.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.teamcity/_Self/buildTypes/ActiveTests.kt
									
									
									
									
										vendored
									
									
								
							| @@ -55,4 +55,4 @@ sealed class ActiveTests(buildName: String, ijVersion: String) : BuildType({ | |||||||
| }) | }) | ||||||
|  |  | ||||||
| object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT") | object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT") | ||||||
| object TestsForIntelliJ20213 : ActiveTests("Tests for IntelliJ 2021.3", "2021.3.2") | object TestsForIntelliJ20222 : ActiveTests("Tests for IntelliJ 2022.2", "2022.2.1") | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								.teamcity/_Self/buildTypes/Compatibility.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								.teamcity/_Self/buildTypes/Compatibility.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | package _Self.buildTypes | ||||||
|  |  | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule | ||||||
|  |  | ||||||
|  | object Compatibility : BuildType({ | ||||||
|  |   id("IdeaVimCompatibility") | ||||||
|  |   name = "IdeaVim compatibility with external plugins" | ||||||
|  |  | ||||||
|  |   vcs { | ||||||
|  |     root(DslContext.settingsRoot) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   steps { | ||||||
|  |     script { | ||||||
|  |       name = "Check" | ||||||
|  |       scriptContent = """ | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}io.github.mishkun.ideavimsneak' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city | ||||||
|  |                 # Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city | ||||||
|  |                 java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city | ||||||
|  |             """.trimIndent() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   triggers { | ||||||
|  |     schedule { | ||||||
|  |       schedulingPolicy = daily { | ||||||
|  |         hour = 4 | ||||||
|  |       } | ||||||
|  |       branchFilter = "" | ||||||
|  |       triggerBuild = always() | ||||||
|  |       withPendingChangesOnly = false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   features { | ||||||
|  |     golang { | ||||||
|  |       testFormat = "json" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
							
								
								
									
										2
									
								
								.teamcity/_Self/buildTypes/Nvim.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.teamcity/_Self/buildTypes/Nvim.kt
									
									
									
									
										vendored
									
									
								
							| @@ -31,7 +31,7 @@ object Nvim : BuildType({ | |||||||
|     script { |     script { | ||||||
|       name = "Set up NeoVim" |       name = "Set up NeoVim" | ||||||
|       scriptContent = """ |       scriptContent = """ | ||||||
|               wget https://github.com/neovim/neovim/releases/download/v0.4.4/nvim-linux64.tar.gz |               wget https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz | ||||||
|               tar xzf nvim-linux64.tar.gz |               tar xzf nvim-linux64.tar.gz | ||||||
|               cd nvim-linux64/bin |               cd nvim-linux64/bin | ||||||
|               chmod +x nvim |               chmod +x nvim | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.teamcity/_Self/buildTypes/Qodana.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.teamcity/_Self/buildTypes/Qodana.kt
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ import _Self.Constants.QODANA_TESTS | |||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType | import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode | import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext | import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric | import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange | import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange | ||||||
| @@ -46,12 +47,15 @@ object Qodana : BuildType({ | |||||||
|       param("clonefinder-enable", "true") |       param("clonefinder-enable", "true") | ||||||
|       param("clonefinder-reference-projects", "src") |       param("clonefinder-reference-projects", "src") | ||||||
|       param("yaml-configuration", "") |       param("yaml-configuration", "") | ||||||
|  |       linter = jvm { | ||||||
|  |         version = Qodana.JVMVersion.LATEST | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   triggers { |   triggers { | ||||||
|     vcs { |     vcs { | ||||||
|       enabled = false |       enabled = true | ||||||
|       branchFilter = "" |       branchFilter = "" | ||||||
|     } |     } | ||||||
|     schedule { |     schedule { | ||||||
|   | |||||||
							
								
								
									
										62
									
								
								.teamcity/_Self/buildTypes/TestsForIntelliJ_213-221.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								.teamcity/_Self/buildTypes/TestsForIntelliJ_213-221.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | @file:Suppress("ClassName") | ||||||
|  |  | ||||||
|  | package _Self.buildTypes | ||||||
|  |  | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs | ||||||
|  |  | ||||||
|  | sealed class TestsForIntelliJ_213_221_branch(private val version: String) : BuildType({ | ||||||
|  |   name = "Tests for IntelliJ $version" | ||||||
|  |  | ||||||
|  |   params { | ||||||
|  |     param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") | ||||||
|  |     param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true") | ||||||
|  |     param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-$version") | ||||||
|  |     param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") | ||||||
|  |     param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   vcs { | ||||||
|  |     root(_Self.vcsRoots.Branch_213_221) | ||||||
|  |  | ||||||
|  |     checkoutMode = CheckoutMode.AUTO | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   steps { | ||||||
|  |     gradle { | ||||||
|  |       tasks = "clean test" | ||||||
|  |       buildFile = "" | ||||||
|  |       enableStacktrace = true | ||||||
|  |       param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   triggers { | ||||||
|  |     vcs { | ||||||
|  |       branchFilter = "" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   requirements { | ||||||
|  |     noLessThanVer("teamcity.agent.jvm.version", "1.8") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   failureConditions { | ||||||
|  |     failOnMetricChange { | ||||||
|  |       metric = BuildFailureOnMetric.MetricType.TEST_COUNT | ||||||
|  |       threshold = 20 | ||||||
|  |       units = BuildFailureOnMetric.MetricUnit.PERCENTS | ||||||
|  |       comparison = BuildFailureOnMetric.MetricComparison.LESS | ||||||
|  |       compareTo = build { | ||||||
|  |         buildRule = lastSuccessful() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | object TestsForIntelliJ20213 : TestsForIntelliJ_213_221_branch("2021.3.2") | ||||||
							
								
								
									
										2
									
								
								.teamcity/_Self/subprojects/OldTests.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.teamcity/_Self/subprojects/OldTests.kt
									
									
									
									
										vendored
									
									
								
							| @@ -11,6 +11,7 @@ import _Self.buildTypes.TestsForIntelliJ20202 | |||||||
| import _Self.buildTypes.TestsForIntelliJ20203 | import _Self.buildTypes.TestsForIntelliJ20203 | ||||||
| import _Self.buildTypes.TestsForIntelliJ20211 | import _Self.buildTypes.TestsForIntelliJ20211 | ||||||
| import _Self.buildTypes.TestsForIntelliJ20212 | import _Self.buildTypes.TestsForIntelliJ20212 | ||||||
|  | import _Self.buildTypes.TestsForIntelliJ20213 | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.Project | import jetbrains.buildServer.configs.kotlin.v2019_2.Project | ||||||
|  |  | ||||||
| object OldTests : Project({ | object OldTests : Project({ | ||||||
| @@ -28,4 +29,5 @@ object OldTests : Project({ | |||||||
|   buildType(TestsForIntelliJ20203) |   buildType(TestsForIntelliJ20203) | ||||||
|   buildType(TestsForIntelliJ20211) |   buildType(TestsForIntelliJ20211) | ||||||
|   buildType(TestsForIntelliJ20212) |   buildType(TestsForIntelliJ20212) | ||||||
|  |   buildType(TestsForIntelliJ20213) | ||||||
| }) | }) | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								.teamcity/_Self/vcsRoots/Branch_213_221.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.teamcity/_Self/vcsRoots/Branch_213_221.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | @file:Suppress("ClassName") | ||||||
|  |  | ||||||
|  | package _Self.vcsRoots | ||||||
|  |  | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot | ||||||
|  |  | ||||||
|  | object Branch_213_221 : GitVcsRoot({ | ||||||
|  |   id("HttpsGithubComJetBrainsIdeavimBranch213221") | ||||||
|  |   name = "https://github.com/JetBrains/ideavim (branch 213-221)" | ||||||
|  |   url = "https://github.com/JetBrains/ideavim.git" | ||||||
|  |   branch = "213-221" | ||||||
|  | }) | ||||||
							
								
								
									
										40
									
								
								.teamcity/patches/buildTypes/Build.kts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								.teamcity/patches/buildTypes/Build.kts
									
									
									
									
										vendored
									
									
								
							| @@ -1,40 +0,0 @@ | |||||||
| package patches.buildTypes |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, create a buildType with id = 'Build' |  | ||||||
| in the root project, and delete the patch script. |  | ||||||
| */ |  | ||||||
| create(DslContext.projectId, BuildType({ |  | ||||||
|     id("Build") |  | ||||||
|     name = "IdeaVim compatibility with external plugins" |  | ||||||
|  |  | ||||||
|     vcs { |  | ||||||
|         root(RelativeId("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster")) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     steps { |  | ||||||
|         script { |  | ||||||
|             scriptContent = "go run test.go" |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     triggers { |  | ||||||
|         vcs { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     features { |  | ||||||
|         golang { |  | ||||||
|             testFormat = "json" |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| })) |  | ||||||
|  |  | ||||||
							
								
								
									
										25
									
								
								.teamcity/patches/buildTypes/Nvim.kts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								.teamcity/patches/buildTypes/Nvim.kts
									
									
									
									
										vendored
									
									
								
							| @@ -1,25 +0,0 @@ | |||||||
| package patches.buildTypes |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, change the buildType with id = 'Nvim' |  | ||||||
| accordingly, and delete the patch script. |  | ||||||
| */ |  | ||||||
| changeBuildType(RelativeId("Nvim")) { |  | ||||||
|     triggers { |  | ||||||
|         val trigger1 = find<VcsTrigger> { |  | ||||||
|             vcs { |  | ||||||
|                 branchFilter = "" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         trigger1.apply { |  | ||||||
|             enabled = false |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										25
									
								
								.teamcity/patches/buildTypes/PluginVerifier.kts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								.teamcity/patches/buildTypes/PluginVerifier.kts
									
									
									
									
										vendored
									
									
								
							| @@ -1,25 +0,0 @@ | |||||||
| package patches.buildTypes |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, change the buildType with id = 'PluginVerifier' |  | ||||||
| accordingly, and delete the patch script. |  | ||||||
| */ |  | ||||||
| changeBuildType(RelativeId("PluginVerifier")) { |  | ||||||
|     triggers { |  | ||||||
|         val trigger1 = find<VcsTrigger> { |  | ||||||
|             vcs { |  | ||||||
|                 branchFilter = "" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         trigger1.apply { |  | ||||||
|             enabled = false |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										44
									
								
								.teamcity/patches/buildTypes/Qodana.kts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								.teamcity/patches/buildTypes/Qodana.kts
									
									
									
									
										vendored
									
									
								
							| @@ -2,9 +2,8 @@ package patches.buildTypes | |||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* | import jetbrains.buildServer.configs.kotlin.v2019_2.* | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.ScheduleTrigger |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* | import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -16,6 +15,9 @@ changeBuildType(RelativeId("Qodana")) { | |||||||
|     expectSteps { |     expectSteps { | ||||||
|         qodana { |         qodana { | ||||||
|             name = "Qodana" |             name = "Qodana" | ||||||
|  |             linter = jvm { | ||||||
|  |                 version = Qodana.JVMVersion.LATEST | ||||||
|  |             } | ||||||
|             param("clonefinder-enable", "true") |             param("clonefinder-enable", "true") | ||||||
|             param("clonefinder-languages", "Java") |             param("clonefinder-languages", "Java") | ||||||
|             param("clonefinder-languages-container", "Java Kotlin") |             param("clonefinder-languages-container", "Java Kotlin") | ||||||
| @@ -29,27 +31,25 @@ changeBuildType(RelativeId("Qodana")) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     steps { |     steps { | ||||||
|         update<Qodana>(0) { |         insert(0) { | ||||||
|  |             gradle { | ||||||
|  |                 name = "Generate grammar" | ||||||
|  |                 tasks = "generateGrammarSource" | ||||||
|  |                 param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         update<Qodana>(1) { | ||||||
|             clearConditions() |             clearConditions() | ||||||
|             linter = jvm { |             reportAsTests = true | ||||||
|                 version = Qodana.JVMVersion.LATEST |             argumentsCommandDocker = "-e QODANA_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmdhbml6YXRpb24iOiIzUFZrQSIsInByb2plY3QiOiIzN1FlQSIsInRva2VuIjoiM0t2bXoifQ.uohp81tM7iAfvvB6k8faarfpV-OjusAaEbWQ8iNrOgs" | ||||||
|             } |             argumentsEntryPointDocker = "--baseline qodana.sarif.json" | ||||||
|         } |             param("clonefinder-languages", "") | ||||||
|     } |             param("collect-anonymous-statistics", "") | ||||||
|  |             param("licenseaudit-enable", "") | ||||||
|     triggers { |             param("clonefinder-languages-container", "") | ||||||
|         val trigger1 = find<ScheduleTrigger> { |             param("clonefinder-queried-project", "") | ||||||
|             schedule { |             param("clonefinder-enable", "") | ||||||
|                 schedulingPolicy = weekly { |             param("clonefinder-reference-projects", "") | ||||||
|                     dayOfWeek = ScheduleTrigger.DAY.Tuesday |  | ||||||
|                 } |  | ||||||
|                 branchFilter = "" |  | ||||||
|                 triggerBuild = always() |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         trigger1.apply { |  | ||||||
|             enabled = false |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								.teamcity/patches/buildTypes/ReleaseEap.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								.teamcity/patches/buildTypes/ReleaseEap.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | package patches.buildTypes | ||||||
|  |  | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.* | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.VcsLabeling | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.vcsLabeling | ||||||
|  | import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | This patch script was generated by TeamCity on settings change in UI. | ||||||
|  | To apply the patch, change the buildType with id = 'ReleaseEap' | ||||||
|  | accordingly, and delete the patch script. | ||||||
|  | */ | ||||||
|  | changeBuildType(RelativeId("ReleaseEap")) { | ||||||
|  |     features { | ||||||
|  |         val feature1 = find<VcsLabeling> { | ||||||
|  |             vcsLabeling { | ||||||
|  |                 vcsRootId = "${DslContext.settingsRoot.id}" | ||||||
|  |                 labelingPattern = "%system.build.number%" | ||||||
|  |                 successfulOnly = true | ||||||
|  |                 branchFilter = "" | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         feature1.apply { | ||||||
|  |             successfulOnly = false | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								.teamcity/patches/projects/_Self.kts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								.teamcity/patches/projects/_Self.kts
									
									
									
									
										vendored
									
									
								
							| @@ -1,74 +0,0 @@ | |||||||
| package patches.projects |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.AmazonEC2CloudImage |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.AmazonEC2CloudProfile |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.Project |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.amazonEC2CloudImage |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.amazonEC2CloudProfile |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, change the root project |  | ||||||
| accordingly, and delete the patch script. |  | ||||||
| */ |  | ||||||
| changeProject(DslContext.projectId) { |  | ||||||
|     features { |  | ||||||
|         val feature1 = find<AmazonEC2CloudImage> { |  | ||||||
|             amazonEC2CloudImage { |  | ||||||
|                 id = "PROJECT_EXT_768" |  | ||||||
|                 profileId = "amazon-48" |  | ||||||
|                 agentPoolId = "41" |  | ||||||
|                 name = "BuildAgentsIdeaVim" |  | ||||||
|                 vpcSubnetId = "subnet-58839511" |  | ||||||
|                 keyPairName = "" |  | ||||||
|                 instanceType = "c5d.xlarge" |  | ||||||
|                 securityGroups = listOf("sg-eda08696", "sg-7332cf0f") |  | ||||||
|                 useSpotInstances = true |  | ||||||
|                 instanceTags = mapOf( |  | ||||||
|                     "project" to "idea-vim" |  | ||||||
|                 ) |  | ||||||
|                 source = Source("ami-0d1a6a32faa92923e") |  | ||||||
|                 param("image-instances-limit", "") |  | ||||||
|                 param("spot-instance-price", "") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         feature1.apply { |  | ||||||
|             profileId = "amazon-48" |  | ||||||
|             agentPoolId = "41" |  | ||||||
|             name = "BuildAgentsIdeaVim" |  | ||||||
|             vpcSubnetId = "subnet-58839511" |  | ||||||
|             keyPairName = "" |  | ||||||
|             instanceType = "c5d.xlarge" |  | ||||||
|             securityGroups = listOf("sg-eda08696", "sg-7332cf0f") |  | ||||||
|             useSpotInstances = true |  | ||||||
|             instanceTags = mapOf( |  | ||||||
|                 "project" to "idea-vim" |  | ||||||
|             ) |  | ||||||
|             source = Source("ami-0fa17ce8238eb8868") |  | ||||||
|         } |  | ||||||
|         val feature2 = find<AmazonEC2CloudProfile> { |  | ||||||
|             amazonEC2CloudProfile { |  | ||||||
|                 id = "amazon-48" |  | ||||||
|                 name = "Cloud Agents - Single Build" |  | ||||||
|                 terminateAfterBuild = true |  | ||||||
|                 terminateIdleMinutes = 15 |  | ||||||
|                 region = AmazonEC2CloudProfile.Regions.EU_WEST_DUBLIN |  | ||||||
|                 maxInstancesCount = 10 |  | ||||||
|                 authType = accessKey { |  | ||||||
|                     keyId = "credentialsJSON:dbcdb2a2-de5f-4bc9-9421-292b19e83947" |  | ||||||
|                     secretKey = "credentialsJSON:65a87fe7-0977-4af9-96f1-344f2b82d269" |  | ||||||
|                 } |  | ||||||
|                 param("agentPushPreset", "") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         feature2.apply { |  | ||||||
|             name = "Cloud Agents - Single Build" |  | ||||||
|             terminateAfterBuild = true |  | ||||||
|             terminateIdleMinutes = 15 |  | ||||||
|             region = AmazonEC2CloudProfile.Regions.EU_WEST_DUBLIN |  | ||||||
|             maxInstancesCount = 10 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| package patches.vcsRoots |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, create a vcsRoot with id = 'HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster' |  | ||||||
| in the root project, and delete the patch script. |  | ||||||
| */ |  | ||||||
| create(DslContext.projectId, GitVcsRoot({ |  | ||||||
|     id("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster") |  | ||||||
|     name = "https://github.com/AlexPl292/IdeaVimCompatibility#refs/heads/master" |  | ||||||
|     url = "https://github.com/AlexPl292/IdeaVimCompatibility" |  | ||||||
|     branch = "refs/heads/master" |  | ||||||
|     branchSpec = "refs/heads/*" |  | ||||||
|     authMethod = password { |  | ||||||
|         userName = "AlexPl292" |  | ||||||
|         password = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f" |  | ||||||
|     } |  | ||||||
|     param("oauthProviderId", "PROJECT_EXT_1") |  | ||||||
|     param("useAlternates", "true") |  | ||||||
| })) |  | ||||||
|  |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| package patches.vcsRoots |  | ||||||
|  |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* |  | ||||||
| import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| This patch script was generated by TeamCity on settings change in UI. |  | ||||||
| To apply the patch, create a vcsRoot with id = 'IdeaVimCompatibility' |  | ||||||
| in the root project, and delete the patch script. |  | ||||||
| */ |  | ||||||
| create(DslContext.projectId, GitVcsRoot({ |  | ||||||
|     id("IdeaVimCompatibility") |  | ||||||
|     name = "IdeaVimCompatibility" |  | ||||||
|     url = "git@github.com:AlexPl292/IdeaVimCompatibility.git" |  | ||||||
|     branch = "refs/heads/master" |  | ||||||
|     authMethod = uploadedKey { |  | ||||||
|         userName = "git" |  | ||||||
|         uploadedKey = "Alex Plate TeamCity key" |  | ||||||
|     } |  | ||||||
|     param("useAlternates", "true") |  | ||||||
| })) |  | ||||||
|  |  | ||||||
							
								
								
									
										73
									
								
								AUTHORS.md
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								AUTHORS.md
									
									
									
									
									
								
							| @@ -32,16 +32,48 @@ Contributors: | |||||||
|   [![icon][github]](https://github.com/yole) |   [![icon][github]](https://github.com/yole) | ||||||
|     |     | ||||||
|   Dmitry Jemerov |   Dmitry Jemerov | ||||||
|  | * [![icon][mail]](mailto:tony.kay@gmail.com) | ||||||
|  |   [![icon][github]](https://github.com/awkay) | ||||||
|  |     | ||||||
|  |   Tony Kay | ||||||
|  | * [![icon][mail]](mailto:jamescmartinez@gmail.com) | ||||||
|  |   [![icon][github]](https://github.com/jamescmartinez) | ||||||
|  |     | ||||||
|  |   James Martinez | ||||||
|  | * [![icon][mail]](mailto:almas337519@gmail.com) | ||||||
|  |   [![icon][github]](https://github.com/strogiyotec) | ||||||
|  |     | ||||||
|  |   strogiyotec | ||||||
|  | * [![icon][mail]](mailto:raimon49@hotmail.com) | ||||||
|  |   [![icon][github]](https://github.com/raimon49) | ||||||
|  |     | ||||||
|  |   raimon | ||||||
|  | * [![icon][mail]](mailto:agrsbm@gmail.com) | ||||||
|  |   [![icon][github-off]](#) | ||||||
|  |     | ||||||
|  |   Alexander Griesbaum | ||||||
|  | * [![icon][mail]](mailto:manwe64@gmail.com) | ||||||
|  |   [![icon][github]](https://github.com/baldrs) | ||||||
|  |     | ||||||
|  |   Baldrs | ||||||
|  | * [![icon][mail]](mailto:yury@shurup.com) | ||||||
|  |   [![icon][github]](https://github.com/zyv) | ||||||
|  |     | ||||||
|  |   Yury V. Zaytsev | ||||||
|  | * [![icon][mail]](mailto:jflorian@doubledog.org) | ||||||
|  |   [![icon][github]](https://github.com/jflorian) | ||||||
|  |     | ||||||
|  |   John Florian | ||||||
| * [![icon][mail]](mailto:marquis@marquiswang.com) | * [![icon][mail]](mailto:marquis@marquiswang.com) | ||||||
|   [![icon][github]](https://github.com/marquiswang) |   [![icon][github]](https://github.com/marquiswang) | ||||||
|     |     | ||||||
|   Marquis Wang |   Marquis Wang | ||||||
| * [![icon][mail]](mailto:madgnome@gmail.com) | * [![icon][mail]](mailto:madgnome@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/madgnome) | ||||||
|     |     | ||||||
|   Julien Hoarau   |   Julien Hoarau   | ||||||
| * [![icon][mail]](mailto:masanobu.imai@gmail.com) | * [![icon][mail]](mailto:masanobu.imai@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/masanobuimai) | ||||||
|     |     | ||||||
|   Masanobu Imai |   Masanobu Imai | ||||||
| * [![icon][mail]](mailto:poxvuibr@gmail.com) | * [![icon][mail]](mailto:poxvuibr@gmail.com) | ||||||
| @@ -57,7 +89,7 @@ Contributors: | |||||||
|     |     | ||||||
|   John Lindquist |   John Lindquist | ||||||
| * [![icon][mail]](mailto:iklotzko@ltech.com) | * [![icon][mail]](mailto:iklotzko@ltech.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/iklotzko) | ||||||
|     |     | ||||||
|   Ira Klotzko |   Ira Klotzko | ||||||
| * [![icon][mail]](mailto:alex@selesse.com) | * [![icon][mail]](mailto:alex@selesse.com) | ||||||
| @@ -65,7 +97,7 @@ Contributors: | |||||||
|     |     | ||||||
|   Alex Selesse |   Alex Selesse | ||||||
| * [![icon][mail]](mailto:dbennett@palantir.com) | * [![icon][mail]](mailto:dbennett@palantir.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/dathanb) | ||||||
|     |     | ||||||
|   Dathan Bennett |   Dathan Bennett | ||||||
| * [![icon][mail]](mailto:kphayen@gmail.com) | * [![icon][mail]](mailto:kphayen@gmail.com) | ||||||
| @@ -77,11 +109,11 @@ Contributors: | |||||||
|     |     | ||||||
|   Alexey Shmalko |   Alexey Shmalko | ||||||
| * [![icon][mail]](mailto:a.m.brookins@gmail.com) | * [![icon][mail]](mailto:a.m.brookins@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/abrookins) | ||||||
|     |     | ||||||
|   Andrew Brookins |   Andrew Brookins | ||||||
| * [![icon][mail]](mailto:changwang83@gmail.com) | * [![icon][mail]](mailto:changwang83@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/changwang) | ||||||
|     |     | ||||||
|   Chang Wang |   Chang Wang | ||||||
| * [![icon][mail]](mailto:josejaime.sanchez@gmail.com) | * [![icon][mail]](mailto:josejaime.sanchez@gmail.com) | ||||||
| @@ -89,19 +121,19 @@ Contributors: | |||||||
|     |     | ||||||
|   Jaime Sanchez |   Jaime Sanchez | ||||||
| * [![icon][mail]](mailto:thomas@homburg.dk) | * [![icon][mail]](mailto:thomas@homburg.dk) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/homburg) | ||||||
|     |     | ||||||
|   Thomas B Homburg |   Thomas B Homburg | ||||||
| * [![icon][mail]](mailto:smartbomb@server.fake) | * [![icon][mail]](mailto:smartbomb@server.fake) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/smartbomb) | ||||||
|     |     | ||||||
|   smartbomb |   smartbomb | ||||||
| * [![icon][mail]](mailto:tuomas.tynkkynen@iki.fi) | * [![icon][mail]](mailto:tuomas.tynkkynen@iki.fi) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/dezgeg) | ||||||
|     |     | ||||||
|   Tuomas Tynkkynen |   Tuomas Tynkkynen | ||||||
| * [![icon][mail]](mailto:jackson@donorschoose.org) | * [![icon][mail]](mailto:jackson@donorschoose.org) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/jdpopkin) | ||||||
|     |     | ||||||
|   Jackson Popkin |   Jackson Popkin | ||||||
| * [![icon][mail]](mailto:yuyuyu1999@gmail.com) | * [![icon][mail]](mailto:yuyuyu1999@gmail.com) | ||||||
| @@ -109,7 +141,7 @@ Contributors: | |||||||
|     |     | ||||||
|   Teruo Kunihiro |   Teruo Kunihiro | ||||||
| * [![icon][mail]](mailto:lubashka.994@mail.ru) | * [![icon][mail]](mailto:lubashka.994@mail.ru) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/lubba) | ||||||
|     |     | ||||||
|   Liubov Paina |   Liubov Paina | ||||||
| * [![icon][mail]](mailto:me@dhleong.net) | * [![icon][mail]](mailto:me@dhleong.net) | ||||||
| @@ -137,7 +169,7 @@ Contributors: | |||||||
|     |     | ||||||
|   tieTYT |   tieTYT | ||||||
| * [![icon][mail]](mailto:nickgieschen@gmail.com) | * [![icon][mail]](mailto:nickgieschen@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/nickgieschen) | ||||||
|     |     | ||||||
|   Nick Gieschen |   Nick Gieschen | ||||||
| * [![icon][mail]](mailto:ikenox@gmail.com) | * [![icon][mail]](mailto:ikenox@gmail.com) | ||||||
| @@ -149,7 +181,7 @@ Contributors: | |||||||
|     |     | ||||||
|   Maximilian Luz |   Maximilian Luz | ||||||
| * [![icon][mail]](mailto:vparfinenko@excelsior-usa.com) | * [![icon][mail]](mailto:vparfinenko@excelsior-usa.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/cypok) | ||||||
|     |     | ||||||
|   Vladimir Parfinenko |   Vladimir Parfinenko | ||||||
| * [![icon][mail]](mailto:hassmann@hwdev.de) | * [![icon][mail]](mailto:hassmann@hwdev.de) | ||||||
| @@ -193,7 +225,7 @@ Contributors: | |||||||
|     |     | ||||||
|   Marcel Hild |   Marcel Hild | ||||||
| * [![icon][mail]](mailto:vedranb@gmail.com) | * [![icon][mail]](mailto:vedranb@gmail.com) | ||||||
|   [![icon][github-off]](#) |   [![icon][github]](https://github.com/vedran) | ||||||
|     |     | ||||||
|   Vedran Budimcic |   Vedran Budimcic | ||||||
| * [![icon][mail]](mailto:andreigasparovici1@gmail.com) | * [![icon][mail]](mailto:andreigasparovici1@gmail.com) | ||||||
| @@ -208,10 +240,13 @@ Contributors: | |||||||
|   [![icon][github]](https://github.com/TonyArra) |   [![icon][github]](https://github.com/TonyArra) | ||||||
|     |     | ||||||
|   Tony Arra |   Tony Arra | ||||||
| * [![icon][mail]](mailto:bradziolko@gmail.com) | * [![icon][mail]](mailto:mj@ziolko.dev) | ||||||
|   [![icon][github]](https://github.com/bradziolko) |   [![icon][github]](https://github.com/mjziolko) | ||||||
|     |     | ||||||
|   Brad Ziolko |   Madeline Ziolko | ||||||
|  |   [Original contribution from: | ||||||
|  |   [![icon][mail]](mailto:bradziolko@gmail.com) | ||||||
|  |   [![icon][github]](https://github.com/bradziolko)] | ||||||
| * [![icon][mail]](mailto:sumoooru2@gmail.com) | * [![icon][mail]](mailto:sumoooru2@gmail.com) | ||||||
|   [![icon][github]](https://github.com/sumoooru2) |   [![icon][github]](https://github.com/sumoooru2) | ||||||
|     |     | ||||||
| @@ -416,6 +451,10 @@ Contributors: | |||||||
|   [![icon][github]](https://github.com/Vvalter) |   [![icon][github]](https://github.com/Vvalter) | ||||||
|     |     | ||||||
|   Simon Rainer |   Simon Rainer | ||||||
|  | * [![icon][mail]](mailto:filipp.vakhitov@jetbrains.com) | ||||||
|  |   [![icon][github]](https://github.com/lippfi) | ||||||
|  |     | ||||||
|  |   lippfi | ||||||
|                          |                          | ||||||
| If you are a contributor and your name is not listed here, feel free to | If you are a contributor and your name is not listed here, feel free to | ||||||
| contact the maintainers. | contact the maintainers. | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								CHANGES.md
									
									
									
									
									
								
							| @@ -25,6 +25,17 @@ usual beta standards. | |||||||
|  |  | ||||||
| ## To Be Released | ## To Be Released | ||||||
|  |  | ||||||
|  | ### Fixes: | ||||||
|  | * [VIM-1758](https://youtrack.jetbrains.com/issue/VIM-1758) Commentary plugin in rider | ||||||
|  | * [VIM-1903](https://youtrack.jetbrains.com/issue/VIM-1903) Autoindent now works in rider | ||||||
|  | * [VIM-2744](https://youtrack.jetbrains.com/issue/VIM-2744) Fix undo from ex line | ||||||
|  | * [VIM-2749](https://youtrack.jetbrains.com/issue/VIM-2749) Fix :tabn and :tabN commands | ||||||
|  | * [VIM-2718](https://youtrack.jetbrains.com/issue/VIM-2718) Fixed case where the primary caret was changed | ||||||
|  | * [VIM-2766](https://youtrack.jetbrains.com/issue/VIM-2766) Move NERDTree update to background thread | ||||||
|  | * [VIM-2768](https://youtrack.jetbrains.com/issue/VIM-2768) Refactor listeners | ||||||
|  |  | ||||||
|  | ## 1.11.0, 2022-08-09 | ||||||
|  |  | ||||||
| ### Features: | ### Features: | ||||||
| * Add `gcu` command for Commentary plugin | * Add `gcu` command for Commentary plugin | ||||||
| * Add `:Commentary` command, which works great for commands such as `:%g/fun/Commentary` | * Add `:Commentary` command, which works great for commands such as `:%g/fun/Commentary` | ||||||
| @@ -36,6 +47,7 @@ usual beta standards. | |||||||
|   E.g. `<Plug>Commentary` instead of `<Plug>(CommentMotion)`. Old mappings are maintained for compatibility. |   E.g. `<Plug>Commentary` instead of `<Plug>(CommentMotion)`. Old mappings are maintained for compatibility. | ||||||
| * If you open `~/.ideavimrc` in IDE, remove a mapping, and reload the config using the reload button, | * If you open `~/.ideavimrc` in IDE, remove a mapping, and reload the config using the reload button, | ||||||
|   the mapping will actually be unmapped. |   the mapping will actually be unmapped. | ||||||
|  | * New vim (and IdeaVim) behaviour: `ci(`& friends searches for the brackets in the line. | ||||||
|  |  | ||||||
| ### Fixes: | ### Fixes: | ||||||
| * [VIM-2587](https://youtrack.jetbrains.com/issue/VIM-2587) Use ctrl-6 as ctrl-^ | * [VIM-2587](https://youtrack.jetbrains.com/issue/VIM-2587) Use ctrl-6 as ctrl-^ | ||||||
| @@ -52,11 +64,14 @@ usual beta standards. | |||||||
| * [VIM-2595](https://youtrack.jetbrains.com/issue/VIM-2595) Support plugins in macro execution | * [VIM-2595](https://youtrack.jetbrains.com/issue/VIM-2595) Support plugins in macro execution | ||||||
| * [VIM-2671](https://youtrack.jetbrains.com/issue/VIM-2671) Fix using plugins from mappings | * [VIM-2671](https://youtrack.jetbrains.com/issue/VIM-2671) Fix using plugins from mappings | ||||||
| * [VIM-2675](https://youtrack.jetbrains.com/issue/VIM-2675) Fix numbering register in visual mode | * [VIM-2675](https://youtrack.jetbrains.com/issue/VIM-2675) Fix numbering register in visual mode | ||||||
| * [VIM-696](https://youtrack.jetbrains.com/issue/VIM-696/vim-selection-issue-after-undo) Fix selection after undo |  | ||||||
| * [VIM-744](https://youtrack.jetbrains.com/issue/VIM-744/Use-undoredo-with-count-modifier) Add count to undo/redo | * [VIM-744](https://youtrack.jetbrains.com/issue/VIM-744/Use-undoredo-with-count-modifier) Add count to undo/redo | ||||||
| * [VIM-1862](https://youtrack.jetbrains.com/issue/VIM-1862/Ex-commands-executed-in-keymaps-and-macros-are-added-to-the-command-history) Fix command history | * [VIM-1862](https://youtrack.jetbrains.com/issue/VIM-1862/Ex-commands-executed-in-keymaps-and-macros-are-added-to-the-command-history) Fix command history | ||||||
| * [VIM-2227](https://youtrack.jetbrains.com/issue/VIM-2227) Wrong behavior when deleting / changing surround with invalid character | * [VIM-2227](https://youtrack.jetbrains.com/issue/VIM-2227) Wrong behavior when deleting / changing surround with invalid character | ||||||
| * [VIM-2691](https://youtrack.jetbrains.com/issue/VIM-2691) Save file on :w | * [VIM-2691](https://youtrack.jetbrains.com/issue/VIM-2691) Save file on :w | ||||||
|  | * [VIM-2710](https://youtrack.jetbrains.com/issue/VIM-2710) Show options value on `set opt` | ||||||
|  | * [VIM-913](https://youtrack.jetbrains.com/issue/VIM-913) Partially fix the issue with macros and autocompletion | ||||||
|  | * [VIM-2723](https://youtrack.jetbrains.com/issue/VIM-2723) Move focus to editor after :q | ||||||
|  | * [VIM-2728](https://youtrack.jetbrains.com/issue/VIM-2728) Give access to global variables | ||||||
|  |  | ||||||
| ### Merged PRs: | ### Merged PRs: | ||||||
| * [468](https://github.com/JetBrains/ideavim/pull/468) by [Thomas Schouten](https://github.com/PHPirates): Implement UserDataHolder for EditorDataContext | * [468](https://github.com/JetBrains/ideavim/pull/468) by [Thomas Schouten](https://github.com/PHPirates): Implement UserDataHolder for EditorDataContext | ||||||
| @@ -66,6 +81,10 @@ usual beta standards. | |||||||
| * [494](https://github.com/JetBrains/ideavim/pull/494) by [Matt Ellis](https://github.com/citizenmatt): Cleanup pre-212 CaretVisualAttributes compatibility code | * [494](https://github.com/JetBrains/ideavim/pull/494) by [Matt Ellis](https://github.com/citizenmatt): Cleanup pre-212 CaretVisualAttributes compatibility code | ||||||
| * [504](https://github.com/JetBrains/ideavim/pull/504) by [Matt Ellis](https://github.com/citizenmatt): Minor bug fixes | * [504](https://github.com/JetBrains/ideavim/pull/504) by [Matt Ellis](https://github.com/citizenmatt): Minor bug fixes | ||||||
| * [519](https://github.com/JetBrains/ideavim/pull/519) by [chylex](https://github.com/chylex): Fix(VIM-2227): Wrong behavior when deleting / changing surround with invalid character | * [519](https://github.com/JetBrains/ideavim/pull/519) by [chylex](https://github.com/chylex): Fix(VIM-2227): Wrong behavior when deleting / changing surround with invalid character | ||||||
|  | * [525](https://github.com/JetBrains/ideavim/pull/525) by [Matt Ellis](https://github.com/citizenmatt): Improve handling of fractional width fonts | ||||||
|  | * [526](https://github.com/JetBrains/ideavim/pull/526) by [Alex Pláte](https://github.com/AlexPl292): Create gradle.properties | ||||||
|  | * [528](https://github.com/JetBrains/ideavim/pull/528) by [chylex](https://github.com/chylex): Implement partial code completion support in macros | ||||||
|  | * [531](https://github.com/JetBrains/ideavim/pull/531) by [Matt Ellis](https://github.com/citizenmatt): Consolidate doTest methods | ||||||
|  |  | ||||||
| ## 1.10.0, 2022-02-17 | ## 1.10.0, 2022-02-17 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ IdeaVim is an open source project created by 80+ contributors. Would you like to | |||||||
| This page is created to help you start contributing. And who knows, maybe in a few days this project will be brighter than ever! | This page is created to help you start contributing. And who knows, maybe in a few days this project will be brighter than ever! | ||||||
|  |  | ||||||
| :warning: The plugin is currently under a huge refactoring aiming to split into vim-engine and IdeaVim in order to | :warning: The plugin is currently under a huge refactoring aiming to split into vim-engine and IdeaVim in order to | ||||||
| support the new [Fleet IDE](https://www.jetbrains.com/fleet/). | support the new [Fleet IDE](https://www.jetbrains.com/fleet/). Please see [Fleet refactoring](#Fleet-refactoring). | ||||||
|  |  | ||||||
| ## Before you begin | ## Before you begin | ||||||
|  |  | ||||||
| @@ -32,7 +32,7 @@ OK, ready to do some coding? | |||||||
| Yoo hoo! You’re all set to begin contributing. | Yoo hoo! You’re all set to begin contributing. | ||||||
| We've prepared some useful configurations for you: | We've prepared some useful configurations for you: | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| And here are useful gradle commands: | And here are useful gradle commands: | ||||||
|  |  | ||||||
| @@ -120,6 +120,17 @@ so you can reuse your `.vimrc` settings. | |||||||
| We also support proper command mappings (functions are mapped to `<Plug>...`), the operator function (`OperatorFunction`), and so on. | We also support proper command mappings (functions are mapped to `<Plug>...`), the operator function (`OperatorFunction`), and so on. | ||||||
| - Magic is supported as well. See `Magic`. | - Magic is supported as well. See `Magic`. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Fleet refactoring | ||||||
|  | At the moment, IdeaVim is under an active refactoring aiming to split IdeaVim into two modules: vim-engine and IdeaVim. | ||||||
|  |  | ||||||
|  | If you develop a plugin that depends on IdeaVim: We have an instrument to check that our changes don't affect | ||||||
|  | the plugins in the marketplace. Also, we commit to support currently used API at least till the end of 2022. | ||||||
|  | If you still encounter any issues with the newer versions of IdeaVim, please [contact maintainers](https://github.com/JetBrains/ideavim#contact-maintainers). | ||||||
|  | We kindly ask you not to use anything from the new API (like `VimEditor`, `injector`) because at the moment we don't | ||||||
|  | guarantee the compatibility of this API in the future versions. | ||||||
|  |  | ||||||
|  |  | ||||||
| ----- | ----- | ||||||
|  |  | ||||||
| ### I read the whole page but something is still unclear. | ### I read the whole page but something is still unclear. | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @@ -11,7 +11,7 @@ IdeaVim | |||||||
| [![Gitter][gitter-svg]][gitter] | [![Gitter][gitter-svg]][gitter] | ||||||
| [![Twitter][twitter-svg]][twitter] | [![Twitter][twitter-svg]][twitter] | ||||||
|  |  | ||||||
| IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs. | IdeaVim is a Vim engine for JetBrains IDEs. | ||||||
|  |  | ||||||
| ##### Contact maintainers: | ##### Contact maintainers: | ||||||
| * [Bug tracker](https://youtrack.jetbrains.com/issues/VIM) | * [Bug tracker](https://youtrack.jetbrains.com/issues/VIM) | ||||||
| @@ -36,7 +36,7 @@ Setup | |||||||
| - IdeaVim can be installed via `Settings | Plugins`. | - IdeaVim can be installed via `Settings | Plugins`. | ||||||
| See the [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#). | See the [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#). | ||||||
|  |  | ||||||
| - Use `Tools | Vim Emulator` in the menu to enable or disable emulation. | - Use `Tools | Vim` in the menu to enable or disable vim. | ||||||
|  |  | ||||||
| - Use the `~/.ideavimrc` file as an analog of `~/.vimrc` ([learn more](#Files)). The XDG standard is supported, as well. | - Use the `~/.ideavimrc` file as an analog of `~/.vimrc` ([learn more](#Files)). The XDG standard is supported, as well. | ||||||
|  |  | ||||||
| @@ -88,7 +88,7 @@ Here are some examples of supported vim features and commands: | |||||||
| * Vim web help | * Vim web help | ||||||
| * `~/.ideavimrc` configuration file | * `~/.ideavimrc` configuration file | ||||||
|  |  | ||||||
| [Emulated Vim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins): | [IdeaVim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins): | ||||||
|  |  | ||||||
| * vim-easymotion | * vim-easymotion | ||||||
| * NERDTree | * NERDTree | ||||||
| @@ -198,7 +198,7 @@ Alternatively, you can set up initialization commands using [XDG](https://specif | |||||||
| Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file. | Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file. | ||||||
|  |  | ||||||
|  |  | ||||||
| Emulated Vim Plugins | IdeaVim Plugins | ||||||
| -------------------- | -------------------- | ||||||
|  |  | ||||||
| See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins) | See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins) | ||||||
| @@ -226,7 +226,10 @@ Ex commands or via `:map` command mappings: | |||||||
|  |  | ||||||
|     <details> |     <details> | ||||||
|         <summary><strong>"Track action Ids" Details</strong> (click to see)</summary> |         <summary><strong>"Track action Ids" Details</strong> (click to see)</summary> | ||||||
|         <img src="assets/readme/track_action_id.gif" alt="track action ids"/> |         <picture> | ||||||
|  |             <source media="(prefers-color-scheme: dark)" srcset="assets/readme/track_action_dark.gif"> | ||||||
|  |             <img src="assets/readme/track_action_light.gif" alt="track action ids"/> | ||||||
|  |         </picture> | ||||||
|     </details> |     </details> | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								assets/contributing/configs-dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/contributing/configs-dark.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 27 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/contributing/configs-light.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/contributing/configs-light.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 31 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 22 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/readme/track_action_dark.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/readme/track_action_dark.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.0 MiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 2.1 MiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/readme/track_action_light.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/readme/track_action_light.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 981 KiB | 
| @@ -15,7 +15,9 @@ buildscript { | |||||||
|         classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2") |         classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2") | ||||||
|         classpath("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r") |         classpath("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r") | ||||||
|         classpath("org.kohsuke:github-api:1.305") |         classpath("org.kohsuke:github-api:1.305") | ||||||
|         classpath("org.jetbrains:markdown:0.3.1") |  | ||||||
|  |         // This comes from the changelog plugin | ||||||
|  | //        classpath("org.jetbrains:markdown:0.3.1") | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -24,11 +26,11 @@ plugins { | |||||||
|     java |     java | ||||||
|     kotlin("jvm") version "1.6.21" |     kotlin("jvm") version "1.6.21" | ||||||
|  |  | ||||||
|     id("org.jetbrains.intellij") version "1.7.0-SNAPSHOT" |     id("org.jetbrains.intellij") version "1.10.0-SNAPSHOT" | ||||||
|     id("org.jetbrains.changelog") version "1.3.1" |     id("org.jetbrains.changelog") version "1.3.1" | ||||||
|  |  | ||||||
|     // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle |     // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle | ||||||
|     id("org.jlleitschuh.gradle.ktlint") version "10.2.1" |     id("org.jlleitschuh.gradle.ktlint") version "10.3.0" | ||||||
| } | } | ||||||
|  |  | ||||||
| // Import variables from gradle.properties file | // Import variables from gradle.properties file | ||||||
| @@ -71,6 +73,8 @@ dependencies { | |||||||
|     antlr("org.antlr:antlr4:$antlrVersion") |     antlr("org.antlr:antlr4:$antlrVersion") | ||||||
|  |  | ||||||
|     api(project(":vim-engine")) |     api(project(":vim-engine")) | ||||||
|  |  | ||||||
|  |     testApi("com.squareup.okhttp3:okhttp:4.10.0") | ||||||
| } | } | ||||||
|  |  | ||||||
| configurations { | configurations { | ||||||
| @@ -85,6 +89,8 @@ tasks.register<Test>("testWithNeovim") { | |||||||
|     group = "verification" |     group = "verification" | ||||||
|     systemProperty("ideavim.nvim.test", "true") |     systemProperty("ideavim.nvim.test", "true") | ||||||
|     exclude("/ui/**") |     exclude("/ui/**") | ||||||
|  |     exclude("**/longrunning/**") | ||||||
|  |     exclude("**/propertybased/**") | ||||||
| } | } | ||||||
|  |  | ||||||
| tasks.register<Test>("testPropertyBased") { | tasks.register<Test>("testPropertyBased") { | ||||||
| @@ -115,6 +121,8 @@ tasks { | |||||||
|         include("**/*test.class") |         include("**/*test.class") | ||||||
|         include("**/*Tests.class") |         include("**/*Tests.class") | ||||||
|         exclude("**/ParserTest.class") |         exclude("**/ParserTest.class") | ||||||
|  |         exclude("**/longrunning/**") | ||||||
|  |         exclude("**/propertybased/**") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     val testPropertyBased by getting(Test::class) { |     val testPropertyBased by getting(Test::class) { | ||||||
| @@ -144,7 +152,7 @@ tasks { | |||||||
|     compileKotlin { |     compileKotlin { | ||||||
|         kotlinOptions { |         kotlinOptions { | ||||||
|             jvmTarget = javaVersion |             jvmTarget = javaVersion | ||||||
|             apiVersion = "1.5" |             apiVersion = "1.6" | ||||||
|             freeCompilerArgs = listOf("-Xjvm-default=all-compatibility") |             freeCompilerArgs = listOf("-Xjvm-default=all-compatibility") | ||||||
| //            allWarningsAsErrors = true | //            allWarningsAsErrors = true | ||||||
|         } |         } | ||||||
| @@ -152,12 +160,24 @@ tasks { | |||||||
|     compileTestKotlin { |     compileTestKotlin { | ||||||
|         kotlinOptions { |         kotlinOptions { | ||||||
|             jvmTarget = javaVersion |             jvmTarget = javaVersion | ||||||
|             apiVersion = "1.5" |             apiVersion = "1.6" | ||||||
| //            allWarningsAsErrors = true | //            allWarningsAsErrors = true | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | java { | ||||||
|  |     toolchain { | ||||||
|  |         languageVersion.set(JavaLanguageVersion.of(javaVersion)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | kotlin { | ||||||
|  |     jvmToolchain { | ||||||
|  |         (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(javaVersion)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| gradle.projectsEvaluated { | gradle.projectsEvaluated { | ||||||
|     tasks.compileJava { |     tasks.compileJava { | ||||||
| //        options.compilerArgs.add("-Werror") | //        options.compilerArgs.add("-Werror") | ||||||
| @@ -200,7 +220,7 @@ tasks { | |||||||
|     runPluginVerifier { |     runPluginVerifier { | ||||||
|         downloadDir.set("${project.buildDir}/pluginVerifier/ides") |         downloadDir.set("${project.buildDir}/pluginVerifier/ides") | ||||||
|         teamCityOutputFormat.set(true) |         teamCityOutputFormat.set(true) | ||||||
|         ideVersions.set(listOf("IC-2021.3.4")) | //        ideVersions.set(listOf("IC-2021.3.4")) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     generateGrammarSource { |     generateGrammarSource { | ||||||
| @@ -231,12 +251,18 @@ tasks { | |||||||
|         dependsOn(createOpenApiSourceJar) |         dependsOn(createOpenApiSourceJar) | ||||||
|         from(createOpenApiSourceJar) { into("lib/src") } |         from(createOpenApiSourceJar) { into("lib/src") } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Don't forget to update plugin.xml | ||||||
|  |     patchPluginXml { | ||||||
|  |         sinceBuild.set("222") | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| // --- Linting | // --- Linting | ||||||
|  |  | ||||||
| ktlint { | ktlint { | ||||||
|     disabledRules.add("no-wildcard-imports") |     disabledRules.add("no-wildcard-imports") | ||||||
|  |     version.set("0.43.0") | ||||||
| } | } | ||||||
|  |  | ||||||
| // --- Tests | // --- Tests | ||||||
| @@ -261,7 +287,7 @@ changelog { | |||||||
|     itemPrefix.set("*") |     itemPrefix.set("*") | ||||||
|     path.set("${project.projectDir}/CHANGES.md") |     path.set("${project.projectDir}/CHANGES.md") | ||||||
|     unreleasedTerm.set("To Be Released") |     unreleasedTerm.set("To Be Released") | ||||||
|     headerParserRegex.set("\\d\\.\\d+(.\\d+)?".toRegex()) |     headerParserRegex.set("(\\d\\.\\d+(.\\d+)?)".toRegex()) | ||||||
| //    header = { "${project.version}" } | //    header = { "${project.version}" } | ||||||
| //    version = "0.60" | //    version = "0.60" | ||||||
| } | } | ||||||
| @@ -314,20 +340,30 @@ tasks.register("slackNotification") { | |||||||
|             println("Response code: $postRc") |             println("Response code: $postRc") | ||||||
|             if (postRc == 200) { |             if (postRc == 200) { | ||||||
|                 println(inputStream.bufferedReader().use { it.readText() }) |                 println(inputStream.bufferedReader().use { it.readText() }) | ||||||
|  |             } else { | ||||||
|  |                 println(errorStream.bufferedReader().use { it.readText() }) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| // --- Update authors | // Uncomment to enable FUS testing mode | ||||||
|  | // tasks { | ||||||
|  | //    withType<org.jetbrains.intellij.tasks.RunIdeTask> { | ||||||
|  | //        jvmArgs("-Didea.is.internal=true") | ||||||
|  | //        jvmArgs("-Dfus.internal.test.mode=true") | ||||||
|  | //    } | ||||||
|  | // } | ||||||
|  |  | ||||||
|  | // --- Update authors | ||||||
| tasks.register("updateAuthors") { | tasks.register("updateAuthors") { | ||||||
|     doLast { |     doLast { | ||||||
|         val uncheckedEmails = setOf( |         val uncheckedEmails = setOf( | ||||||
|             "aleksei.plate@jetbrains.com", |             "aleksei.plate@jetbrains.com", | ||||||
|             "aleksei.plate@teamcity", |             "aleksei.plate@teamcity", | ||||||
|             "aleksei.plate@TeamCity", |             "aleksei.plate@TeamCity", | ||||||
|             "alex.plate@192.168.0.109" |             "alex.plate@192.168.0.109", | ||||||
|  |             "nikita.koshcheev@TeamCity", | ||||||
|         ) |         ) | ||||||
|         updateAuthors(uncheckedEmails) |         updateAuthors(uncheckedEmails) | ||||||
|     } |     } | ||||||
| @@ -338,6 +374,7 @@ val prId: String by project | |||||||
| tasks.register("updateMergedPr") { | tasks.register("updateMergedPr") { | ||||||
|     doLast { |     doLast { | ||||||
|         if (project.hasProperty("prId")) { |         if (project.hasProperty("prId")) { | ||||||
|  |             println("Got pr id: $prId") | ||||||
|             updateMergedPr(prId.toInt()) |             updateMergedPr(prId.toInt()) | ||||||
|         } else { |         } else { | ||||||
|             error("Cannot get prId") |             error("Cannot get prId") | ||||||
| @@ -501,7 +538,9 @@ data class Change(val id: String, val text: String) | |||||||
|  |  | ||||||
| fun updateMergedPr(number: Int) { | fun updateMergedPr(number: Int) { | ||||||
|     val gitHub = org.kohsuke.github.GitHub.connect() |     val gitHub = org.kohsuke.github.GitHub.connect() | ||||||
|  |     println("Connecting to the repo...") | ||||||
|     val repository = gitHub.getRepository("JetBrains/ideavim") |     val repository = gitHub.getRepository("JetBrains/ideavim") | ||||||
|  |     println("Getting pull requests...") | ||||||
|     val pullRequest = repository.getPullRequest(number) |     val pullRequest = repository.getPullRequest(number) | ||||||
|     if (pullRequest.user.login == "dependabot[bot]") return |     if (pullRequest.user.login == "dependabot[bot]") return | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| # suppress inspection "UnusedProperty" for whole file | # suppress inspection "UnusedProperty" for whole file | ||||||
|  |  | ||||||
| ideaVersion=LATEST-EAP-SNAPSHOT | ideaVersion=2022.2.2 | ||||||
| downloadIdeaSources=true | downloadIdeaSources=true | ||||||
| instrumentPluginCode=true | instrumentPluginCode=true | ||||||
| version=SNAPSHOT | version=chylex-13 | ||||||
| javaVersion=11 | javaVersion=17 | ||||||
| remoteRobotVersion=0.11.10 | remoteRobotVersion=0.11.15 | ||||||
| antlrVersion=4.10.1 | antlrVersion=4.10.1 | ||||||
|  |  | ||||||
| # Please don't forget to update kotlin version in buildscript section | # Please don't forget to update kotlin version in buildscript section | ||||||
|   | |||||||
							
								
								
									
										79982
									
								
								qodana.sarif.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79982
									
								
								qodana.sarif.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -27,6 +27,7 @@ import com.intellij.openapi.editor.EditorFactory; | |||||||
| import com.intellij.openapi.editor.actionSystem.TypedAction; | import com.intellij.openapi.editor.actionSystem.TypedAction; | ||||||
| import com.intellij.openapi.editor.actionSystem.TypedActionHandler; | import com.intellij.openapi.editor.actionSystem.TypedActionHandler; | ||||||
| import com.intellij.openapi.editor.event.*; | import com.intellij.openapi.editor.event.*; | ||||||
|  | import com.intellij.openapi.util.Disposer; | ||||||
| import com.maddyhome.idea.vim.helper.HandlerInjector; | import com.maddyhome.idea.vim.helper.HandlerInjector; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| @@ -101,38 +102,41 @@ public class EventFacade { | |||||||
|     EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); |     EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @SuppressWarnings("deprecation") |   public void addEditorMouseListener(@NotNull Editor editor, | ||||||
|   public void removeEditorFactoryListener(@NotNull EditorFactoryListener listener) { |                                      @NotNull EditorMouseListener listener, | ||||||
|     // Listener is removed not only if application is disposed |                                      @NotNull Disposable disposable) { | ||||||
|     EditorFactory.getInstance().removeEditorFactoryListener(listener); |     editor.addEditorMouseListener(listener, disposable); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void addEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) { |  | ||||||
|     editor.addEditorMouseListener(listener); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void removeEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) { |   public void removeEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) { | ||||||
|     editor.removeEditorMouseListener(listener); |     editor.removeEditorMouseListener(listener); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void addComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) { |   public void addComponentMouseListener(@NotNull Component component, | ||||||
|  |                                         @NotNull MouseListener mouseListener, | ||||||
|  |                                         @NotNull Disposable disposable) { | ||||||
|     component.addMouseListener(mouseListener); |     component.addMouseListener(mouseListener); | ||||||
|  |     Disposer.register(disposable, () -> component.removeMouseListener(mouseListener)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void removeComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) { |   public void removeComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) { | ||||||
|     component.removeMouseListener(mouseListener); |     component.removeMouseListener(mouseListener); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void addEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) { |   public void addEditorMouseMotionListener(@NotNull Editor editor, | ||||||
|     editor.addEditorMouseMotionListener(listener); |                                            @NotNull EditorMouseMotionListener listener, | ||||||
|  |                                            @NotNull Disposable disposable) { | ||||||
|  |     editor.addEditorMouseMotionListener(listener, disposable); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void removeEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) { |   public void removeEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) { | ||||||
|     editor.removeEditorMouseMotionListener(listener); |     editor.removeEditorMouseMotionListener(listener); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void addEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) { |   public void addEditorSelectionListener(@NotNull Editor editor, | ||||||
|     editor.getSelectionModel().addSelectionListener(listener); |                                          @NotNull SelectionListener listener, | ||||||
|  |                                          @NotNull Disposable disposable) { | ||||||
|  |     editor.getSelectionModel().addSelectionListener(listener, disposable); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void removeEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) { |   public void removeEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) { | ||||||
|   | |||||||
| @@ -18,8 +18,14 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim | package com.maddyhome.idea.vim | ||||||
|  |  | ||||||
|  | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx | ||||||
| import com.intellij.openapi.project.Project | import com.intellij.openapi.project.Project | ||||||
|  | import com.intellij.openapi.project.ProjectManagerListener | ||||||
| import com.intellij.openapi.startup.StartupActivity | import com.intellij.openapi.startup.StartupActivity | ||||||
|  | import com.maddyhome.idea.vim.api.injector | ||||||
|  | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
|  | import com.maddyhome.idea.vim.helper.localEditors | ||||||
|  | import com.maddyhome.idea.vim.options.OptionScope | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @author Alex Plate |  * @author Alex Plate | ||||||
| @@ -36,3 +42,19 @@ class PluginStartup : StartupActivity.DumbAware/*, LightEditCompatible*/ { | |||||||
|     VimPlugin.getInstance().initialize() |     VimPlugin.getInstance().initialize() | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // This is a temporal workaround for VIM-2487 | ||||||
|  | class PyNotebooksCloseWorkaround : ProjectManagerListener { | ||||||
|  |   override fun projectClosingBeforeSave(project: Project) { | ||||||
|  |     val close = injector.optionService.getOptionValue(OptionScope.GLOBAL, "closenotebooks").asBoolean() | ||||||
|  |     if (close) { | ||||||
|  |       localEditors().forEach { editor -> | ||||||
|  |         val virtualFile = EditorHelper.getVirtualFile(editor) | ||||||
|  |         if (virtualFile?.extension == "ipynb") { | ||||||
|  |           val fileEditorManager = FileEditorManagerEx.getInstanceEx(project) | ||||||
|  |           fileEditorManager.closeFile(virtualFile) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -19,8 +19,6 @@ package com.maddyhome.idea.vim; | |||||||
|  |  | ||||||
| import com.intellij.ide.plugins.IdeaPluginDescriptor; | import com.intellij.ide.plugins.IdeaPluginDescriptor; | ||||||
| import com.intellij.ide.plugins.PluginManagerCore; | import com.intellij.ide.plugins.PluginManagerCore; | ||||||
| import com.intellij.notification.Notification; |  | ||||||
| import com.intellij.notification.NotificationListener; |  | ||||||
| import com.intellij.openapi.Disposable; | import com.intellij.openapi.Disposable; | ||||||
| import com.intellij.openapi.application.Application; | import com.intellij.openapi.application.Application; | ||||||
| import com.intellij.openapi.application.ApplicationManager; | import com.intellij.openapi.application.ApplicationManager; | ||||||
| @@ -32,9 +30,9 @@ import com.intellij.openapi.extensions.PluginId; | |||||||
| import com.intellij.openapi.keymap.Keymap; | import com.intellij.openapi.keymap.Keymap; | ||||||
| import com.intellij.openapi.keymap.ex.KeymapManagerEx; | import com.intellij.openapi.keymap.ex.KeymapManagerEx; | ||||||
| import com.intellij.openapi.keymap.impl.DefaultKeymap; | import com.intellij.openapi.keymap.impl.DefaultKeymap; | ||||||
| import com.intellij.openapi.options.ShowSettingsUtil; |  | ||||||
| import com.intellij.openapi.project.Project; | import com.intellij.openapi.project.Project; | ||||||
| import com.intellij.openapi.ui.Messages; | import com.intellij.openapi.ui.Messages; | ||||||
|  | import com.intellij.openapi.util.Disposer; | ||||||
| import com.intellij.openapi.util.SystemInfo; | import com.intellij.openapi.util.SystemInfo; | ||||||
| import com.maddyhome.idea.vim.api.VimInjectorKt; | import com.maddyhome.idea.vim.api.VimInjectorKt; | ||||||
| import com.maddyhome.idea.vim.api.VimKeyGroup; | import com.maddyhome.idea.vim.api.VimKeyGroup; | ||||||
| @@ -48,20 +46,17 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup; | |||||||
| import com.maddyhome.idea.vim.helper.MacKeyRepeat; | import com.maddyhome.idea.vim.helper.MacKeyRepeat; | ||||||
| import com.maddyhome.idea.vim.listener.VimListenerManager; | import com.maddyhome.idea.vim.listener.VimListenerManager; | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimInjector; | import com.maddyhome.idea.vim.newapi.IjVimInjector; | ||||||
| import com.maddyhome.idea.vim.options.OptionService; |  | ||||||
| import com.maddyhome.idea.vim.ui.StatusBarIconFactory; | import com.maddyhome.idea.vim.ui.StatusBarIconFactory; | ||||||
| import com.maddyhome.idea.vim.ui.VimEmulationConfigurable; |  | ||||||
| import com.maddyhome.idea.vim.ui.ex.ExEntryPanel; | import com.maddyhome.idea.vim.ui.ex.ExEntryPanel; | ||||||
| import com.maddyhome.idea.vim.vimscript.services.FunctionStorage; | import com.maddyhome.idea.vim.vimscript.services.FunctionStorage; | ||||||
| import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService; | import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService; | ||||||
| import com.maddyhome.idea.vim.vimscript.services.VimVariableService; | import com.maddyhome.idea.vim.vimscript.services.OptionService; | ||||||
|  | import com.maddyhome.idea.vim.vimscript.services.VariableService; | ||||||
| import org.jdom.Element; | import org.jdom.Element; | ||||||
| import org.jetbrains.annotations.Nls; | import org.jetbrains.annotations.Nls; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import javax.swing.event.HyperlinkEvent; |  | ||||||
|  |  | ||||||
| import static com.maddyhome.idea.vim.group.EditorGroup.EDITOR_STORE_ELEMENT; | import static com.maddyhome.idea.vim.group.EditorGroup.EDITOR_STORE_ELEMENT; | ||||||
| import static com.maddyhome.idea.vim.group.KeyGroup.SHORTCUT_CONFLICTS_ELEMENT; | import static com.maddyhome.idea.vim.group.KeyGroup.SHORTCUT_CONFLICTS_ELEMENT; | ||||||
| import static com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc; | import static com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc; | ||||||
| @@ -94,6 +89,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|  |  | ||||||
|   private final @NotNull VimState state = new VimState(); |   private final @NotNull VimState state = new VimState(); | ||||||
|  |  | ||||||
|  |   public Disposable onOffDisposable; | ||||||
|  |  | ||||||
|   VimPlugin() { |   VimPlugin() { | ||||||
|     ApplicationConfigurationMigrator.getInstance().migrate(); |     ApplicationConfigurationMigrator.getInstance().migrate(); | ||||||
|   } |   } | ||||||
| @@ -117,7 +114,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|   @Override |   @Override | ||||||
|   public void dispose() { |   public void dispose() { | ||||||
|     LOG.debug("disposeComponent"); |     LOG.debug("disposeComponent"); | ||||||
|     turnOffPlugin(); |     turnOffPlugin(false); | ||||||
|     LOG.debug("done"); |     LOG.debug("done"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -226,8 +223,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|     return (PutGroup)VimInjectorKt.getInjector().getPut(); |     return (PutGroup)VimInjectorKt.getInjector().getPut(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public static @NotNull VimVariableService getVariableService() { |   public static @NotNull VariableService getVariableService() { | ||||||
|     return ApplicationManager.getApplication().getService(VimVariableService.class); |     return ApplicationManager.getApplication().getService(VariableService.class); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public static @NotNull OptionService getOptionService() { |   public static @NotNull OptionService getOptionService() { | ||||||
| @@ -275,7 +272,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|     if (isEnabled() == enabled) return; |     if (isEnabled() == enabled) return; | ||||||
|  |  | ||||||
|     if (!enabled) { |     if (!enabled) { | ||||||
|       getInstance().turnOffPlugin(); |       getInstance().turnOffPlugin(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getInstance().enabled = enabled; |     getInstance().enabled = enabled; | ||||||
| @@ -341,6 +338,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|    *      execution, what theoretically may cause bugs (e.g. VIM-2540) |    *      execution, what theoretically may cause bugs (e.g. VIM-2540) | ||||||
|    */ |    */ | ||||||
|   private void turnOnPlugin() { |   private void turnOnPlugin() { | ||||||
|  |     onOffDisposable = Disposer.newDisposable(this, "IdeaVimOnOffDisposer"); | ||||||
|  |  | ||||||
|     // 1) Update state |     // 1) Update state | ||||||
|     ApplicationManager.getApplication().invokeLater(this::updateState); |     ApplicationManager.getApplication().invokeLater(this::updateState); | ||||||
|  |  | ||||||
| @@ -366,16 +365,20 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|     VimListenerManager.INSTANCE.turnOn(); |     VimListenerManager.INSTANCE.turnOn(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private void turnOffPlugin() { |   private void turnOffPlugin(boolean unsubscribe) { | ||||||
|     SearchGroup searchGroup = getSearchIfCreated(); |     SearchGroup searchGroup = getSearchIfCreated(); | ||||||
|     if (searchGroup != null) { |     if (searchGroup != null) { | ||||||
|       searchGroup.turnOff(); |       searchGroup.turnOff(); | ||||||
|     } |     } | ||||||
|  |     if (unsubscribe) { | ||||||
|       VimListenerManager.INSTANCE.turnOff(); |       VimListenerManager.INSTANCE.turnOff(); | ||||||
|  |     } | ||||||
|     ExEntryPanel.fullReset(); |     ExEntryPanel.fullReset(); | ||||||
|  |  | ||||||
|     // Unregister vim actions in command mode |     // Unregister vim actions in command mode | ||||||
|     RegisterActions.unregisterActions(); |     RegisterActions.unregisterActions(); | ||||||
|  |  | ||||||
|  |     Disposer.dispose(onOffDisposable); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private boolean stateUpdated = false; |   private boolean stateUpdated = false; | ||||||
| @@ -389,7 +392,9 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|         final Boolean enabled = keyRepeat.isEnabled(); |         final Boolean enabled = keyRepeat.isEnabled(); | ||||||
|         final Boolean isKeyRepeat = getEditor().isKeyRepeat(); |         final Boolean isKeyRepeat = getEditor().isKeyRepeat(); | ||||||
|         if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) { |         if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) { | ||||||
|           if (VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) { |           // This system property is used in IJ ui robot to hide the startup tips | ||||||
|  |           boolean showNotification = Boolean.getBoolean("ide.show.tips.on.startup.default.value"); | ||||||
|  |           if (showNotification && VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) { | ||||||
|             getEditor().setKeyRepeat(true); |             getEditor().setKeyRepeat(true); | ||||||
|             keyRepeat.setEnabled(true); |             keyRepeat.setEnabled(true); | ||||||
|           } |           } | ||||||
| @@ -408,12 +413,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|           keymap = manager.getKeymap(DefaultKeymap.getInstance().getDefaultKeymapName()); |           keymap = manager.getKeymap(DefaultKeymap.getInstance().getDefaultKeymapName()); | ||||||
|         } |         } | ||||||
|         assert keymap != null : "Default keymap not found"; |         assert keymap != null : "Default keymap not found"; | ||||||
|         VimPlugin.getNotifications().specialKeymap(keymap, new NotificationListener.Adapter() { |  | ||||||
|           @Override |  | ||||||
|           protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { |  | ||||||
|             ShowSettingsUtil.getInstance().showSettingsDialog(null, VimEmulationConfigurable.class); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|         manager.setActiveKeymap(keymap); |         manager.setActiveKeymap(keymap); | ||||||
|       } |       } | ||||||
|       if (previousStateVersion > 0 && previousStateVersion < 4) { |       if (previousStateVersion > 0 && previousStateVersion < 4) { | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ | |||||||
| package com.maddyhome.idea.vim.action | package com.maddyhome.idea.vim.action | ||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.ActionPlaces | import com.intellij.openapi.actionSystem.ActionPlaces | ||||||
|  | import com.intellij.openapi.actionSystem.ActionUpdateThread | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.project.DumbAwareToggleAction | import com.intellij.openapi.project.DumbAwareToggleAction | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| @@ -42,4 +43,6 @@ class VimPluginToggleAction : DumbAwareToggleAction()/*, LightEditCompatible*/ { | |||||||
|       if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable") |       if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable") | ||||||
|     } else MessageHelper.message("action.VimPluginToggle.text") |     } else MessageHelper.message("action.VimPluginToggle.text") | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   override fun getActionUpdateThread() = ActionUpdateThread.BGT | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.action | |||||||
| import com.google.common.collect.ImmutableSet | import com.google.common.collect.ImmutableSet | ||||||
| import com.intellij.codeInsight.lookup.LookupManager | import com.intellij.codeInsight.lookup.LookupManager | ||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
|  | import com.intellij.openapi.actionSystem.ActionUpdateThread | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.EmptyAction | import com.intellij.openapi.actionSystem.EmptyAction | ||||||
| @@ -95,6 +96,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // There is a chance that we can use BGT, but we call for isCell inside the update. | ||||||
|  |   // Not sure if can can use BGT with this call. Let's use EDT for now. | ||||||
|  |   override fun getActionUpdateThread() = ActionUpdateThread.EDT | ||||||
|  |  | ||||||
|   override fun update(e: AnActionEvent) { |   override fun update(e: AnActionEvent) { | ||||||
|     val start = if (traceTime) System.currentTimeMillis() else null |     val start = if (traceTime) System.currentTimeMillis() else null | ||||||
|     e.presentation.isEnabled = isEnabled(e) |     e.presentation.isEnabled = isEnabled(e) | ||||||
| @@ -149,6 +154,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ { | |||||||
|  |  | ||||||
|       if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false |       if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false | ||||||
|        |        | ||||||
|  |       if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT) return false | ||||||
|  |       if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) return false | ||||||
|  |       if (keyCode == KeyEvent.VK_HOME || keyCode == KeyEvent.VK_END) return false | ||||||
|  |  | ||||||
|       if (editor.inInsertMode) { |       if (editor.inInsertMode) { | ||||||
|         if (keyCode == KeyEvent.VK_TAB) { |         if (keyCode == KeyEvent.VK_TAB) { | ||||||
|           // TODO: This stops VimEditorTab seeing <Tab> in insert mode and correctly scrolling the view |           // TODO: This stops VimEditorTab seeing <Tab> in insert mode and correctly scrolling the view | ||||||
|   | |||||||
| @@ -22,6 +22,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.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
|  | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.Argument | import com.maddyhome.idea.vim.command.Argument | ||||||
| import com.maddyhome.idea.vim.command.Command | import com.maddyhome.idea.vim.command.Command | ||||||
| import com.maddyhome.idea.vim.command.CommandFlags | import com.maddyhome.idea.vim.command.CommandFlags | ||||||
| @@ -34,13 +35,13 @@ import com.maddyhome.idea.vim.group.visual.VimSelection | |||||||
| import com.maddyhome.idea.vim.handler.VimActionHandler | import com.maddyhome.idea.vim.handler.VimActionHandler | ||||||
| import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler | import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler | ||||||
| import com.maddyhome.idea.vim.helper.MessageHelper | import com.maddyhome.idea.vim.helper.MessageHelper | ||||||
| import com.maddyhome.idea.vim.helper.vimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.helper.enumSetOf | import com.maddyhome.idea.vim.helper.enumSetOf | ||||||
|  | import com.maddyhome.idea.vim.helper.vimStateMachine | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import java.util.* | import java.util.* | ||||||
|  |  | ||||||
| private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean { | private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean { | ||||||
|   val operatorFunction = VimPlugin.getKey().operatorFunction |   val operatorFunction = injector.keyGroup.operatorFunction | ||||||
|   if (operatorFunction == null) { |   if (operatorFunction == null) { | ||||||
|     VimPlugin.showMessage(MessageHelper.message("E774")) |     VimPlugin.showMessage(MessageHelper.message("E774")) | ||||||
|     return false |     return false | ||||||
| @@ -49,7 +50,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR | |||||||
|   val saveRepeatHandler = VimRepeater.repeatHandler |   val saveRepeatHandler = VimRepeater.repeatHandler | ||||||
|   VimPlugin.getMark().setChangeMarks(editor, textRange) |   VimPlugin.getMark().setChangeMarks(editor, textRange) | ||||||
|   KeyHandler.getInstance().reset(editor) |   KeyHandler.getInstance().reset(editor) | ||||||
|   val result = operatorFunction.apply(editor.ij, context.ij, selectionType) |   val result = operatorFunction.apply(editor, context, selectionType) | ||||||
|   VimRepeater.repeatHandler = saveRepeatHandler |   VimRepeater.repeatHandler = saveRepeatHandler | ||||||
|   return result |   return result | ||||||
| } | } | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.SingleExecution() { | |||||||
|     val res = arrayOf(true) |     val res = arrayOf(true) | ||||||
|     editor.forEachNativeCaret( |     editor.forEachNativeCaret( | ||||||
|       { caret: VimCaret -> |       { caret: VimCaret -> | ||||||
|         if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false)) res[0] = false |         if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)) res[0] = false | ||||||
|       }, |       }, | ||||||
|       true |       true | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution() | |||||||
|     val res = arrayOf(true) |     val res = arrayOf(true) | ||||||
|     editor.forEachNativeCaret( |     editor.forEachNativeCaret( | ||||||
|       { caret: VimCaret -> |       { caret: VimCaret -> | ||||||
|         if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true)) res[0] = false |         if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) res[0] = false | ||||||
|       }, |       }, | ||||||
|       true |       true | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -57,7 +57,14 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution( | |||||||
|         caret: VimCaret -> |         caret: VimCaret -> | ||||||
|         if (!caret.isValid) return@forEachNativeCaret |         if (!caret.isValid) return@forEachNativeCaret | ||||||
|         val range = caretsAndSelections[caret] ?: return@forEachNativeCaret |         val range = caretsAndSelections[caret] ?: return@forEachNativeCaret | ||||||
|         if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), false)) { |         if (!injector.changeGroup.deleteJoinRange( | ||||||
|  |             editor, | ||||||
|  |             caret, | ||||||
|  |             range.toVimTextRange(true).normalize(), | ||||||
|  |             false, | ||||||
|  |             operatorArguments | ||||||
|  |           ) | ||||||
|  |         ) { | ||||||
|           res[0] = false |           res[0] = false | ||||||
|         } |         } | ||||||
|       }, true |       }, true | ||||||
|   | |||||||
| @@ -56,7 +56,14 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec | |||||||
|       { caret: VimCaret -> |       { caret: VimCaret -> | ||||||
|         if (!caret.isValid) return@forEachNativeCaret |         if (!caret.isValid) return@forEachNativeCaret | ||||||
|         val range = caretsAndSelections[caret] ?: return@forEachNativeCaret |         val range = caretsAndSelections[caret] ?: return@forEachNativeCaret | ||||||
|         if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), true)) { |         if (!injector.changeGroup.deleteJoinRange( | ||||||
|  |             editor, | ||||||
|  |             caret, | ||||||
|  |             range.toVimTextRange(true).normalize(), | ||||||
|  |             true, | ||||||
|  |             operatorArguments | ||||||
|  |           ) | ||||||
|  |         ) { | ||||||
|           res[0] = false |           res[0] = false | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| package com.maddyhome.idea.vim.action.internal | package com.maddyhome.idea.vim.action.internal | ||||||
|  |  | ||||||
| import com.intellij.ide.ui.AntialiasingType | import com.intellij.ide.ui.AntialiasingType | ||||||
|  | import com.intellij.ide.ui.UISettings | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| @@ -124,7 +125,7 @@ class AddBlockInlaysAction : AnAction() { | |||||||
|         val editorContext = FontInfo.getFontRenderContext(editor.contentComponent) |         val editorContext = FontInfo.getFontRenderContext(editor.contentComponent) | ||||||
|         return FontRenderContext( |         return FontRenderContext( | ||||||
|           editorContext.transform, AntialiasingType.getKeyForCurrentScope(false), |           editorContext.transform, AntialiasingType.getKeyForCurrentScope(false), | ||||||
|           if (editor is EditorImpl) editor.myFractionalMetricsHintValue else RenderingHints.VALUE_FRACTIONALMETRICS_OFF |           if (editor is EditorImpl) UISettings.editorFractionalMetricsHint else RenderingHints.VALUE_FRACTIONALMETRICS_OFF | ||||||
|         ) |         ) | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,12 +24,22 @@ import com.maddyhome.idea.vim.newapi.vim | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * COMPATIBILITY-LAYER: Additional class |  * COMPATIBILITY-LAYER: Additional class | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  */ |  */ | ||||||
| class CommandState(private val machine: VimStateMachine) { | class CommandState(private val machine: VimStateMachine) { | ||||||
|  |  | ||||||
|   val isOperatorPending: Boolean |   val isOperatorPending: Boolean | ||||||
|     get() = machine.isOperatorPending |     get() = machine.isOperatorPending | ||||||
|  |  | ||||||
|  |   val mode: CommandState.Mode | ||||||
|  |     get() = machine.mode.ij | ||||||
|  |  | ||||||
|  |   val commandBuilder: CommandBuilder | ||||||
|  |     get() = machine.commandBuilder | ||||||
|  |  | ||||||
|  |   val mappingState: MappingState | ||||||
|  |     get() = machine.mappingState | ||||||
|  |  | ||||||
|   enum class Mode { |   enum class Mode { | ||||||
|     // Basic modes |     // Basic modes | ||||||
|     COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/ |     COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/ | ||||||
| @@ -50,7 +60,6 @@ class CommandState(private val machine: VimStateMachine) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| val CommandState.SubMode.engine: VimStateMachine.SubMode | val CommandState.SubMode.engine: VimStateMachine.SubMode | ||||||
|   get() = when (this) { |   get() = when (this) { | ||||||
|     CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE |     CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE | ||||||
| @@ -73,7 +82,6 @@ val CommandState.Mode.engine: VimStateMachine.Mode | |||||||
|     CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT |     CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| val VimStateMachine.Mode.ij: CommandState.Mode | val VimStateMachine.Mode.ij: CommandState.Mode | ||||||
|   get() = when (this) { |   get() = when (this) { | ||||||
|     VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND |     VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor | |||||||
| import com.maddyhome.idea.vim.KeyHandler | import com.maddyhome.idea.vim.KeyHandler | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.action.change.Extension | import com.maddyhome.idea.vim.action.change.Extension | ||||||
|  | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
| import com.maddyhome.idea.vim.common.CommandAlias | import com.maddyhome.idea.vim.common.CommandAlias | ||||||
| @@ -60,6 +61,7 @@ object VimExtensionFacade { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * COMPATIBILITY-LAYER: Additional method |    * COMPATIBILITY-LAYER: Additional method | ||||||
|  |    * Please see: https://jb.gg/zo8n0r | ||||||
|    */ |    */ | ||||||
|   /** The 'map' command for mapping keys to handlers defined in extensions. */ |   /** The 'map' command for mapping keys to handlers defined in extensions. */ | ||||||
|   @JvmStatic |   @JvmStatic | ||||||
| @@ -125,7 +127,7 @@ object VimExtensionFacade { | |||||||
|   /** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */ |   /** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */ | ||||||
|   @JvmStatic |   @JvmStatic | ||||||
|   fun setOperatorFunction(function: OperatorFunction) { |   fun setOperatorFunction(function: OperatorFunction) { | ||||||
|     VimPlugin.getKey().setOperatorFunction(function) |     VimPlugin.getKey().operatorFunction = function | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -182,12 +184,24 @@ object VimExtensionFacade { | |||||||
|     return reg.keys |     return reg.keys | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @JvmStatic | ||||||
|  |   fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? { | ||||||
|  |     val reg = caret.registerStorage.getRegister(caret, register) ?: return null | ||||||
|  |     return reg.keys | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** Set the current contents of the given register */ |   /** Set the current contents of the given register */ | ||||||
|   @JvmStatic |   @JvmStatic | ||||||
|   fun setRegister(register: Char, keys: List<KeyStroke?>?) { |   fun setRegister(register: Char, keys: List<KeyStroke?>?) { | ||||||
|     VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList()) |     VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList()) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** Set the current contents of the given register */ | ||||||
|  |   @JvmStatic | ||||||
|  |   fun setRegisterForCaret(register: Char, caret: VimCaret, keys: List<KeyStroke?>?) { | ||||||
|  |     caret.registerStorage.setKeys(caret, register, keys?.filterNotNull() ?: emptyList()) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** Set the current contents of the given register */ |   /** Set the current contents of the given register */ | ||||||
|   @JvmStatic |   @JvmStatic | ||||||
|   fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) { |   fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) { | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ import com.maddyhome.idea.vim.newapi.ij | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * COMPATIBILITY-LAYER: Created a class, renamed original class |  * COMPATIBILITY-LAYER: Created a class, renamed original class | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  */ |  */ | ||||||
| interface VimExtensionHandler : ExtensionHandler { | interface VimExtensionHandler : ExtensionHandler { | ||||||
|   override fun execute(editor: VimEditor, context: ExecutionContext) { |   override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|   | |||||||
| @@ -25,9 +25,9 @@ import com.maddyhome.idea.vim.api.VimExtensionRegistrator | |||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.ex.ExException | import com.maddyhome.idea.vim.ex.ExException | ||||||
| import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove | import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove | ||||||
|  | import com.maddyhome.idea.vim.option.ToggleOption | ||||||
| import com.maddyhome.idea.vim.options.OptionChangeListener | import com.maddyhome.idea.vim.options.OptionChangeListener | ||||||
| import com.maddyhome.idea.vim.options.OptionScope | import com.maddyhome.idea.vim.options.OptionScope | ||||||
| import com.maddyhome.idea.vim.option.ToggleOption |  | ||||||
| import com.maddyhome.idea.vim.statistic.PluginState | import com.maddyhome.idea.vim.statistic.PluginState | ||||||
| import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,10 +17,11 @@ | |||||||
|  */ |  */ | ||||||
| package com.maddyhome.idea.vim.extension.commentary | package com.maddyhome.idea.vim.extension.commentary | ||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.DataContext | import com.intellij.codeInsight.actions.AsyncActionExecutionService | ||||||
| import com.intellij.openapi.actionSystem.IdeActions | import com.intellij.openapi.actionSystem.IdeActions | ||||||
| import com.intellij.openapi.application.runWriteAction | import com.intellij.openapi.application.runWriteAction | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
|  | import com.intellij.openapi.util.Ref | ||||||
| import com.intellij.psi.PsiComment | import com.intellij.psi.PsiComment | ||||||
| import com.intellij.psi.PsiElement | import com.intellij.psi.PsiElement | ||||||
| import com.intellij.psi.PsiFile | import com.intellij.psi.PsiFile | ||||||
| @@ -34,13 +35,14 @@ import com.maddyhome.idea.vim.api.injector | |||||||
| import com.maddyhome.idea.vim.command.Argument | import com.maddyhome.idea.vim.command.Argument | ||||||
| import com.maddyhome.idea.vim.command.Command | import com.maddyhome.idea.vim.command.Command | ||||||
| import com.maddyhome.idea.vim.command.CommandFlags | import com.maddyhome.idea.vim.command.CommandFlags | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.MappingMode | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
| import com.maddyhome.idea.vim.command.TextObjectVisualType | import com.maddyhome.idea.vim.command.TextObjectVisualType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.CommandAliasHandler | import com.maddyhome.idea.vim.common.CommandAliasHandler | ||||||
| import com.maddyhome.idea.vim.command.MappingMode |  | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
| import com.maddyhome.idea.vim.ex.ranges.Ranges | import com.maddyhome.idea.vim.ex.ranges.Ranges | ||||||
|  | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand | import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | ||||||
| @@ -48,7 +50,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa | |||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler |  | ||||||
| import com.maddyhome.idea.vim.handler.TextObjectActionHandler | import com.maddyhome.idea.vim.handler.TextObjectActionHandler | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.PsiHelper | import com.maddyhome.idea.vim.helper.PsiHelper | ||||||
| @@ -56,20 +57,24 @@ import com.maddyhome.idea.vim.helper.vimStateMachine | |||||||
| import com.maddyhome.idea.vim.key.OperatorFunction | import com.maddyhome.idea.vim.key.OperatorFunction | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import com.maddyhome.idea.vim.newapi.vim |  | ||||||
| import java.util.* | import java.util.* | ||||||
|  |  | ||||||
| class CommentaryExtension : VimExtension { | class CommentaryExtension : VimExtension { | ||||||
|  |  | ||||||
|   companion object { |   companion object { | ||||||
|     fun doCommentary(editor: VimEditor, context: ExecutionContext, range: TextRange, selectionType: SelectionType, resetCaret: Boolean): Boolean { |     fun doCommentary( | ||||||
|  |       editor: VimEditor, | ||||||
|  |       context: ExecutionContext, | ||||||
|  |       range: TextRange, | ||||||
|  |       selectionType: SelectionType, | ||||||
|  |       resetCaret: Boolean, | ||||||
|  |     ): Boolean { | ||||||
|       val mode = editor.vimStateMachine.mode |       val mode = editor.vimStateMachine.mode | ||||||
|       if (mode !== VimStateMachine.Mode.VISUAL) { |       if (mode !== VimStateMachine.Mode.VISUAL) { | ||||||
|         editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset) |         editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset) | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       return runWriteAction { |       return runWriteAction { | ||||||
|         try { |  | ||||||
|         // Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action |         // Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action | ||||||
|         // isn't available |         // isn't available | ||||||
|         val actions = if (selectionType === SelectionType.LINE_WISE) { |         val actions = if (selectionType === SelectionType.LINE_WISE) { | ||||||
| @@ -78,9 +83,25 @@ class CommentaryExtension : VimExtension { | |||||||
|           listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE) |           listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|           injector.actionExecutor.executeAction(actions[0], context) || |         val res = Ref.create<Boolean>(true) | ||||||
|             injector.actionExecutor.executeAction(actions[1], context) |         AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[0], { | ||||||
|         } finally { |           res.set(injector.actionExecutor.executeAction(actions[0], context)) | ||||||
|  |         }, { afterCommenting(mode, editor, resetCaret, range) }) | ||||||
|  |         if (!res.get()) { | ||||||
|  |           AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[1], { | ||||||
|  |             res.set(injector.actionExecutor.executeAction(actions[1], context)) | ||||||
|  |           }, { afterCommenting(mode, editor, resetCaret, range) }) | ||||||
|  |         } | ||||||
|  |         res.get() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun afterCommenting( | ||||||
|  |       mode: VimStateMachine.Mode, | ||||||
|  |       editor: VimEditor, | ||||||
|  |       resetCaret: Boolean, | ||||||
|  |       range: TextRange, | ||||||
|  |     ) { | ||||||
|       // Remove the selection, if we added it |       // Remove the selection, if we added it | ||||||
|       if (mode !== VimStateMachine.Mode.VISUAL) { |       if (mode !== VimStateMachine.Mode.VISUAL) { | ||||||
|         editor.removeSelection() |         editor.removeSelection() | ||||||
| @@ -98,8 +119,6 @@ class CommentaryExtension : VimExtension { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   override fun getName() = "commentary" |   override fun getName() = "commentary" | ||||||
|  |  | ||||||
| @@ -112,7 +131,13 @@ class CommentaryExtension : VimExtension { | |||||||
|  |  | ||||||
|     putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("gc"), owner, plugCommentaryKeys, true) |     putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("gc"), owner, plugCommentaryKeys, true) | ||||||
|     putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcc"), owner, plugCommentaryLineKeys, true) |     putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcc"), owner, plugCommentaryLineKeys, true) | ||||||
|     putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcu"), owner, injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"), true) |     putKeyMappingIfMissing( | ||||||
|  |       MappingMode.N, | ||||||
|  |       injector.parser.parseKeys("gcu"), | ||||||
|  |       owner, | ||||||
|  |       injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"), | ||||||
|  |       true | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     // Previous versions of IdeaVim used different mappings to Vim's Commentary. Make sure everything works if someone |     // Previous versions of IdeaVim used different mappings to Vim's Commentary. Make sure everything works if someone | ||||||
|     // is still using the old mapping |     // is still using the old mapping | ||||||
| @@ -132,14 +157,19 @@ class CommentaryExtension : VimExtension { | |||||||
|   private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler { |   private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler { | ||||||
|     override val isRepeatable = true |     override val isRepeatable = true | ||||||
|  |  | ||||||
|  |     // In this operator we process selection by ourselves. This is necessary for rider, VIM-1758 | ||||||
|  |     override fun postProcessSelection(): Boolean { | ||||||
|  |       return false | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       setOperatorFunction(this) |       setOperatorFunction(this) | ||||||
|       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) |       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { |     override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { | ||||||
|       val range = VimPlugin.getMark().getChangeMarks(editor.vim) ?: return false |       val range = VimPlugin.getMark().getChangeMarks(editor) ?: return false | ||||||
|       return doCommentary(editor.vim, context.vim, range, selectionType, true) |       return doCommentary(editor, context, range, selectionType, true) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -174,7 +204,7 @@ class CommentaryExtension : VimExtension { | |||||||
|       context: ExecutionContext, |       context: ExecutionContext, | ||||||
|       count: Int, |       count: Int, | ||||||
|       rawCount: Int, |       rawCount: Int, | ||||||
|       argument: Argument? |       argument: Argument?, | ||||||
|     ): TextRange? { |     ): TextRange? { | ||||||
|  |  | ||||||
|       val nativeEditor = (editor as IjVimEditor).editor |       val nativeEditor = (editor as IjVimEditor).editor | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.extension.exchange | package com.maddyhome.idea.vim.extension.exchange | ||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.application.runWriteAction | import com.intellij.openapi.application.runWriteAction | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.editor.LogicalPosition | import com.intellij.openapi.editor.LogicalPosition | ||||||
| @@ -31,10 +30,11 @@ 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.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.SelectionType |  | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
|  | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
|  | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister | import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister | ||||||
| @@ -42,7 +42,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa | |||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler |  | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.fileSize | import com.maddyhome.idea.vim.helper.fileSize | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition | import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition | ||||||
| @@ -133,7 +132,7 @@ class VimExchangeExtension : VimExtension { | |||||||
|         val subMode = editor.subMode |         val subMode = editor.subMode | ||||||
|         // Leave visual mode to create selection marks |         // Leave visual mode to create selection marks | ||||||
|         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) |         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) | ||||||
|         Operator(true).apply(editor.ij, context.ij, SelectionType.fromSubMode(subMode)) |         Operator(true).apply(editor, context, SelectionType.fromSubMode(subMode)) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -147,7 +146,8 @@ class VimExchangeExtension : VimExtension { | |||||||
|       else -> error("Invalid SubMode: $this") |       else -> error("Invalid SubMode: $this") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { |     override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { | ||||||
|  |       val editor = vimEditor.ij | ||||||
|       fun highlightExchange(ex: Exchange): RangeHighlighter { |       fun highlightExchange(ex: Exchange): RangeHighlighter { | ||||||
|         val attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES) |         val attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES) | ||||||
|         val hlArea = when (ex.type) { |         val hlArea = when (ex.type) { | ||||||
|   | |||||||
| @@ -33,21 +33,21 @@ import com.maddyhome.idea.vim.api.injector | |||||||
| import com.maddyhome.idea.vim.command.Argument | import com.maddyhome.idea.vim.command.Argument | ||||||
| import com.maddyhome.idea.vim.command.Command | import com.maddyhome.idea.vim.command.Command | ||||||
| import com.maddyhome.idea.vim.command.CommandFlags | import com.maddyhome.idea.vim.command.CommandFlags | ||||||
|  | import com.maddyhome.idea.vim.command.MappingMode | ||||||
| import com.maddyhome.idea.vim.command.MotionType | import com.maddyhome.idea.vim.command.MotionType | ||||||
| import com.maddyhome.idea.vim.command.OperatorArguments | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.common.Direction | import com.maddyhome.idea.vim.common.Direction | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade | import com.maddyhome.idea.vim.extension.VimExtensionFacade | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler |  | ||||||
| import com.maddyhome.idea.vim.handler.Motion | import com.maddyhome.idea.vim.handler.Motion | ||||||
| import com.maddyhome.idea.vim.handler.MotionActionHandler | import com.maddyhome.idea.vim.handler.MotionActionHandler | ||||||
| import com.maddyhome.idea.vim.handler.toMotionOrError | import com.maddyhome.idea.vim.handler.toMotionOrError | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.PsiHelper | import com.maddyhome.idea.vim.helper.PsiHelper | ||||||
| import com.maddyhome.idea.vim.helper.vimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.helper.enumSetOf | import com.maddyhome.idea.vim.helper.enumSetOf | ||||||
|  | import com.maddyhome.idea.vim.helper.vimStateMachine | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import java.util.* | import java.util.* | ||||||
| @@ -233,7 +233,7 @@ private object FileTypePatterns { | |||||||
|     } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") { |     } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") { | ||||||
|       this.cMakePatterns |       this.cMakePatterns | ||||||
|     } else { |     } else { | ||||||
|       return null |       this.htmlPatterns | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,8 +29,8 @@ import com.maddyhome.idea.vim.VimPlugin | |||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.extension.nerdtree | |||||||
| import com.intellij.ide.projectView.ProjectView | import com.intellij.ide.projectView.ProjectView | ||||||
| import com.intellij.ide.projectView.impl.ProjectViewImpl | import com.intellij.ide.projectView.impl.ProjectViewImpl | ||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
|  | import com.intellij.openapi.actionSystem.ActionUpdateThread | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| import com.intellij.openapi.application.ApplicationManager | import com.intellij.openapi.application.ApplicationManager | ||||||
| @@ -44,18 +45,18 @@ import com.maddyhome.idea.vim.api.VimEditor | |||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.common.CommandAlias | import com.maddyhome.idea.vim.common.CommandAlias | ||||||
| import com.maddyhome.idea.vim.common.CommandAliasHandler | import com.maddyhome.idea.vim.common.CommandAliasHandler | ||||||
| import com.maddyhome.idea.vim.common.CommandNode |  | ||||||
| import com.maddyhome.idea.vim.common.CommandPartNode |  | ||||||
| import com.maddyhome.idea.vim.common.Node |  | ||||||
| import com.maddyhome.idea.vim.common.RootNode |  | ||||||
| import com.maddyhome.idea.vim.common.addLeafs |  | ||||||
| import com.maddyhome.idea.vim.ex.ranges.Ranges | import com.maddyhome.idea.vim.ex.ranges.Ranges | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.group.KeyGroup | import com.maddyhome.idea.vim.group.KeyGroup | ||||||
| import com.maddyhome.idea.vim.helper.MessageHelper | import com.maddyhome.idea.vim.helper.MessageHelper | ||||||
| import com.maddyhome.idea.vim.helper.runAfterGotFocus | import com.maddyhome.idea.vim.helper.runAfterGotFocus | ||||||
|  | import com.maddyhome.idea.vim.key.CommandNode | ||||||
|  | import com.maddyhome.idea.vim.key.CommandPartNode | ||||||
| import com.maddyhome.idea.vim.key.MappingOwner | import com.maddyhome.idea.vim.key.MappingOwner | ||||||
|  | import com.maddyhome.idea.vim.key.Node | ||||||
| import com.maddyhome.idea.vim.key.RequiredShortcut | import com.maddyhome.idea.vim.key.RequiredShortcut | ||||||
|  | import com.maddyhome.idea.vim.key.RootNode | ||||||
|  | import com.maddyhome.idea.vim.key.addLeafs | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString | ||||||
| @@ -172,7 +173,7 @@ class NerdTree : VimExtension { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   class ProjectViewListener(private val project: Project) : ToolWindowManagerListener { |   class ProjectViewListener(private val project: Project) : ToolWindowManagerListener { | ||||||
|     override fun toolWindowShown(id: String, toolWindow: ToolWindow) { |     override fun toolWindowShown(toolWindow: ToolWindow) { | ||||||
|       if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return |       if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return | ||||||
|  |  | ||||||
|       val dispatcher = NerdDispatcher.getInstance(project) |       val dispatcher = NerdDispatcher.getInstance(project) | ||||||
| @@ -242,6 +243,8 @@ class NerdTree : VimExtension { | |||||||
|       e.presentation.isEnabled = !speedSearchIsHere(project) |       e.presentation.isEnabled = !speedSearchIsHere(project) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override fun getActionUpdateThread() = ActionUpdateThread.EDT | ||||||
|  |  | ||||||
|     private fun speedSearchIsHere(project: Project): Boolean { |     private fun speedSearchIsHere(project: Project): Boolean { | ||||||
|       val component = ProjectView.getInstance(project).currentProjectViewPane.tree ?: return false |       val component = ProjectView.getInstance(project).currentProjectViewPane.tree ?: return false | ||||||
|       return SpeedSearchSupply.getSupply(component) != null |       return SpeedSearchSupply.getSupply(component) != null | ||||||
| @@ -342,7 +345,7 @@ class NerdTree : VimExtension { | |||||||
|         if (file.isDirectory) return@Code |         if (file.isDirectory) return@Code | ||||||
|         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters |         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters | ||||||
|         val currentWindow = splitters.currentWindow |         val currentWindow = splitters.currentWindow | ||||||
|         currentWindow.split(SwingConstants.HORIZONTAL, true, file, true) |         currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true) | ||||||
|       } |       } | ||||||
|     ) |     ) | ||||||
|     registerCommand( |     registerCommand( | ||||||
| @@ -351,7 +354,7 @@ class NerdTree : VimExtension { | |||||||
|         val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code |         val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code | ||||||
|         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters |         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters | ||||||
|         val currentWindow = splitters.currentWindow |         val currentWindow = splitters.currentWindow | ||||||
|         currentWindow.split(SwingConstants.VERTICAL, true, file, true) |         currentWindow?.split(SwingConstants.VERTICAL, true, file, true) | ||||||
|  |  | ||||||
|         // FIXME: 22.01.2021 This solution bouncing a bit |         // FIXME: 22.01.2021 This solution bouncing a bit | ||||||
|         callAction("ActivateProjectToolWindow", context.vim) |         callAction("ActivateProjectToolWindow", context.vim) | ||||||
| @@ -363,7 +366,7 @@ class NerdTree : VimExtension { | |||||||
|         val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code |         val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code | ||||||
|         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters |         val splitters = FileEditorManagerEx.getInstanceEx(project).splitters | ||||||
|         val currentWindow = splitters.currentWindow |         val currentWindow = splitters.currentWindow | ||||||
|         currentWindow.split(SwingConstants.HORIZONTAL, true, file, true) |         currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true) | ||||||
|  |  | ||||||
|         callAction("ActivateProjectToolWindow", context.vim) |         callAction("ActivateProjectToolWindow", context.vim) | ||||||
|       } |       } | ||||||
| @@ -560,7 +563,3 @@ class NerdTree : VimExtension { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| private fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) { |  | ||||||
|   addLeafs(injector.parser.parseKeys(keys), actionHolder) |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -24,10 +24,10 @@ import com.maddyhome.idea.vim.api.ExecutionContext | |||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
|  | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade | import com.maddyhome.idea.vim.extension.VimExtensionFacade | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler |  | ||||||
| import com.maddyhome.idea.vim.group.MotionGroup | import com.maddyhome.idea.vim.group.MotionGroup | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.SearchHelper | import com.maddyhome.idea.vim.helper.SearchHelper | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.extension.replacewithregister | package com.maddyhome.idea.vim.extension.replacewithregister | ||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| @@ -26,6 +25,7 @@ import com.maddyhome.idea.vim.api.VimCaret | |||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
|  | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.command.isLine | import com.maddyhome.idea.vim.command.isLine | ||||||
| @@ -38,8 +38,10 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissin | |||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||||||
| import com.maddyhome.idea.vim.group.visual.VimSelection | import com.maddyhome.idea.vim.group.visual.VimSelection | ||||||
| import com.maddyhome.idea.vim.helper.EditorDataContext | import com.maddyhome.idea.vim.helper.EditorDataContext | ||||||
|  | import com.maddyhome.idea.vim.helper.editorMode | ||||||
| import com.maddyhome.idea.vim.helper.mode | import com.maddyhome.idea.vim.helper.mode | ||||||
| import com.maddyhome.idea.vim.helper.subMode | import com.maddyhome.idea.vim.helper.subMode | ||||||
|  | import com.maddyhome.idea.vim.helper.vimStateMachine | ||||||
| import com.maddyhome.idea.vim.key.OperatorFunction | import com.maddyhome.idea.vim.key.OperatorFunction | ||||||
| import com.maddyhome.idea.vim.newapi.IjExecutionContext | import com.maddyhome.idea.vim.newapi.IjExecutionContext | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| @@ -65,15 +67,14 @@ class ReplaceWithRegister : VimExtension { | |||||||
|  |  | ||||||
|   private class RwrVisual : ExtensionHandler { |   private class RwrVisual : ExtensionHandler { | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       val caretsAndSelections = mutableMapOf<VimCaret, VimSelection>() |  | ||||||
|       val typeInEditor = SelectionType.fromSubMode(editor.subMode) |       val typeInEditor = SelectionType.fromSubMode(editor.subMode) | ||||||
|       editor.forEachCaret { caret -> |       editor.forEachCaret { caret -> | ||||||
|         val selectionStart = caret.selectionStart |         val selectionStart = caret.selectionStart | ||||||
|         val selectionEnd = caret.selectionEnd |         val selectionEnd = caret.selectionEnd | ||||||
|  |  | ||||||
|         caretsAndSelections += caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor) |         val visualSelection = caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor) | ||||||
|  |         doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), typeInEditor)) | ||||||
|       } |       } | ||||||
|       doReplace(editor.ij, PutData.VisualSelection(caretsAndSelections, typeInEditor)) |  | ||||||
|       editor.exitVisualModeNative() |       editor.exitVisualModeNative() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -97,11 +98,11 @@ class ReplaceWithRegister : VimExtension { | |||||||
|         val lineStart = editor.getLineStartOffset(logicalLine) |         val lineStart = editor.getLineStartOffset(logicalLine) | ||||||
|         val lineEnd = editor.getLineEndOffset(logicalLine, true) |         val lineEnd = editor.getLineEndOffset(logicalLine, true) | ||||||
|  |  | ||||||
|         caretsAndSelections += caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor) |         val visualSelection = caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor) | ||||||
|       } |         caretsAndSelections += visualSelection | ||||||
|  |  | ||||||
|       val visualSelection = PutData.VisualSelection(caretsAndSelections, SelectionType.LINE_WISE) |         doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), SelectionType.LINE_WISE)) | ||||||
|       doReplace(editor.ij, visualSelection) |       } | ||||||
|  |  | ||||||
|       editor.forEachCaret { caret -> |       editor.forEachCaret { caret -> | ||||||
|         val vimStart = caretsAndSelections[caret]?.vimStart |         val vimStart = caretsAndSelections[caret]?.vimStart | ||||||
| @@ -113,20 +114,22 @@ class ReplaceWithRegister : VimExtension { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private class Operator : OperatorFunction { |   private class Operator : OperatorFunction { | ||||||
|     override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { |     override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { | ||||||
|  |       val editor = (vimEditor as IjVimEditor).editor | ||||||
|       val range = getRange(editor) ?: return false |       val range = getRange(editor) ?: return false | ||||||
|       val visualSelection = PutData.VisualSelection( |       val visualSelection = PutData.VisualSelection( | ||||||
|         mapOf( |         mapOf( | ||||||
|           editor.caretModel.primaryCaret.vim to VimSelection.create( |           vimEditor.primaryCaret() to VimSelection.create( | ||||||
|             range.startOffset, |             range.startOffset, | ||||||
|             range.endOffset - 1, |             range.endOffset - 1, | ||||||
|             selectionType, |             selectionType, | ||||||
|             IjVimEditor(editor) |             vimEditor | ||||||
|           ) |           ) | ||||||
|         ), |         ), | ||||||
|         selectionType |         selectionType | ||||||
|       ) |       ) | ||||||
|       doReplace(editor, visualSelection) |       // todo multicaret | ||||||
|  |       doReplace(editor, vimEditor.primaryCaret(), visualSelection) | ||||||
|       return true |       return true | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -147,8 +150,9 @@ class ReplaceWithRegister : VimExtension { | |||||||
|     @NonNls |     @NonNls | ||||||
|     private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual" |     private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual" | ||||||
|  |  | ||||||
|     private fun doReplace(editor: Editor, visualSelection: PutData.VisualSelection) { |     private fun doReplace(editor: Editor, caret: VimCaret, visualSelection: PutData.VisualSelection) { | ||||||
|       val savedRegister = VimPlugin.getRegister().lastRegister ?: return |       val lastRegisterChar = injector.registerGroup.lastRegisterChar | ||||||
|  |       val savedRegister = caret.registerStorage.getRegister(caret, lastRegisterChar) ?: return | ||||||
|  |  | ||||||
|       var usedType = savedRegister.type |       var usedType = savedRegister.type | ||||||
|       var usedText = savedRegister.text |       var usedText = savedRegister.text | ||||||
| @@ -170,11 +174,19 @@ class ReplaceWithRegister : VimExtension { | |||||||
|         putToLine = -1 |         putToLine = -1 | ||||||
|       ) |       ) | ||||||
|       ClipboardOptionHelper.IdeaputDisabler().use { |       ClipboardOptionHelper.IdeaputDisabler().use { | ||||||
|         VimPlugin.getPut().putText(IjVimEditor(editor), IjExecutionContext(EditorDataContext.init(editor)), putData) |         VimPlugin.getPut().putText( | ||||||
|  |           IjVimEditor(editor), | ||||||
|  |           IjExecutionContext(EditorDataContext.init(editor)), | ||||||
|  |           putData, | ||||||
|  |           operatorArguments = OperatorArguments( | ||||||
|  |             editor.vimStateMachine?.isOperatorPending ?: false, | ||||||
|  |             0, editor.editorMode, editor.subMode | ||||||
|  |           ) | ||||||
|  |         ) | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister) |       caret.registerStorage.saveRegister(caret, savedRegister.name, savedRegister) | ||||||
|       VimPlugin.getRegister().saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister) |       caret.registerStorage.saveRegister(caret, VimPlugin.getRegister().defaultRegister, savedRegister) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,35 +17,37 @@ | |||||||
|  */ |  */ | ||||||
| package com.maddyhome.idea.vim.extension.surround | package com.maddyhome.idea.vim.extension.surround | ||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.application.runWriteAction | import com.intellij.openapi.application.runWriteAction | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
|  | import com.maddyhome.idea.vim.api.VimCaret | ||||||
|  | import com.maddyhome.idea.vim.api.VimChangeGroup | ||||||
| import com.maddyhome.idea.vim.api.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.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.SelectionType |  | ||||||
| import com.maddyhome.idea.vim.command.MappingMode | import com.maddyhome.idea.vim.command.MappingMode | ||||||
|  | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
|  | import com.maddyhome.idea.vim.extension.ExtensionHandler | ||||||
| import com.maddyhome.idea.vim.extension.VimExtension | import com.maddyhome.idea.vim.extension.VimExtension | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister | import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegisterForCaret | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke | import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString | import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret | ||||||
| import com.maddyhome.idea.vim.extension.ExtensionHandler |  | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper |  | ||||||
| import com.maddyhome.idea.vim.helper.editorMode | import com.maddyhome.idea.vim.helper.editorMode | ||||||
|  | import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore | ||||||
| import com.maddyhome.idea.vim.key.OperatorFunction | import com.maddyhome.idea.vim.key.OperatorFunction | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimCaret | import com.maddyhome.idea.vim.newapi.IjVimCaret | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper | import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper | ||||||
|  | import com.maddyhome.idea.vim.put.PutData | ||||||
| import org.jetbrains.annotations.NonNls | import org.jetbrains.annotations.NonNls | ||||||
| import java.awt.event.KeyEvent | import java.awt.event.KeyEvent | ||||||
| import javax.swing.KeyStroke | import javax.swing.KeyStroke | ||||||
| @@ -84,22 +86,20 @@ class VimSurroundExtension : VimExtension { | |||||||
|     override val isRepeatable = true |     override val isRepeatable = true | ||||||
|  |  | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       setOperatorFunction(Operator()) |       setOperatorFunction(Operator(supportsMultipleCursors = false)) // TODO | ||||||
|       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) |       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private class VSurroundHandler : ExtensionHandler { |   private class VSurroundHandler : ExtensionHandler { | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart |  | ||||||
|       // NB: Operator ignores SelectionType anyway |       // NB: Operator ignores SelectionType anyway | ||||||
|       if (!Operator().apply(editor.ij, context.ij, SelectionType.CHARACTER_WISE)) { |       if (!Operator(supportsMultipleCursors = true).apply(editor, context, SelectionType.CHARACTER_WISE)) { | ||||||
|         return |         return | ||||||
|       } |       } | ||||||
|       runWriteAction { |       runWriteAction { | ||||||
|         // Leave visual mode |         // Leave visual mode | ||||||
|         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) |         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) | ||||||
|         editor.ij.caretModel.moveToOffset(selectionStart) |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -115,33 +115,74 @@ class VimSurroundExtension : VimExtension { | |||||||
|       if (charTo.code == 0) return |       if (charTo.code == 0) return | ||||||
|  |  | ||||||
|       val newSurround = getOrInputPair(charTo, editor.ij) ?: return |       val newSurround = getOrInputPair(charTo, editor.ij) ?: return | ||||||
|       runWriteAction { change(editor.ij, charFrom, newSurround) } |       runWriteAction { change(editor, context, charFrom, newSurround) } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     companion object { |     companion object { | ||||||
|       fun change(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) { |       fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { | ||||||
|         // We take over the " register, so preserve it |         editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) } | ||||||
|         val oldValue: List<KeyStroke>? = getRegister(REGISTER) |  | ||||||
|         // Empty the " register |  | ||||||
|         setRegister(REGISTER, null) |  | ||||||
|         // Extract the inner value |  | ||||||
|         perform("di" + pick(charFrom), editor) |  | ||||||
|         val innerValue: MutableList<KeyStroke> = getRegister(REGISTER)?.toMutableList() ?: mutableListOf() |  | ||||||
|         // If the surrounding characters were not found, the register will be empty |  | ||||||
|         if (innerValue.isNotEmpty()) { |  | ||||||
|           // Delete the surrounding |  | ||||||
|           perform("da" + pick(charFrom), editor) |  | ||||||
|           // Insert the surrounding characters and paste |  | ||||||
|           if (newSurround != null) { |  | ||||||
|             innerValue.addAll(0, injector.parser.parseKeys(newSurround.first)) |  | ||||||
|             innerValue.addAll(injector.parser.parseKeys(newSurround.second)) |  | ||||||
|       } |       } | ||||||
|           pasteSurround(innerValue, editor) |        | ||||||
|           // Jump back to start |       fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { | ||||||
|           executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) |         // Save old register values for carets | ||||||
|  |         val surroundings = editor.sortedCarets() | ||||||
|  |           .map { | ||||||
|  |             val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it) | ||||||
|  |             setRegisterForCaret(REGISTER, it, null) | ||||||
|  |             SurroundingInfo(it, null, oldValue, null) | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |         // Delete surrounding's content | ||||||
|  |         perform("di" + pick(charFrom), editor.ij) | ||||||
|  |  | ||||||
|  |         // Add info about surrounding's inner text and location | ||||||
|  |         surroundings.forEach { | ||||||
|  |           val registerValue = getRegisterForCaret(REGISTER, it.caret) | ||||||
|  |           val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue | ||||||
|  |           it.innerText = innerValue | ||||||
|  |  | ||||||
|  |           val lineEndOffset = injector.engineEditorHelper.getLineEndOffset(editor, it.caret.getLine().line, false) | ||||||
|  |           if (lineEndOffset == it.caret.offset.point) { | ||||||
|  |             it.isLineEnd = true | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Remove surrounding | ||||||
|  |         perform("da" + pick(charFrom), editor.ij) | ||||||
|  |  | ||||||
|  |         surroundings.forEach { | ||||||
|  |           if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) { | ||||||
|  |             it.innerText = emptyList() | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           // caret should be placed at the first char of inserted text | ||||||
|  |           // the best solution would be using [ mark after the paste, but marks are not supported by multicaret | ||||||
|  |           // todo | ||||||
|  |           if (it.innerText != null) { | ||||||
|  |             it.offset = it.caret.offset.point | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         surroundings | ||||||
|  |           .filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding | ||||||
|  |           .map { surrounding -> | ||||||
|  |             val innerValue = injector.parser.toPrintableString(surrounding.innerText!!) | ||||||
|  |             val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue | ||||||
|  |             val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList()) | ||||||
|  |             val putData = PutData(textData, null, 1, insertTextBeforeCaret = !surrounding.isLineEnd, rawIndent = true, caretAfterInsertedText = false) | ||||||
|  |  | ||||||
|  |             surrounding.caret to putData | ||||||
|  |           }.forEach { | ||||||
|  |             injector.put.putTextForCaret(editor, it.first, context, it.second) | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |         surroundings.forEach { | ||||||
|  |           it.restoreRegister() | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (surroundings.size == 1) { | ||||||
|  |           surroundings.first().moveCaret() | ||||||
|         } |         } | ||||||
|         // Restore the old value |  | ||||||
|         setRegister(REGISTER, oldValue) |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       private fun perform(sequence: String, editor: Editor) { |       private fun perform(sequence: String, editor: Editor) { | ||||||
| @@ -149,21 +190,6 @@ class VimSurroundExtension : VimExtension { | |||||||
|           .use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) } |           .use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       private fun pasteSurround( |  | ||||||
|         innerValue: List<KeyStroke?>, |  | ||||||
|         editor: Editor, |  | ||||||
|       ) { // This logic is direct from vim-surround |  | ||||||
|         val offset = editor.caretModel.offset |  | ||||||
|         val lineEndOffset = EditorHelper.getLineEndForOffset(editor, offset) |  | ||||||
|         val motionEndMark = VimPlugin.getMark().getMark(editor.vim, ']') |  | ||||||
|         val motionEndOffset = if (motionEndMark != null) { |  | ||||||
|           EditorHelper.getOffset(editor, motionEndMark.logicalLine, motionEndMark.col) |  | ||||||
|         } else -1 |  | ||||||
|         val pasteCommand = if (motionEndOffset == lineEndOffset && offset + 1 == lineEndOffset) "p" else "P" |  | ||||||
|         setRegister(REGISTER, innerValue) |  | ||||||
|         perform(pasteCommand, editor) |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       private fun pick(charFrom: Char) = when (charFrom) { |       private fun pick(charFrom: Char) = when (charFrom) { | ||||||
|         'a' -> '>' |         'a' -> '>' | ||||||
|         'r' -> ']' |         'r' -> ']' | ||||||
| @@ -172,6 +198,18 @@ class VimSurroundExtension : VimExtension { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var offset: Int?, var isLineEnd: Boolean = false) { | ||||||
|  |     fun restoreRegister() { | ||||||
|  |       setRegisterForCaret(REGISTER, caret, oldRegisterContent) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun moveCaret() { | ||||||
|  |       if (innerText != null && offset != null) { | ||||||
|  |         caret.moveToOffset(offset!! + if (isLineEnd) 1 else 0) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   private class DSurroundHandler : ExtensionHandler { |   private class DSurroundHandler : ExtensionHandler { | ||||||
|     override val isRepeatable = true |     override val isRepeatable = true | ||||||
|  |  | ||||||
| @@ -180,30 +218,49 @@ class VimSurroundExtension : VimExtension { | |||||||
|       val charFrom = getChar(editor.ij) |       val charFrom = getChar(editor.ij) | ||||||
|       if (charFrom.code == 0) return |       if (charFrom.code == 0) return | ||||||
|  |  | ||||||
|       runWriteAction { CSurroundHandler.change(editor.ij, charFrom, null) } |       runWriteAction { CSurroundHandler.change(editor, context, charFrom, null) } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private class Operator : OperatorFunction { |   private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction { | ||||||
|     override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { |     override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { | ||||||
|  |       val editor = vimEditor.ij | ||||||
|       val c = getChar(editor) |       val c = getChar(editor) | ||||||
|       if (c.code == 0) return true |       if (c.code == 0) return true | ||||||
|  |  | ||||||
|       val pair = getOrInputPair(c, editor) ?: return false |       val pair = getOrInputPair(c, editor) ?: return false | ||||||
|       // XXX: Will it work with line-wise or block-wise selections? |  | ||||||
|       val range = getSurroundRange(editor) ?: return false |  | ||||||
|       runWriteAction { |       runWriteAction { | ||||||
|         val change = VimPlugin.getChange() |         val change = VimPlugin.getChange() | ||||||
|         val leftSurround = pair.first |         if (supportsMultipleCursors) { | ||||||
|         val primaryCaret = editor.caretModel.primaryCaret |           editor.runWithEveryCaretAndRestore { | ||||||
|         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, leftSurround) |             applyOnce(editor, change, pair) | ||||||
|         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + leftSurround.length, pair.second) |           } | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |           applyOnce(editor, change, pair) | ||||||
|           // Jump back to start |           // Jump back to start | ||||||
|           executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) |           executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|       return true |       return true | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>) { | ||||||
|  |       // XXX: Will it work with line-wise or block-wise selections? | ||||||
|  |       val range = getSurroundRange(editor) | ||||||
|  |       if (range != null) { | ||||||
|  |         val primaryCaret = editor.caretModel.primaryCaret | ||||||
|  |         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, pair.first) | ||||||
|  |         change.insertText( | ||||||
|  |           IjVimEditor(editor), | ||||||
|  |           IjVimCaret(primaryCaret), | ||||||
|  |           range.endOffset + pair.first.length, | ||||||
|  |           pair.second | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) { |     private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) { | ||||||
|       VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim) |       VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim) | ||||||
|       VimStateMachine.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) } |       VimStateMachine.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) } | ||||||
|   | |||||||
| @@ -20,7 +20,10 @@ package com.maddyhome.idea.vim.group; | |||||||
| import com.google.common.base.Splitter; | import com.google.common.base.Splitter; | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||||
|  | import com.intellij.codeInsight.actions.AsyncActionExecutionService; | ||||||
|  | import com.intellij.openapi.Disposable; | ||||||
| import com.intellij.openapi.actionSystem.DataContext; | import com.intellij.openapi.actionSystem.DataContext; | ||||||
|  | import com.intellij.openapi.actionSystem.IdeActions; | ||||||
| import com.intellij.openapi.application.ApplicationManager; | import com.intellij.openapi.application.ApplicationManager; | ||||||
| import com.intellij.openapi.command.CommandProcessor; | import com.intellij.openapi.command.CommandProcessor; | ||||||
| import com.intellij.openapi.command.UndoConfirmationPolicy; | import com.intellij.openapi.command.UndoConfirmationPolicy; | ||||||
| @@ -33,6 +36,9 @@ import com.intellij.openapi.editor.event.EditorMouseEvent; | |||||||
| import com.intellij.openapi.editor.event.EditorMouseListener; | import com.intellij.openapi.editor.event.EditorMouseListener; | ||||||
| import com.intellij.openapi.editor.impl.TextRangeInterval; | import com.intellij.openapi.editor.impl.TextRangeInterval; | ||||||
| import com.intellij.openapi.project.Project; | import com.intellij.openapi.project.Project; | ||||||
|  | import com.intellij.openapi.ui.MessageType; | ||||||
|  | import com.intellij.openapi.ui.popup.Balloon; | ||||||
|  | import com.intellij.openapi.ui.popup.JBPopupFactory; | ||||||
| import com.intellij.openapi.util.text.StringUtil; | import com.intellij.openapi.util.text.StringUtil; | ||||||
| import com.intellij.psi.PsiFile; | import com.intellij.psi.PsiFile; | ||||||
| import com.intellij.psi.codeStyle.CodeStyleManager; | import com.intellij.psi.codeStyle.CodeStyleManager; | ||||||
| @@ -48,13 +54,19 @@ import com.maddyhome.idea.vim.ex.ranges.LineRange; | |||||||
| import com.maddyhome.idea.vim.group.visual.VimSelection; | import com.maddyhome.idea.vim.group.visual.VimSelection; | ||||||
| import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt; | import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt; | ||||||
| import com.maddyhome.idea.vim.helper.*; | import com.maddyhome.idea.vim.helper.*; | ||||||
|  | import com.maddyhome.idea.vim.icons.VimIcons; | ||||||
| import com.maddyhome.idea.vim.key.KeyHandlerKeeper; | import com.maddyhome.idea.vim.key.KeyHandlerKeeper; | ||||||
| import com.maddyhome.idea.vim.listener.VimInsertListener; | import com.maddyhome.idea.vim.listener.VimInsertListener; | ||||||
| import com.maddyhome.idea.vim.newapi.*; | import com.maddyhome.idea.vim.newapi.IjExecutionContext; | ||||||
|  | import com.maddyhome.idea.vim.newapi.IjExecutionContextKt; | ||||||
|  | import com.maddyhome.idea.vim.newapi.IjVimCaret; | ||||||
|  | import com.maddyhome.idea.vim.newapi.IjVimEditor; | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants; | import com.maddyhome.idea.vim.options.OptionConstants; | ||||||
| import com.maddyhome.idea.vim.options.OptionScope; | import com.maddyhome.idea.vim.options.OptionScope; | ||||||
| import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString; | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString; | ||||||
| import kotlin.Pair; | import kotlin.Pair; | ||||||
|  | import kotlin.Unit; | ||||||
|  | import kotlin.jvm.functions.Function0; | ||||||
| import kotlin.text.StringsKt; | import kotlin.text.StringsKt; | ||||||
| import org.jetbrains.annotations.NonNls; | import org.jetbrains.annotations.NonNls; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| @@ -85,6 +97,8 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|  |  | ||||||
|   private final List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList(); |   private final List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList(); | ||||||
|  |  | ||||||
|  |   private long lastShownTime = 0L; | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Inserts a new line above the caret position |    * Inserts a new line above the caret position | ||||||
|    * |    * | ||||||
| @@ -142,14 +156,12 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   @Override |   public void editorCreated(Editor editor, @NotNull Disposable disposable) { | ||||||
|   public void editorCreated(VimEditor editor) { |     EventFacade.getInstance().addEditorMouseListener(editor, listener, disposable); | ||||||
|     EventFacade.getInstance().addEditorMouseListener(((IjVimEditor) editor).getEditor(), listener); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   public void editorReleased(Editor editor) { | ||||||
|   public void editorReleased(VimEditor editor) { |     EventFacade.getInstance().removeEditorMouseListener(editor, listener); | ||||||
|     EventFacade.getInstance().removeEditorMouseListener(((IjVimEditor) editor).getEditor(), listener); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -245,7 +257,7 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|         final boolean lastWordChar = |         final boolean lastWordChar = | ||||||
|           offset >= fileSize - 1 || CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType; |           offset >= fileSize - 1 || CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType; | ||||||
|         if (wordMotions.contains(id) && lastWordChar && motion.getCount() == 1) { |         if (wordMotions.contains(id) && lastWordChar && motion.getCount() == 1) { | ||||||
|           final boolean res = deleteCharacter(editor, caret, 1, true); |           final boolean res = deleteCharacter(editor, caret, 1, true, operatorArguments); | ||||||
|           if (res) { |           if (res) { | ||||||
|             editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT); |             editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT); | ||||||
|           } |           } | ||||||
| @@ -306,7 +318,8 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|       Pair<TextRange, SelectionType> deleteRangeAndType = |       Pair<TextRange, SelectionType> deleteRangeAndType = | ||||||
|         getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0)); |         getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0)); | ||||||
|       if (deleteRangeAndType == null) return false; |       if (deleteRangeAndType == null) return false; | ||||||
|       return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context); |       return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context, | ||||||
|  |                          operatorArguments); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -429,6 +442,7 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|    * @param caret             The caret to be moved after range deletion |    * @param caret             The caret to be moved after range deletion | ||||||
|    * @param range             The range to change |    * @param range             The range to change | ||||||
|    * @param type              The type of the range |    * @param type              The type of the range | ||||||
|  |    * @param operatorArguments | ||||||
|    * @return true if able to delete the range, false if not |    * @return true if able to delete the range, false if not | ||||||
|    */ |    */ | ||||||
|   @Override |   @Override | ||||||
| @@ -436,7 +450,8 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|                              @NotNull VimCaret caret, |                              @NotNull VimCaret caret, | ||||||
|                              @NotNull TextRange range, |                              @NotNull TextRange range, | ||||||
|                              @NotNull SelectionType type, |                              @NotNull SelectionType type, | ||||||
|                              ExecutionContext context) { |                              @Nullable ExecutionContext context, | ||||||
|  |                              @NotNull OperatorArguments operatorArguments) { | ||||||
|     int col = 0; |     int col = 0; | ||||||
|     int lines = 0; |     int lines = 0; | ||||||
|     if (type == SelectionType.BLOCK_WISE) { |     if (type == SelectionType.BLOCK_WISE) { | ||||||
| @@ -450,7 +465,7 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|  |  | ||||||
|     final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret)); |     final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret)); | ||||||
|  |  | ||||||
|     boolean res = deleteRange(editor, caret, range, type, true); |     boolean res = deleteRange(editor, caret, range, type, true, operatorArguments); | ||||||
|     if (res) { |     if (res) { | ||||||
|       if (type == SelectionType.LINE_WISE) { |       if (type == SelectionType.LINE_WISE) { | ||||||
|         // Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String |         // Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String | ||||||
| @@ -568,17 +583,31 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|     final int startOffset = injector.getEngineEditorHelper().getLineStartForOffset(editor, range.getStartOffset()); |     final int startOffset = injector.getEngineEditorHelper().getLineStartForOffset(editor, range.getStartOffset()); | ||||||
|     final int endOffset = injector.getEngineEditorHelper().getLineEndForOffset(editor, range.getEndOffset()); |     final int endOffset = injector.getEngineEditorHelper().getLineEndForOffset(editor, range.getEndOffset()); | ||||||
|  |  | ||||||
|     VisualModeHelperKt.vimSetSystemSelectionSilently(((IjVimEditor) editor).getEditor().getSelectionModel(), startOffset, endOffset); |     Editor ijEditor = ((IjVimEditor)editor).getEditor(); | ||||||
|  |     VisualModeHelperKt.vimSetSystemSelectionSilently(ijEditor.getSelectionModel(), startOffset, endOffset); | ||||||
|  |  | ||||||
|  |     Project project = ijEditor.getProject(); | ||||||
|  |     Function0<Unit> actionExecution = () -> { | ||||||
|       NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines(); |       NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines(); | ||||||
|       if (joinLinesAction != null) { |       if (joinLinesAction != null) { | ||||||
|         VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context); |         VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context); | ||||||
|       } |       } | ||||||
|  |       return null; | ||||||
|  |     }; | ||||||
|  |     Function0<Unit> afterAction = () -> { | ||||||
|       final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine(); |       final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine(); | ||||||
|       final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine); |       final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine); | ||||||
|       injector.getMotion().moveCaret(editor, caret, newOffset); |       injector.getMotion().moveCaret(editor, caret, newOffset); | ||||||
|     restoreCursor(editor, caret, ((IjVimCaret) caret).getCaret().getLogicalPosition().line); |       restoreCursor(editor, caret, ((IjVimCaret)caret).getCaret().getLogicalPosition().line); | ||||||
|  |       return null; | ||||||
|  |     }; | ||||||
|  |     if (project != null) { | ||||||
|  |       AsyncActionExecutionService.Companion.getInstance(project) | ||||||
|  |         .withExecutionAfterAction(IdeActions.ACTION_EDITOR_AUTO_INDENT_LINES, actionExecution, afterAction); | ||||||
|  |     } else { | ||||||
|  |       actionExecution.invoke(); | ||||||
|  |       afterAction.invoke(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -586,10 +615,11 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|                           @NotNull VimCaret caret, |                           @NotNull VimCaret caret, | ||||||
|                           @NotNull ExecutionContext context, |                           @NotNull ExecutionContext context, | ||||||
|                           int lines, |                           int lines, | ||||||
|                           int dir) { |                           int dir, | ||||||
|  |                           @NotNull OperatorArguments operatorArguments) { | ||||||
|     int start = ((IjVimCaret) caret).getCaret().getOffset(); |     int start = ((IjVimCaret) caret).getCaret().getOffset(); | ||||||
|     int end = VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret, lines - 1, true); |     int end = VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret, lines - 1, true); | ||||||
|     indentRange(editor, caret, context, new TextRange(start, end), 1, dir); |     indentRange(editor, caret, context, new TextRange(start, end), 1, dir, operatorArguments); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -602,7 +632,7 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|     final TextRange range = |     final TextRange range = | ||||||
|       injector.getMotion().getMotionRange(editor, caret, context, argument, operatorArguments); |       injector.getMotion().getMotionRange(editor, caret, context, argument, operatorArguments); | ||||||
|     if (range != null) { |     if (range != null) { | ||||||
|       indentRange(editor, caret, context, range, 1, dir); |       indentRange(editor, caret, context, range, 1, dir, operatorArguments); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -629,7 +659,8 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|                           @NotNull ExecutionContext context, |                           @NotNull ExecutionContext context, | ||||||
|                           @NotNull TextRange range, |                           @NotNull TextRange range, | ||||||
|                           int count, |                           int count, | ||||||
|                           int dir) { |                           int dir, | ||||||
|  |                           @NotNull OperatorArguments operatorArguments) { | ||||||
|     if (logger.isDebugEnabled()) { |     if (logger.isDebugEnabled()) { | ||||||
|       logger.debug("count=" + count); |       logger.debug("count=" + count); | ||||||
|     } |     } | ||||||
| @@ -675,7 +706,7 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|               } |               } | ||||||
|             } |             } | ||||||
|             if (pos > wsoff) { |             if (pos > wsoff) { | ||||||
|               deleteText(editor, new TextRange(wsoff, pos), null); |               deleteText(editor, new TextRange(wsoff, pos), null, caret, operatorArguments); | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @@ -768,6 +799,23 @@ public class ChangeGroup extends VimChangeGroupBase { | |||||||
|                                         @NotNull TextRange selectedRange, |                                         @NotNull TextRange selectedRange, | ||||||
|                                         final int count, |                                         final int count, | ||||||
|                                         boolean avalanche) { |                                         boolean avalanche) { | ||||||
|  |  | ||||||
|  |     // Just an easter egg | ||||||
|  |     if (avalanche) { | ||||||
|  |       long currentTime = System.currentTimeMillis(); | ||||||
|  |       if (currentTime - lastShownTime > 60_000) { | ||||||
|  |         lastShownTime = currentTime; | ||||||
|  |         ApplicationManager.getApplication().invokeLater(() -> { | ||||||
|  |           final Balloon balloon = JBPopupFactory.getInstance() | ||||||
|  |             .createHtmlTextBalloonBuilder("Wow, nice vim skills!", VimIcons.IDEAVIM, | ||||||
|  |                                           MessageType.INFO.getTitleForeground(), MessageType.INFO.getPopupBackground(), | ||||||
|  |                                           null).createBalloon(); | ||||||
|  |           balloon.show(JBPopupFactory.getInstance().guessBestPopupLocation(((IjVimEditor)editor).getEditor()), | ||||||
|  |                        Balloon.Position.below); | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     String nf = ((VimString) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(editor), OptionConstants.nrformatsName, OptionConstants.nrformatsName)).getValue(); |     String nf = ((VimString) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(editor), OptionConstants.nrformatsName, OptionConstants.nrformatsName)).getValue(); | ||||||
|     boolean alpha = nf.contains("alpha"); |     boolean alpha = nf.contains("alpha"); | ||||||
|     boolean hex = nf.contains("hex"); |     boolean hex = nf.contains("hex"); | ||||||
|   | |||||||
| @@ -232,7 +232,7 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor | |||||||
|       KeyHandler.getInstance().reset(new IjVimEditor(editor)); |       KeyHandler.getInstance().reset(new IjVimEditor(editor)); | ||||||
|     } |     } | ||||||
|     updateCaretsVisualAttributes(editor); |     updateCaretsVisualAttributes(editor); | ||||||
|     editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE); |     //editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public void editorDeinit(@NotNull Editor editor, boolean isReleased) { |   public void editorDeinit(@NotNull Editor editor, boolean isReleased) { | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.group; | |||||||
|  |  | ||||||
| import com.intellij.openapi.actionSystem.DataContext; | import com.intellij.openapi.actionSystem.DataContext; | ||||||
| import com.intellij.openapi.actionSystem.PlatformDataKeys; | import com.intellij.openapi.actionSystem.PlatformDataKeys; | ||||||
|  | import com.intellij.openapi.application.ApplicationManager; | ||||||
| import com.intellij.openapi.diagnostic.Logger; | import com.intellij.openapi.diagnostic.Logger; | ||||||
| import com.intellij.openapi.editor.Document; | import com.intellij.openapi.editor.Document; | ||||||
| import com.intellij.openapi.editor.Editor; | import com.intellij.openapi.editor.Editor; | ||||||
| @@ -27,6 +28,7 @@ import com.intellij.openapi.editor.LogicalPosition; | |||||||
| import com.intellij.openapi.fileEditor.*; | import com.intellij.openapi.fileEditor.*; | ||||||
| import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; | ||||||
| import com.intellij.openapi.fileEditor.impl.EditorWindow; | import com.intellij.openapi.fileEditor.impl.EditorWindow; | ||||||
|  | import com.intellij.openapi.fileEditor.impl.EditorsSplitters; | ||||||
| import com.intellij.openapi.fileTypes.FileType; | import com.intellij.openapi.fileTypes.FileType; | ||||||
| import com.intellij.openapi.fileTypes.FileTypeManager; | import com.intellij.openapi.fileTypes.FileTypeManager; | ||||||
| import com.intellij.openapi.project.Project; | import com.intellij.openapi.project.Project; | ||||||
| @@ -159,6 +161,10 @@ public class FileGroup extends VimFileBase { | |||||||
|       if (virtualFile != null && window != null) { |       if (virtualFile != null && window != null) { | ||||||
|         window.closeFile(virtualFile); |         window.closeFile(virtualFile); | ||||||
|       } |       } | ||||||
|  |       if (!ApplicationManager.getApplication().isUnitTestMode()) { | ||||||
|  |         // This thing doesn't have an implementation in test mode | ||||||
|  |         EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -175,6 +181,10 @@ public class FileGroup extends VimFileBase { | |||||||
|     if (number >= 0 && number < editors.length) { |     if (number >= 0 && number < editors.length) { | ||||||
|       fileEditorManager.closeFile(editors[number], window); |       fileEditorManager.closeFile(editors[number], window); | ||||||
|     } |     } | ||||||
|  |     if (!ApplicationManager.getApplication().isUnitTestMode()) { | ||||||
|  |       // This thing doesn't have an implementation in test mode | ||||||
|  |       EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ class IjVimStorageService : VimStorageServiceBase() { | |||||||
|     editor.ij.putUserData(getOrCreateIjKey(key), data) |     editor.ij.putUserData(getOrCreateIjKey(key), data) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Suppress("UNCHECKED_CAST") | ||||||
|   override fun <T> getDataFromBuffer(editor: VimEditor, key: com.maddyhome.idea.vim.api.Key<T>): T? { |   override fun <T> getDataFromBuffer(editor: VimEditor, key: com.maddyhome.idea.vim.api.Key<T>): T? { | ||||||
|     val buffer = EditorHelper.getVirtualFile(editor.ij)?.path ?: "empty path" |     val buffer = EditorHelper.getVirtualFile(editor.ij)?.path ?: "empty path" | ||||||
|     return bufferToKey[buffer]?.get(key.name) as T? |     return bufferToKey[buffer]?.get(key.name) as T? | ||||||
| @@ -60,6 +61,7 @@ class IjVimStorageService : VimStorageServiceBase() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private val ijKeys = mutableMapOf<String, Key<out Any?>>() |   private val ijKeys = mutableMapOf<String, Key<out Any?>>() | ||||||
|  |   @Suppress("UNCHECKED_CAST") | ||||||
|   private fun <T> getOrCreateIjKey(key: com.maddyhome.idea.vim.api.Key<T>): Key<T> { |   private fun <T> getOrCreateIjKey(key: com.maddyhome.idea.vim.api.Key<T>): Key<T> { | ||||||
|     val storedIjKey = ijKeys[key.name] |     val storedIjKey = ijKeys[key.name] | ||||||
|     if (storedIjKey != null) { |     if (storedIjKey != null) { | ||||||
|   | |||||||
| @@ -38,8 +38,7 @@ import com.maddyhome.idea.vim.action.ComplicatedKeysAction; | |||||||
| import com.maddyhome.idea.vim.action.VimShortcutKeyAction; | import com.maddyhome.idea.vim.action.VimShortcutKeyAction; | ||||||
| import com.maddyhome.idea.vim.api.*; | import com.maddyhome.idea.vim.api.*; | ||||||
| import com.maddyhome.idea.vim.command.MappingMode; | import com.maddyhome.idea.vim.command.MappingMode; | ||||||
| import com.maddyhome.idea.vim.common.Node; | import com.maddyhome.idea.vim.key.Node; | ||||||
| import com.maddyhome.idea.vim.common.NodesKt; |  | ||||||
| import com.maddyhome.idea.vim.ex.ExOutputModel; | import com.maddyhome.idea.vim.ex.ExOutputModel; | ||||||
| import com.maddyhome.idea.vim.handler.EditorActionHandlerBase; | import com.maddyhome.idea.vim.handler.EditorActionHandlerBase; | ||||||
| import com.maddyhome.idea.vim.helper.HelperKt; | import com.maddyhome.idea.vim.helper.HelperKt; | ||||||
| @@ -74,8 +73,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen | |||||||
|  |  | ||||||
|   private static final Logger logger = Logger.getInstance(KeyGroup.class); |   private static final Logger logger = Logger.getInstance(KeyGroup.class); | ||||||
|  |  | ||||||
|   private @Nullable OperatorFunction operatorFunction = null; |  | ||||||
|  |  | ||||||
|   public void registerRequiredShortcutKeys(@NotNull VimEditor editor) { |   public void registerRequiredShortcutKeys(@NotNull VimEditor editor) { | ||||||
|     EventFacade.getInstance() |     EventFacade.getInstance() | ||||||
|       .registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()), |       .registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()), | ||||||
| @@ -120,14 +117,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public @Nullable OperatorFunction getOperatorFunction() { |  | ||||||
|     return operatorFunction; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void setOperatorFunction(@NotNull OperatorFunction function) { |  | ||||||
|     operatorFunction = function; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void saveData(@NotNull Element element) { |   public void saveData(@NotNull Element element) { | ||||||
|     final Element conflictsElement = new Element(SHORTCUT_CONFLICTS_ELEMENT); |     final Element conflictsElement = new Element(SHORTCUT_CONFLICTS_ELEMENT); | ||||||
|     for (Map.Entry<KeyStroke, ShortcutOwnerInfo> entry : myShortcutConflicts.entrySet()) { |     for (Map.Entry<KeyStroke, ShortcutOwnerInfo> entry : myShortcutConflicts.entrySet()) { | ||||||
|   | |||||||
| @@ -108,7 +108,9 @@ public class MacroGroup extends VimMacroBase { | |||||||
|               KeyHandler.getInstance().handleKey(editor, key, context); |               KeyHandler.getInstance().handleKey(editor, key, context); | ||||||
|             }); |             }); | ||||||
|           } |           } | ||||||
|  |           keyStack.resetFirst(); | ||||||
|         } |         } | ||||||
|  |         keyStack.removeFirst(); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -411,6 +411,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * COMPATIBILITY-LAYER: Method added |    * COMPATIBILITY-LAYER: Method added | ||||||
|  |    * Please see: <a href="https://jb.gg/zo8n0r">doc</a> | ||||||
|    * |    * | ||||||
|    * @deprecated Please use method with VimEditor |    * @deprecated Please use method with VimEditor | ||||||
|    */ |    */ | ||||||
|   | |||||||
| @@ -23,8 +23,10 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; | |||||||
| import com.intellij.openapi.fileEditor.FileEditor; | import com.intellij.openapi.fileEditor.FileEditor; | ||||||
| import com.intellij.openapi.fileEditor.FileEditorManagerEvent; | import com.intellij.openapi.fileEditor.FileEditorManagerEvent; | ||||||
| import com.intellij.openapi.fileEditor.TextEditor; | import com.intellij.openapi.fileEditor.TextEditor; | ||||||
|  | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; | ||||||
| import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer; | import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer; | ||||||
| import com.intellij.openapi.fileEditor.impl.EditorWindow; | import com.intellij.openapi.fileEditor.impl.EditorWindow; | ||||||
|  | import com.intellij.openapi.project.Project; | ||||||
| import com.intellij.openapi.vfs.LocalFileSystem; | import com.intellij.openapi.vfs.LocalFileSystem; | ||||||
| import com.intellij.openapi.vfs.VirtualFile; | import com.intellij.openapi.vfs.VirtualFile; | ||||||
| import com.intellij.openapi.vfs.VirtualFileManager; | import com.intellij.openapi.vfs.VirtualFileManager; | ||||||
| @@ -1168,15 +1170,25 @@ public class MotionGroup extends VimMotionGroupBase { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public int moveCaretGotoPreviousTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { |   public int moveCaretGotoPreviousTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { | ||||||
|     switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), rawCount >= 1 ? -rawCount : -1, false); |     Project project = ((IjVimEditor)editor).getEditor().getProject(); | ||||||
|  |     if (project == null) { | ||||||
|  |       return editor.currentCaret().getOffset().getPoint(); | ||||||
|  |     } | ||||||
|  |     EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow(); | ||||||
|  |     switchEditorTab(currentWindow, rawCount >= 1 ? -rawCount : -1, false); | ||||||
|     return editor.currentCaret().getOffset().getPoint(); |     return editor.currentCaret().getOffset().getPoint(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public int moveCaretGotoNextTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { |   public int moveCaretGotoNextTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) { | ||||||
|     final boolean absolute = rawCount >= 1; |     final boolean absolute = rawCount >= 1; | ||||||
|     switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), absolute ? rawCount - 1 : 1, |  | ||||||
|                     absolute); |     Project project = ((IjVimEditor)editor).getEditor().getProject(); | ||||||
|  |     if (project == null) { | ||||||
|  |       return editor.currentCaret().getOffset().getPoint(); | ||||||
|  |     } | ||||||
|  |     EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow(); | ||||||
|  |     switchEditorTab(currentWindow, absolute ? rawCount - 1 : 1, absolute); | ||||||
|     return editor.currentCaret().getOffset().getPoint(); |     return editor.currentCaret().getOffset().getPoint(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,26 +20,24 @@ package com.maddyhome.idea.vim.group | |||||||
|  |  | ||||||
| import com.intellij.icons.AllIcons | import com.intellij.icons.AllIcons | ||||||
| import com.intellij.ide.BrowserUtil | import com.intellij.ide.BrowserUtil | ||||||
| import com.intellij.ide.IdeBundle |  | ||||||
| import com.intellij.ide.actions.OpenFileAction | import com.intellij.ide.actions.OpenFileAction | ||||||
| import com.intellij.ide.actions.RevealFileAction | import com.intellij.ide.actions.RevealFileAction | ||||||
|  | import com.intellij.notification.ActionCenter | ||||||
| import com.intellij.notification.Notification | import com.intellij.notification.Notification | ||||||
| import com.intellij.notification.NotificationGroup | import com.intellij.notification.NotificationGroup | ||||||
| import com.intellij.notification.NotificationGroupManager | import com.intellij.notification.NotificationGroupManager | ||||||
| import com.intellij.notification.NotificationListener |  | ||||||
| import com.intellij.notification.NotificationType | import com.intellij.notification.NotificationType | ||||||
|  | import com.intellij.openapi.actionSystem.ActionUpdateThread | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.KeyboardShortcut | import com.intellij.openapi.actionSystem.KeyboardShortcut | ||||||
| import com.intellij.openapi.ide.CopyPasteManager | import com.intellij.openapi.ide.CopyPasteManager | ||||||
| import com.intellij.openapi.keymap.Keymap |  | ||||||
| import com.intellij.openapi.keymap.KeymapUtil | import com.intellij.openapi.keymap.KeymapUtil | ||||||
| import com.intellij.openapi.options.ShowSettingsUtil | import com.intellij.openapi.options.ShowSettingsUtil | ||||||
| import com.intellij.openapi.project.DumbAwareAction | import com.intellij.openapi.project.DumbAwareAction | ||||||
| import com.intellij.openapi.project.Project | import com.intellij.openapi.project.Project | ||||||
| import com.intellij.openapi.ui.Messages | import com.intellij.openapi.ui.Messages | ||||||
| import com.intellij.openapi.util.SystemInfo | import com.intellij.openapi.util.SystemInfo | ||||||
| import com.intellij.openapi.util.registry.Registry |  | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.helper.MessageHelper | import com.maddyhome.idea.vim.helper.MessageHelper | ||||||
| import com.maddyhome.idea.vim.key.ShortcutOwner | import com.maddyhome.idea.vim.key.ShortcutOwner | ||||||
| @@ -50,7 +48,6 @@ import com.maddyhome.idea.vim.statistic.ActionTracker | |||||||
| import com.maddyhome.idea.vim.ui.VimEmulationConfigurable | import com.maddyhome.idea.vim.ui.VimEmulationConfigurable | ||||||
| import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService | import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService | ||||||
| import com.maddyhome.idea.vim.vimscript.services.VimRcService | import com.maddyhome.idea.vim.vimscript.services.VimRcService | ||||||
| import org.jetbrains.annotations.Nls |  | ||||||
| import java.awt.datatransfer.StringSelection | import java.awt.datatransfer.StringSelection | ||||||
| import java.io.File | import java.io.File | ||||||
| import javax.swing.KeyStroke | import javax.swing.KeyStroke | ||||||
| @@ -115,23 +112,6 @@ class NotificationService(private val project: Project?) { | |||||||
|     Messages.getQuestionIcon() |     Messages.getQuestionIcon() | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   fun specialKeymap(keymap: Keymap, listener: NotificationListener.Adapter) { |  | ||||||
|     val notification = IDEAVIM_STICKY_GROUP.createNotification( |  | ||||||
|       IDEAVIM_NOTIFICATION_TITLE, |  | ||||||
|       "IdeaVim plugin doesn't use the special \"Vim\" keymap any longer. " + |  | ||||||
|         "Switching to \"${keymap.presentableName}\" keymap.<br/><br/>" + |  | ||||||
|         "Now it is possible to set up:<br/>" + |  | ||||||
|         "<ul>" + |  | ||||||
|         "<li>Vim keys in your ~/.ideavimrc file using key mapping commands</li>" + |  | ||||||
|         "<li>IDE action shortcuts in \"File | Settings | Keymap\"</li>" + |  | ||||||
|         "<li>Vim or IDE handlers for conflicting shortcuts in <a href='#settings'>Vim Emulation</a> settings</li>" + |  | ||||||
|         "</ul>", |  | ||||||
|       NotificationType.INFORMATION |  | ||||||
|     ) |  | ||||||
|     notification.setListener(listener) |  | ||||||
|     notification.notify(project) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   fun noVimrcAsDefault() { |   fun noVimrcAsDefault() { | ||||||
|     val notification = IDEAVIM_STICKY_GROUP.createNotification( |     val notification = IDEAVIM_STICKY_GROUP.createNotification( | ||||||
|       IDEAVIM_NOTIFICATION_TITLE, |       IDEAVIM_NOTIFICATION_TITLE, | ||||||
| @@ -208,7 +188,7 @@ class NotificationService(private val project: Project?) { | |||||||
|       Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let { |       Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let { | ||||||
|         notification = it |         notification = it | ||||||
|         it.whenExpired { notification = null } |         it.whenExpired { notification = null } | ||||||
|         it.setContent(it.content + "<br><br><small>Use ${getToolwindowName()} to see previous ids</small>") |         it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>") | ||||||
|  |  | ||||||
|         it.addAction(StopTracking()) |         it.addAction(StopTracking()) | ||||||
|  |  | ||||||
| @@ -222,15 +202,6 @@ class NotificationService(private val project: Project?) { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // [VERSION UPDATE] 221+ Use ActionCenter.getToolWindowName |  | ||||||
|     private fun getToolwindowName(): @Nls String { |  | ||||||
|       return IdeBundle.message(if (isEnabled()) "toolwindow.stripe.Notifications" else "toolwindow.stripe.Event_Log") |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private fun isEnabled(): Boolean { |  | ||||||
|       return Registry.`is`("ide.notification.action.center", true) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     class CopyActionId(val id: String?, val project: Project?) : DumbAwareAction(MessageHelper.message("action.copy.action.id.text")) { |     class CopyActionId(val id: String?, val project: Project?) : DumbAwareAction(MessageHelper.message("action.copy.action.id.text")) { | ||||||
|       override fun actionPerformed(e: AnActionEvent) { |       override fun actionPerformed(e: AnActionEvent) { | ||||||
|         CopyPasteManager.getInstance().setContents(StringSelection(id ?: "")) |         CopyPasteManager.getInstance().setContents(StringSelection(id ?: "")) | ||||||
| @@ -251,6 +222,8 @@ class NotificationService(private val project: Project?) { | |||||||
|       override fun update(e: AnActionEvent) { |       override fun update(e: AnActionEvent) { | ||||||
|         e.presentation.isEnabled = id != null |         e.presentation.isEnabled = id != null | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       override fun getActionUpdateThread() = ActionUpdateThread.BGT | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     class StopTracking : DumbAwareAction("Stop Tracking") { |     class StopTracking : DumbAwareAction("Stop Tracking") { | ||||||
| @@ -287,6 +260,8 @@ class NotificationService(private val project: Project?) { | |||||||
|       val actionText = if (VimRcService.findIdeaVimRc() != null) "Open ~/.ideavimrc" else "Create ~/.ideavimrc" |       val actionText = if (VimRcService.findIdeaVimRc() != null) "Open ~/.ideavimrc" else "Create ~/.ideavimrc" | ||||||
|       e.presentation.text = actionText |       e.presentation.text = actionText | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override fun getActionUpdateThread() = ActionUpdateThread.BGT | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Suppress("DialogTitleCapitalization") |   @Suppress("DialogTitleCapitalization") | ||||||
|   | |||||||
| @@ -92,7 +92,7 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|     String initText = getRange(((IjVimEditor) editor).getEditor(), cmd); |     String initText = getRange(((IjVimEditor) editor).getEditor(), cmd); | ||||||
|     VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE); |     VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE); | ||||||
|     ExEntryPanel panel = ExEntryPanel.getInstance(); |     ExEntryPanel panel = ExEntryPanel.getInstance(); | ||||||
|     panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, 1); |     panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, cmd.getCount()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -123,7 +123,7 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|  |  | ||||||
|       logger.debug("processing command"); |       logger.debug("processing command"); | ||||||
|  |  | ||||||
|       final String text = panel.getText(); |       String text = panel.getText(); | ||||||
|  |  | ||||||
|       if (!panel.getLabel().equals(":")) { |       if (!panel.getLabel().equals(":")) { | ||||||
|         // Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for |         // Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for | ||||||
| @@ -134,8 +134,16 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|  |  | ||||||
|       if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); |       if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); | ||||||
|  |  | ||||||
|  |       int repeat = 1; | ||||||
|  |       if (text.contains("raction ")) { | ||||||
|  |         text = text.replace("raction ", "action "); | ||||||
|  |         repeat = panel.getCount(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for (int i = 0; i < repeat; i++) { | ||||||
|         VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE); |         VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE); | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|     catch (ExException e) { |     catch (ExException e) { | ||||||
|       VimPlugin.showMessage(e.getMessage()); |       VimPlugin.showMessage(e.getMessage()); | ||||||
|       VimPlugin.indicateError(); |       VimPlugin.indicateError(); | ||||||
|   | |||||||
| @@ -61,7 +61,10 @@ internal fun Project.createLineBookmark(editor: Editor, line: Int, mnemonic: Cha | |||||||
|   val type = BookmarkType.get(mnemonic) |   val type = BookmarkType.get(mnemonic) | ||||||
|   if (type == BookmarkType.DEFAULT) return null |   if (type == BookmarkType.DEFAULT) return null | ||||||
|  |  | ||||||
|   val group = bookmarksManager.defaultGroup ?: bookmarksManager.addGroup("IdeaVim", true) ?: return null |   val group = bookmarksManager.defaultGroup | ||||||
|  |     ?: bookmarksManager.getGroup("IdeaVim") | ||||||
|  |     ?: bookmarksManager.addGroup("IdeaVim", true) | ||||||
|  |     ?: return null | ||||||
|   if (group.canAdd(bookmark)) { |   if (group.canAdd(bookmark)) { | ||||||
|     group.add(bookmark, type) |     group.add(bookmark, type) | ||||||
|     return bookmark |     return bookmark | ||||||
|   | |||||||
| @@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.group; | |||||||
| import com.intellij.openapi.actionSystem.DataContext; | import com.intellij.openapi.actionSystem.DataContext; | ||||||
| import com.intellij.openapi.actionSystem.PlatformDataKeys; | import com.intellij.openapi.actionSystem.PlatformDataKeys; | ||||||
| import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; | ||||||
|  | import com.intellij.openapi.fileEditor.impl.EditorComposite; | ||||||
| import com.intellij.openapi.fileEditor.impl.EditorWindow; | import com.intellij.openapi.fileEditor.impl.EditorWindow; | ||||||
| import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite; |  | ||||||
| import com.intellij.openapi.project.Project; | import com.intellij.openapi.project.Project; | ||||||
| import com.intellij.openapi.vfs.VirtualFile; | import com.intellij.openapi.vfs.VirtualFile; | ||||||
| import com.intellij.util.concurrency.annotations.RequiresReadLock; | import com.intellij.util.concurrency.annotations.RequiresReadLock; | ||||||
| @@ -183,7 +183,7 @@ public class WindowGroup extends WindowGroupBase { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) { |   private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) { | ||||||
|     final EditorWithProviderComposite editor = window.getSelectedEditor(); |     final EditorComposite editor = window.getSelectedComposite(); | ||||||
|     if (editor != null) { |     if (editor != null) { | ||||||
|       final Point point = editor.getComponent().getLocationOnScreen(); |       final Point point = editor.getComponent().getLocationOnScreen(); | ||||||
|       final Dimension dimension = editor.getComponent().getSize(); |       final Dimension dimension = editor.getComponent().getSize(); | ||||||
|   | |||||||
| @@ -34,8 +34,9 @@ import com.maddyhome.idea.vim.api.ExecutionContext | |||||||
| import com.maddyhome.idea.vim.api.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.command.isBlock | import com.maddyhome.idea.vim.command.isBlock | ||||||
| import com.maddyhome.idea.vim.command.isChar | import com.maddyhome.idea.vim.command.isChar | ||||||
| import com.maddyhome.idea.vim.command.isLine | import com.maddyhome.idea.vim.command.isLine | ||||||
| @@ -43,7 +44,9 @@ import com.maddyhome.idea.vim.common.TextRange | |||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.TestClipboardModel | import com.maddyhome.idea.vim.helper.TestClipboardModel | ||||||
| import com.maddyhome.idea.vim.helper.fileSize | import com.maddyhome.idea.vim.helper.fileSize | ||||||
|  | import com.maddyhome.idea.vim.helper.mode | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | ||||||
|  | import com.maddyhome.idea.vim.helper.subMode | ||||||
| import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS | import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimCaret | import com.maddyhome.idea.vim.newapi.IjVimCaret | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| @@ -60,10 +63,20 @@ import java.awt.datatransfer.DataFlavor | |||||||
| import kotlin.math.min | import kotlin.math.min | ||||||
|  |  | ||||||
| class PutGroup : VimPutBase() { | class PutGroup : VimPutBase() { | ||||||
|   override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean { |   override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean): Boolean { | ||||||
|     val additionalData = collectPreModificationData(editor, data) |     val additionalData = collectPreModificationData(editor, data) | ||||||
|  |     data.visualSelection?.let { | ||||||
|  |       deleteSelectedText( | ||||||
|  |         editor, | ||||||
|  |         data, | ||||||
|  |         OperatorArguments(false, 0, editor.mode, editor.subMode) | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|     val processedText = processText(editor, data) ?: return false |     val processedText = processText(editor, data) ?: return false | ||||||
|     putForCaret(editor, caret, data, additionalData, context, processedText) |     putForCaret(editor, caret, data, additionalData, context, processedText) | ||||||
|  |     if (editor.primaryCaret() == caret && updateVisualMarks) { | ||||||
|  |       wrapInsertedTextWithVisualMarks(editor, data, processedText) | ||||||
|  |     } | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -89,7 +102,6 @@ class PutGroup : VimPutBase() { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     notifyAboutIdeaPut(editor) |  | ||||||
|     logger.debug("Perform put via plugin") |     logger.debug("Perform put via plugin") | ||||||
|     val myCarets = if (visualSelection != null) { |     val myCarets = if (visualSelection != null) { | ||||||
|       visualSelection.caretsAndSelections.keys.sortedByDescending { it.getLogicalPosition() } |       visualSelection.caretsAndSelections.keys.sortedByDescending { it.getLogicalPosition() } | ||||||
| @@ -109,6 +121,7 @@ class PutGroup : VimPutBase() { | |||||||
|     context: ExecutionContext, |     context: ExecutionContext, | ||||||
|     text: ProcessedTextData, |     text: ProcessedTextData, | ||||||
|   ) { |   ) { | ||||||
|  |     notifyAboutIdeaPut(editor) | ||||||
|     if (data.visualSelection?.typeInEditor?.isLine == true && editor.isOneLineMode()) return |     if (data.visualSelection?.typeInEditor?.isLine == true && editor.isOneLineMode()) return | ||||||
|     val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, text.typeInRegister, data, additionalData) |     val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, text.typeInRegister, data, additionalData) | ||||||
|  |  | ||||||
| @@ -118,7 +131,9 @@ class PutGroup : VimPutBase() { | |||||||
|         editor, caret, context, text.text, text.typeInRegister, subMode, |         editor, caret, context, text.text, text.typeInRegister, subMode, | ||||||
|         startOffset, data.count, data.indent, data.caretAfterInsertedText |         startOffset, data.count, data.indent, data.caretAfterInsertedText | ||||||
|       ) |       ) | ||||||
|  |       if (caret == editor.primaryCaret()) { | ||||||
|         VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset)) |         VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset)) | ||||||
|  |       } | ||||||
|       moveCaretToEndPosition( |       moveCaretToEndPosition( | ||||||
|         editor, |         editor, | ||||||
|         caret, |         caret, | ||||||
| @@ -175,7 +190,12 @@ class PutGroup : VimPutBase() { | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         visualSelection.typeInEditor.isLine -> { |         visualSelection.typeInEditor.isLine -> { | ||||||
|           if (caret.offset == editor.fileSize && editor.fileSize != 0) { |           val lastChar = if (editor.fileSize > 0) { | ||||||
|  |             editor.document.getText(com.intellij.openapi.util.TextRange(editor.fileSize - 1, editor.fileSize))[0] | ||||||
|  |           } else { | ||||||
|  |             null | ||||||
|  |           } | ||||||
|  |           if (caret.offset == editor.fileSize && editor.fileSize != 0 && lastChar != '\n') { | ||||||
|             application.runWriteAction { editor.document.insertString(caret.offset, "\n") } |             application.runWriteAction { editor.document.insertString(caret.offset, "\n") } | ||||||
|             listOf(caret.offset + 1) |             listOf(caret.offset + 1) | ||||||
|           } else listOf(caret.offset) |           } else listOf(caret.offset) | ||||||
|   | |||||||
| @@ -18,23 +18,20 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.group.copy | package com.maddyhome.idea.vim.group.copy | ||||||
|  |  | ||||||
| import com.intellij.openapi.editor.Caret |  | ||||||
| import com.intellij.openapi.editor.Editor |  | ||||||
| import com.intellij.util.containers.ContainerUtil | import com.intellij.util.containers.ContainerUtil | ||||||
| import com.maddyhome.idea.vim.VimPlugin |  | ||||||
| import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction | import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
|  | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
|  | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.Argument | import com.maddyhome.idea.vim.command.Argument | ||||||
| import com.maddyhome.idea.vim.command.OperatorArguments | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
| import com.maddyhome.idea.vim.group.MotionGroup |  | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
| import com.maddyhome.idea.vim.helper.fileSize | import com.maddyhome.idea.vim.helper.fileSize | ||||||
| import com.maddyhome.idea.vim.listener.VimYankListener | import com.maddyhome.idea.vim.listener.VimYankListener | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| import com.maddyhome.idea.vim.newapi.vim |  | ||||||
| import com.maddyhome.idea.vim.yank.YankGroupBase | import com.maddyhome.idea.vim.yank.YankGroupBase | ||||||
| import org.jetbrains.annotations.Contract | import org.jetbrains.annotations.Contract | ||||||
| import kotlin.math.min | import kotlin.math.min | ||||||
| @@ -46,8 +43,8 @@ class YankGroup : YankGroupBase() { | |||||||
|  |  | ||||||
|   fun removeListener(listener: VimYankListener) = yankListeners.remove(listener) |   fun removeListener(listener: VimYankListener) = yankListeners.remove(listener) | ||||||
|  |  | ||||||
|   private fun notifyListeners(editor: Editor, textRange: TextRange) = yankListeners.forEach { |   private fun notifyListeners(editor: VimEditor, textRange: TextRange) = yankListeners.forEach { | ||||||
|     it.yankPerformed(editor, textRange) |     it.yankPerformed(editor.ij, textRange) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -67,32 +64,38 @@ class YankGroup : YankGroupBase() { | |||||||
|     operatorArguments: OperatorArguments |     operatorArguments: OperatorArguments | ||||||
|   ): Boolean { |   ): Boolean { | ||||||
|     val motion = argument.motion |     val motion = argument.motion | ||||||
|  |     val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE | ||||||
|  |  | ||||||
|     val caretModel = editor.ij.caretModel |     val nativeCaretCount = editor.nativeCarets().size | ||||||
|     if (caretModel.caretCount <= 0) return false |     if (nativeCaretCount <= 0) return false | ||||||
|  |  | ||||||
|     val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount) |     val carretToRange = HashMap<VimCaret, TextRange>(nativeCaretCount) | ||||||
|  |     val ranges = ArrayList<Pair<Int, Int>>(nativeCaretCount) | ||||||
|  |  | ||||||
|     // This logic is from original vim |     // This logic is from original vim | ||||||
|     val startOffsets = |     val startOffsets = if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<VimCaret, Int>(nativeCaretCount) | ||||||
|       if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<Caret, Int>(caretModel.caretCount) |  | ||||||
|  |  | ||||||
|     for (caret in caretModel.allCarets) { |     for (caret in editor.nativeCarets()) { | ||||||
|       val motionRange = MotionGroup.getMotionRange(editor.ij, caret, context.ij, argument, operatorArguments) |       val motionRange = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments) | ||||||
|         ?: continue |         ?: continue | ||||||
|  |  | ||||||
|       assert(motionRange.size() == 1) |       assert(motionRange.size() == 1) | ||||||
|       ranges.add(motionRange.startOffset to motionRange.endOffset) |       ranges.add(motionRange.startOffset to motionRange.endOffset) | ||||||
|       startOffsets?.put(caret, motionRange.normalize().startOffset) |       startOffsets?.put(caret, motionRange.normalize().startOffset) | ||||||
|  |       carretToRange[caret] = TextRange(motionRange.startOffset, motionRange.endOffset) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE |  | ||||||
|     val range = getTextRange(ranges, type) ?: return false |     val range = getTextRange(ranges, type) ?: return false | ||||||
|  |  | ||||||
|     if (range.size() == 0) return false |     if (range.size() == 0) return false | ||||||
|  |  | ||||||
|     val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type |     return yankRange( | ||||||
|     return yankRange(editor.ij, range, selectionType, startOffsets) |       editor, | ||||||
|  |       carretToRange, | ||||||
|  |       range, | ||||||
|  |       type, | ||||||
|  |       startOffsets | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -103,19 +106,21 @@ class YankGroup : YankGroupBase() { | |||||||
|    * @return true if able to yank the lines, false if not |    * @return true if able to yank the lines, false if not | ||||||
|    */ |    */ | ||||||
|   override fun yankLine(editor: VimEditor, count: Int): Boolean { |   override fun yankLine(editor: VimEditor, count: Int): Boolean { | ||||||
|     val caretModel = editor.ij.caretModel |     val caretCount = editor.nativeCarets().size | ||||||
|     val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount) |     val ranges = ArrayList<Pair<Int, Int>>(caretCount) | ||||||
|     for (caret in caretModel.allCarets) { |     val caretToRange = HashMap<VimCaret, TextRange>(caretCount) | ||||||
|       val start = VimPlugin.getMotion().moveCaretToLineStart(editor, caret.vim) |     for (caret in editor.nativeCarets()) { | ||||||
|       val end = min(VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret.vim, count - 1, true) + 1, editor.fileSize().toInt()) |       val start = injector.motion.moveCaretToLineStart(editor, caret) | ||||||
|  |       val end = min(injector.motion.moveCaretToLineEndOffset(editor, caret, count - 1, true) + 1, editor.fileSize().toInt()) | ||||||
|  |  | ||||||
|       if (end == -1) continue |       if (end == -1) continue | ||||||
|  |  | ||||||
|       ranges.add(start to end) |       ranges.add(start to end) | ||||||
|  |       caretToRange[caret] = TextRange(start, end) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false |     val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false | ||||||
|     return yankRange(editor.ij, range, SelectionType.LINE_WISE, null) |     return yankRange(editor, caretToRange, range, SelectionType.LINE_WISE, null) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -129,6 +134,7 @@ class YankGroup : YankGroupBase() { | |||||||
|   override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean { |   override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean { | ||||||
|     range ?: return false |     range ?: return false | ||||||
|  |  | ||||||
|  |     val caretToRange = HashMap<VimCaret, TextRange>() | ||||||
|     val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type |     val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type | ||||||
|  |  | ||||||
|     if (type == SelectionType.LINE_WISE) { |     if (type == SelectionType.LINE_WISE) { | ||||||
| @@ -143,24 +149,25 @@ class YankGroup : YankGroupBase() { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     val caretModel = editor.ij.caretModel |  | ||||||
|     val rangeStartOffsets = range.startOffsets |     val rangeStartOffsets = range.startOffsets | ||||||
|     val rangeEndOffsets = range.endOffsets |     val rangeEndOffsets = range.endOffsets | ||||||
|  |  | ||||||
|     return if (moveCursor) { |     val startOffsets = HashMap<VimCaret, Int>(editor.nativeCarets().size) | ||||||
|       val startOffsets = HashMap<Caret, Int>(caretModel.caretCount) |  | ||||||
|     if (type == SelectionType.BLOCK_WISE) { |     if (type == SelectionType.BLOCK_WISE) { | ||||||
|         startOffsets[caretModel.primaryCaret] = range.normalize().startOffset |       startOffsets[editor.primaryCaret()] = range.normalize().startOffset | ||||||
|  |       caretToRange[editor.primaryCaret()] = range | ||||||
|     } else { |     } else { | ||||||
|         val carets = caretModel.allCarets |       for ((i, caret) in editor.nativeCarets().withIndex()) { | ||||||
|         for (i in carets.indices) { |         val textRange = TextRange(rangeStartOffsets[i], rangeEndOffsets[i]) | ||||||
|           startOffsets[carets[i]] = TextRange(rangeStartOffsets[i], rangeEndOffsets[i]).normalize().startOffset |         startOffsets[caret] = textRange.normalize().startOffset | ||||||
|  |         caretToRange[caret] = textRange | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|       yankRange(editor.ij, range, selectionType, startOffsets) |     return if (moveCursor) { | ||||||
|  |       yankRange(editor, caretToRange, range, selectionType, startOffsets) | ||||||
|     } else { |     } else { | ||||||
|       yankRange(editor.ij, range, selectionType, null) |       yankRange(editor, caretToRange, range, selectionType, null) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -192,15 +199,20 @@ class YankGroup : YankGroupBase() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private fun yankRange( |   private fun yankRange( | ||||||
|     editor: Editor, |     editor: VimEditor, | ||||||
|  |     caretToRange: Map<VimCaret, TextRange>, | ||||||
|     range: TextRange, |     range: TextRange, | ||||||
|     type: SelectionType, |     type: SelectionType, | ||||||
|     startOffsets: Map<Caret, Int>?, |     startOffsets: Map<VimCaret, Int>?, | ||||||
|   ): Boolean { |   ): Boolean { | ||||||
|     startOffsets?.forEach { (caret, offset) -> MotionGroup.moveCaret(editor, caret, offset) } |     startOffsets?.forEach { (caret, offset) -> injector.motion.moveCaret(editor, caret, offset) } | ||||||
|  |  | ||||||
|     notifyListeners(editor, range) |     notifyListeners(editor, range) | ||||||
|  |  | ||||||
|     return VimPlugin.getRegister().storeText(editor.vim, range, type, false) |     var result = true | ||||||
|  |     for ((caret, myRange) in caretToRange) { | ||||||
|  |       result = caret.registerStorage.storeText(caret, editor, myRange, type, false) && result | ||||||
|  |     } | ||||||
|  |     return result | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ import com.maddyhome.idea.vim.KeyHandler | |||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.helper.EditorDataContext | import com.maddyhome.idea.vim.helper.EditorDataContext | ||||||
| import com.maddyhome.idea.vim.helper.vimStateMachine | import com.maddyhome.idea.vim.helper.editorMode | ||||||
| import com.maddyhome.idea.vim.helper.exitSelectMode | import com.maddyhome.idea.vim.helper.exitSelectMode | ||||||
| import com.maddyhome.idea.vim.helper.exitVisualMode | import com.maddyhome.idea.vim.helper.exitVisualMode | ||||||
| import com.maddyhome.idea.vim.helper.hasVisualSelection | import com.maddyhome.idea.vim.helper.hasVisualSelection | ||||||
| @@ -35,8 +35,8 @@ import com.maddyhome.idea.vim.helper.inSelectMode | |||||||
| import com.maddyhome.idea.vim.helper.inVisualMode | import com.maddyhome.idea.vim.helper.inVisualMode | ||||||
| import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | ||||||
| import com.maddyhome.idea.vim.helper.isTemplateActive | import com.maddyhome.idea.vim.helper.isTemplateActive | ||||||
| import com.maddyhome.idea.vim.helper.editorMode |  | ||||||
| import com.maddyhome.idea.vim.helper.popAllModes | import com.maddyhome.idea.vim.helper.popAllModes | ||||||
|  | import com.maddyhome.idea.vim.helper.vimStateMachine | ||||||
| import com.maddyhome.idea.vim.listener.VimListenerManager | import com.maddyhome.idea.vim.listener.VimListenerManager | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
|   | |||||||
| @@ -25,11 +25,11 @@ import com.maddyhome.idea.vim.VimPlugin | |||||||
| import com.maddyhome.idea.vim.api.VimMotionGroupBase | import com.maddyhome.idea.vim.api.VimMotionGroupBase | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.helper.EditorHelper | import com.maddyhome.idea.vim.helper.EditorHelper | ||||||
|  | import com.maddyhome.idea.vim.helper.editorMode | ||||||
| import com.maddyhome.idea.vim.helper.inBlockSubMode | import com.maddyhome.idea.vim.helper.inBlockSubMode | ||||||
| import com.maddyhome.idea.vim.helper.inSelectMode | import com.maddyhome.idea.vim.helper.inSelectMode | ||||||
| import com.maddyhome.idea.vim.helper.inVisualMode | import com.maddyhome.idea.vim.helper.inVisualMode | ||||||
| import com.maddyhome.idea.vim.helper.isEndAllowed | import com.maddyhome.idea.vim.helper.isEndAllowed | ||||||
| import com.maddyhome.idea.vim.helper.editorMode |  | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | ||||||
| import com.maddyhome.idea.vim.helper.subMode | import com.maddyhome.idea.vim.helper.subMode | ||||||
| import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes | import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes | ||||||
|   | |||||||
| @@ -44,6 +44,7 @@ class VisualMotionGroup : VimVisualMotionGroupBase() { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * COMPATIBILITY-LAYER: Added a method |    * COMPATIBILITY-LAYER: Added a method | ||||||
|  |    * Please see: https://jb.gg/zo8n0r | ||||||
|    */ |    */ | ||||||
|   fun enterVisualMode(editor: Editor, subMode: CommandState.SubMode? = null): Boolean { |   fun enterVisualMode(editor: Editor, subMode: CommandState.SubMode? = null): Boolean { | ||||||
|     return this.enterVisualMode(editor.vim, subMode?.engine) |     return this.enterVisualMode(editor.vim, subMode?.engine) | ||||||
|   | |||||||
| @@ -60,12 +60,14 @@ val Editor.editorMode | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * COMPATIBILITY-LAYER: New method |  * COMPATIBILITY-LAYER: New method | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  */ |  */ | ||||||
| val Editor.mode | val Editor.mode | ||||||
|   get() = this.vim.vimStateMachine.mode.ij |   get() = this.vim.vimStateMachine.mode.ij | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * COMPATIBILITY-LAYER: New method |  * COMPATIBILITY-LAYER: New method | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  */ |  */ | ||||||
| val CommandState.Mode.isEndAllowed: Boolean | val CommandState.Mode.isEndAllowed: Boolean | ||||||
|   get() = this.engine.isEndAllowed |   get() = this.engine.isEndAllowed | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ import org.jetbrains.annotations.Nullable; | |||||||
| import org.jetbrains.annotations.Range; | import org.jetbrains.annotations.Range; | ||||||
|  |  | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
|  | import java.awt.geom.Point2D; | ||||||
| import java.nio.CharBuffer; | import java.nio.CharBuffer; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.Comparator; | import java.util.Comparator; | ||||||
| @@ -154,6 +155,7 @@ public class EditorHelper { | |||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * COMPATIBILITY-LAYER: Created a function |    * COMPATIBILITY-LAYER: Created a function | ||||||
|  |    * Please see: <a href="https://jb.gg/zo8n0r">doc</a> | ||||||
|    */ |    */ | ||||||
|   public static int getVisualLineCount(final @NotNull Editor editor) { |   public static int getVisualLineCount(final @NotNull Editor editor) { | ||||||
|     return getVisualLineCount(new IjVimEditor(editor)); |     return getVisualLineCount(new IjVimEditor(editor)); | ||||||
| @@ -245,12 +247,27 @@ public class EditorHelper { | |||||||
|    * font. It does not include inlays or folds. |    * font. It does not include inlays or folds. | ||||||
|    * <p> |    * <p> | ||||||
|    * Note that this value is only approximate and should be avoided whenever possible! |    * Note that this value is only approximate and should be avoided whenever possible! | ||||||
|  |    * </p> | ||||||
|    * |    * | ||||||
|    * @param editor The editor |    * @param editor The editor | ||||||
|    * @return The number of screen columns |    * @return The number of screen columns | ||||||
|    */ |    */ | ||||||
|   public static int getApproximateScreenWidth(final @NotNull Editor editor) { |   public static int getApproximateScreenWidth(final @NotNull Editor editor) { | ||||||
|     return getVisibleArea(editor).width / EditorUtil.getPlainSpaceWidth(editor); |     return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Gets the width of the space character in the editor's plain font as a float. | ||||||
|  |    * <p> | ||||||
|  |    * Font width can be fractional, but {@link EditorUtil#getPlainSpaceWidth(Editor)} returns it as an int, which can | ||||||
|  |    * lead to rounding errors. | ||||||
|  |    * </p> | ||||||
|  |    * | ||||||
|  |    * @param editor The editor | ||||||
|  |    * @return The width of the space character in the editor's plain font in pixels. It might be a fractional value. | ||||||
|  |    */ | ||||||
|  |   public static float getPlainSpaceWidthFloat(final @NotNull Editor editor) { | ||||||
|  |     return EditorUtil.fontForChar(' ', Font.PLAIN, editor).charWidth2D(' '); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -802,19 +819,20 @@ public class EditorHelper { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x; |     final int columnLeftX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn)).getX()); | ||||||
|     scrollHorizontally(editor, columnLeftX); |     scrollHorizontally(editor, columnLeftX); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) { |   public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) { | ||||||
|     final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn)); |     final Point2D point = editor.visualPositionToPoint2D(new VisualPosition(visualLine, visualColumn)); | ||||||
|     final int screenWidth = getVisibleArea(editor).width; |     final int screenWidth = getVisibleArea(editor).width; | ||||||
|  |  | ||||||
|     // Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number |     // Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number | ||||||
|     // of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is |     // of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is | ||||||
|     // still a good solution. Besides, what kind of monster uses Vim with proportional fonts? |     // still a good solution. Besides, what kind of monster uses Vim with proportional fonts? | ||||||
|     final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor); |     final float standardColumnWidth = EditorHelper.getPlainSpaceWidthFloat(editor); | ||||||
|     final int x = max(0, point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth)); |     final int screenMidColumn = (int) (screenWidth / standardColumnWidth / 2); | ||||||
|  |     final int x = max(0, (int) Math.round(point.getX() - (screenMidColumn * standardColumnWidth))); | ||||||
|     scrollHorizontally(editor, x); |     scrollHorizontally(editor, x); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -839,7 +857,7 @@ public class EditorHelper { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays |     // Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays | ||||||
|     final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x; |     final int targetColumnRightX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn + 1)).getX()); | ||||||
|     final int screenWidth = getVisibleArea(editor).width; |     final int screenWidth = getVisibleArea(editor).width; | ||||||
|     scrollHorizontally(editor, targetColumnRightX - screenWidth); |     scrollHorizontally(editor, targetColumnRightX - screenWidth); | ||||||
|   } |   } | ||||||
| @@ -1001,18 +1019,18 @@ public class EditorHelper { | |||||||
|     // Note that visualPos.leansRight will be true for the right half side of the character grid |     // Note that visualPos.leansRight will be true for the right half side of the character grid | ||||||
|     VisualPosition closestVisualPosition = editor.xyToVisualPosition(new Point(x, y)); |     VisualPosition closestVisualPosition = editor.xyToVisualPosition(new Point(x, y)); | ||||||
|  |  | ||||||
|     // Make sure we get the character that contains this XY, not the editor's decision about closest character. The |     // Make sure we get the character that contains this XY, not the editor's decision about the closest character. The | ||||||
|     // editor will give us the next character if X is over half way through the character grid. |     // editor will give us the next character if X is over halfway through the character grid. Take into account that | ||||||
|     int xActualLeft = editor.visualPositionToXY(closestVisualPosition).x; |     // the font size might be fractional, but the editor's area is integer. Use floating point values and round. | ||||||
|  |     long xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX()); | ||||||
|     if (xActualLeft > x) { |     if (xActualLeft > x) { | ||||||
|       closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition); |       closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition); | ||||||
|       xActualLeft = editor.visualPositionToXY(closestVisualPosition).x; |       xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (xActualLeft >= leftBound) { |     if (xActualLeft >= leftBound) { | ||||||
|       final int xActualRight = |       final VisualPosition nextVisualPosition = new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1); | ||||||
|         editor.visualPositionToXY(new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1)).x - |       final long xActualRight = Math.round(editor.visualPositionToPoint2D(nextVisualPosition).getX()) - 1; | ||||||
|         1; |  | ||||||
|       if (xActualRight <= rightBound) { |       if (xActualRight <= rightBound) { | ||||||
|         return closestVisualPosition.column; |         return closestVisualPosition.column; | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ package com.maddyhome.idea.vim.helper | |||||||
|  |  | ||||||
| import com.intellij.codeWithMe.ClientId | import com.intellij.codeWithMe.ClientId | ||||||
| import com.intellij.openapi.editor.Caret | import com.intellij.openapi.editor.Caret | ||||||
|  | import com.intellij.openapi.editor.CaretState | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.editor.ex.util.EditorUtil | import com.intellij.openapi.editor.ex.util.EditorUtil | ||||||
| import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx | ||||||
| @@ -106,3 +107,41 @@ val Caret.vimLine: Int | |||||||
|  */ |  */ | ||||||
| val Editor.vimLine: Int | val Editor.vimLine: Int | ||||||
|   get() = this.caretModel.currentCaret.vimLine |   get() = this.caretModel.currentCaret.vimLine | ||||||
|  |  | ||||||
|  | inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) { | ||||||
|  |   val caretModel = this.caretModel | ||||||
|  |   val carets = if (this.inBlockSubMode) null else caretModel.allCarets | ||||||
|  |   if (carets == null || carets.size == 1) { | ||||||
|  |     action() | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     var initialDocumentSize = this.document.textLength | ||||||
|  |     var documentSizeDifference = 0 | ||||||
|  |  | ||||||
|  |     val caretOffsets = carets.map { it.selectionStart to it.selectionEnd } | ||||||
|  |     val restoredCarets = mutableListOf<CaretState>() | ||||||
|  |  | ||||||
|  |     caretModel.removeSecondaryCarets() | ||||||
|  |      | ||||||
|  |     for ((selectionStart, selectionEnd) in caretOffsets) { | ||||||
|  |       if (selectionStart == selectionEnd) { | ||||||
|  |         caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference) | ||||||
|  |       } | ||||||
|  |       else { | ||||||
|  |         caretModel.primaryCaret.setSelection( | ||||||
|  |           selectionStart + documentSizeDifference, | ||||||
|  |           selectionEnd + documentSizeDifference | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       action() | ||||||
|  |       restoredCarets.add(caretModel.caretsAndSelections.single()) | ||||||
|  |  | ||||||
|  |       val documentLength = this.document.textLength | ||||||
|  |       documentSizeDifference += documentLength - initialDocumentSize | ||||||
|  |       initialDocumentSize = documentLength | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     caretModel.caretsAndSelections = restoredCarets | ||||||
|  |   }  | ||||||
|  | } | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ import com.intellij.codeInsight.template.TemplateManager | |||||||
| import com.intellij.codeWithMe.ClientId | import com.intellij.codeWithMe.ClientId | ||||||
| import com.intellij.injected.editor.EditorWindow | import com.intellij.injected.editor.EditorWindow | ||||||
| import com.intellij.openapi.editor.Caret | import com.intellij.openapi.editor.Caret | ||||||
|  | import com.intellij.openapi.editor.ClientEditorManager | ||||||
| import com.intellij.openapi.editor.Document | import com.intellij.openapi.editor.Document | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.editor.EditorFactory | import com.intellij.openapi.editor.EditorFactory | ||||||
| @@ -30,6 +31,7 @@ import com.intellij.openapi.util.Key | |||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants | import com.maddyhome.idea.vim.options.OptionConstants | ||||||
| import com.maddyhome.idea.vim.options.OptionScope | import com.maddyhome.idea.vim.options.OptionScope | ||||||
|  | import kotlin.streams.toList | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This annotation is created for test functions (methods). |  * This annotation is created for test functions (methods). | ||||||
| @@ -83,10 +85,9 @@ fun Editor.getTopLevelEditor() = if (this is EditorWindow) this.delegate else th | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Return list of editors for local host (for code with me plugin) |  * Return list of editors for local host (for code with me plugin) | ||||||
|  * [VERSION UPDATE] 212+ ClientEditorManager.editors() |  | ||||||
|  */ |  */ | ||||||
| fun localEditors(): List<Editor> { | fun localEditors(): List<Editor> { | ||||||
|   return EditorFactory.getInstance().allEditors.filter { editor -> editor.editorClientId.let { it == null || it == ClientId.currentOrNull } } |   return ClientEditorManager.getCurrentInstance().editors().toList() | ||||||
| } | } | ||||||
|  |  | ||||||
| fun localEditors(doc: Document): List<Editor> { | fun localEditors(doc: Document): List<Editor> { | ||||||
|   | |||||||
| @@ -24,11 +24,8 @@ import com.intellij.openapi.actionSystem.ActionPlaces | |||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.AnActionResult | import com.intellij.openapi.actionSystem.AnActionResult | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.actionSystem.IdeActions | import com.intellij.openapi.actionSystem.IdeActions | ||||||
| import com.intellij.openapi.actionSystem.PlatformCoreDataKeys |  | ||||||
| import com.intellij.openapi.actionSystem.PlatformDataKeys | import com.intellij.openapi.actionSystem.PlatformDataKeys | ||||||
| import com.intellij.openapi.actionSystem.Presentation |  | ||||||
| import com.intellij.openapi.actionSystem.ex.ActionManagerEx | import com.intellij.openapi.actionSystem.ex.ActionManagerEx | ||||||
| import com.intellij.openapi.actionSystem.ex.ActionUtil | import com.intellij.openapi.actionSystem.ex.ActionUtil | ||||||
| import com.intellij.openapi.command.CommandProcessor | import com.intellij.openapi.command.CommandProcessor | ||||||
| @@ -86,7 +83,7 @@ class IjActionExecutor : VimActionExecutor { | |||||||
|     // This method executes inside of lastUpdateAndCheckDumb |     // This method executes inside of lastUpdateAndCheckDumb | ||||||
|     // Another related issue: VIM-2604 |     // Another related issue: VIM-2604 | ||||||
|     if (!ActionUtil.lastUpdateAndCheckDumb(ijAction, event, false)) return false |     if (!ActionUtil.lastUpdateAndCheckDumb(ijAction, event, false)) return false | ||||||
|     if (ijAction is ActionGroup && !canBePerformed(event, ijAction, context.ij)) { |     if (ijAction is ActionGroup && !event.presentation.isPerformGroup) { | ||||||
|       // Some ActionGroups should not be performed, but shown as a popup |       // Some ActionGroups should not be performed, but shown as a popup | ||||||
|       val popup = JBPopupFactory.getInstance() |       val popup = JBPopupFactory.getInstance() | ||||||
|         .createActionGroupPopup(event.presentation.text, ijAction, context.ij, false, null, -1) |         .createActionGroupPopup(event.presentation.text, ijAction, context.ij, false, null, -1) | ||||||
| @@ -118,10 +115,9 @@ class IjActionExecutor : VimActionExecutor { | |||||||
|     var indexError: IndexNotReadyException? = null |     var indexError: IndexNotReadyException? = null | ||||||
|     val manager = ActionManagerEx.getInstanceEx() |     val manager = ActionManagerEx.getInstanceEx() | ||||||
|     manager.fireBeforeActionPerformed(action, event) |     manager.fireBeforeActionPerformed(action, event) | ||||||
|     val component = event.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT) |  | ||||||
|     var result: AnActionResult? = null |     var result: AnActionResult? = null | ||||||
|     try { |     try { | ||||||
|       SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use { ignore -> |       SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use { | ||||||
|         performRunnable.run() |         performRunnable.run() | ||||||
|         result = AnActionResult.PERFORMED |         result = AnActionResult.PERFORMED | ||||||
|       } |       } | ||||||
| @@ -143,17 +139,6 @@ class IjActionExecutor : VimActionExecutor { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private fun canBePerformed(event: AnActionEvent, action: ActionGroup, context: DataContext): Boolean { |  | ||||||
|     val presentation = event.presentation |  | ||||||
|     return try { |  | ||||||
|       // [VERSION UPDATE] 221+ Just use Presentation.isPerformGroup |  | ||||||
|       val method = Presentation::class.java.getMethod("isPerformGroup") |  | ||||||
|       method.invoke(presentation) as Boolean |  | ||||||
|     } catch (e: Exception) { |  | ||||||
|       action.canBePerformed(context) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Execute an action by name |    * Execute an action by name | ||||||
|    * |    * | ||||||
|   | |||||||
| @@ -25,9 +25,9 @@ import com.intellij.openapi.editor.Caret | |||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.OperatorArguments | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
| import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor | import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor | ||||||
| import com.maddyhome.idea.vim.newapi.IjExecutionContext | import com.maddyhome.idea.vim.newapi.IjExecutionContext | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ import com.intellij.psi.PsiElement; | |||||||
| import com.intellij.psi.PsiFile; | import com.intellij.psi.PsiFile; | ||||||
| import com.intellij.psi.util.PsiTreeUtil; | import com.intellij.psi.util.PsiTreeUtil; | ||||||
| import com.maddyhome.idea.vim.VimPlugin; | import com.maddyhome.idea.vim.VimPlugin; | ||||||
|  | import com.maddyhome.idea.vim.api.VimSearchHelperBase; | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine; | import com.maddyhome.idea.vim.command.VimStateMachine; | ||||||
| import com.maddyhome.idea.vim.common.CharacterPosition; | import com.maddyhome.idea.vim.common.CharacterPosition; | ||||||
| import com.maddyhome.idea.vim.common.Direction; | import com.maddyhome.idea.vim.common.Direction; | ||||||
| @@ -529,6 +530,9 @@ public class SearchHelper { | |||||||
|         CharSequence subSequence = chars.subSequence(startOffset, endOffset); |         CharSequence subSequence = chars.subSequence(startOffset, endOffset); | ||||||
|         int inQuotePos = pos - startOffset; |         int inQuotePos = pos - startOffset; | ||||||
|         int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false); |         int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false); | ||||||
|  |         if (inQuoteStart == -1) { | ||||||
|  |           inQuoteStart = findBlockLocation(subSequence, close, type, Direction.FORWARDS, inQuotePos, count, false); | ||||||
|  |         } | ||||||
|         if (inQuoteStart != -1) { |         if (inQuoteStart != -1) { | ||||||
|           startPosInStringFound = true; |           startPosInStringFound = true; | ||||||
|           int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false); |           int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false); | ||||||
| @@ -542,6 +546,9 @@ public class SearchHelper { | |||||||
|  |  | ||||||
|     if (!startPosInStringFound) { |     if (!startPosInStringFound) { | ||||||
|       bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false); |       bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false); | ||||||
|  |       if (bstart == -1) { | ||||||
|  |         bstart = findBlockLocation(chars, close, type, Direction.FORWARDS, pos, count, false); | ||||||
|  |       } | ||||||
|       if (bstart != -1) { |       if (bstart != -1) { | ||||||
|         bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false); |         bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false); | ||||||
|       } |       } | ||||||
| @@ -1195,7 +1202,7 @@ public class SearchHelper { | |||||||
|     int last = -1; |     int last = -1; | ||||||
|     int res = start; |     int res = start; | ||||||
|     while (true) { |     while (true) { | ||||||
|       res = findNextWordOne(chars, res, end, 1, true, false); |       res = (int)VimSearchHelperBase.Companion.findNextWordOne(chars, res, end, 1, true, false); | ||||||
|       if (res == start || res == 0 || res > end || res == last) { |       if (res == start || res == 0 || res > end || res == last) { | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| @@ -1224,105 +1231,6 @@ public class SearchHelper { | |||||||
|     return new CountPosition(count, position); |     return new CountPosition(count, position); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public static int findNextWord(@NotNull Editor editor, int searchFrom, int count, boolean bigWord) { |  | ||||||
|     CharSequence chars = editor.getDocument().getCharsSequence(); |  | ||||||
|     final int size = EditorHelperRt.getFileSize(editor); |  | ||||||
|  |  | ||||||
|     return findNextWord(chars, searchFrom, size, count, bigWord, false); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public static int findNextWord(@NotNull CharSequence chars, |  | ||||||
|                                  int pos, |  | ||||||
|                                  int size, |  | ||||||
|                                  int count, |  | ||||||
|                                  boolean bigWord, |  | ||||||
|                                  boolean spaceWords) { |  | ||||||
|     int step = count >= 0 ? 1 : -1; |  | ||||||
|     count = Math.abs(count); |  | ||||||
|  |  | ||||||
|     int res = pos; |  | ||||||
|     for (int i = 0; i < count; i++) { |  | ||||||
|       res = findNextWordOne(chars, res, size, step, bigWord, spaceWords); |  | ||||||
|       if (res == pos || res == 0 || res == size - 1) { |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return res; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private static int findNextWordOne(@NotNull CharSequence chars, |  | ||||||
|                                      int pos, |  | ||||||
|                                      int size, |  | ||||||
|                                      int step, |  | ||||||
|                                      boolean bigWord, |  | ||||||
|                                      boolean spaceWords) { |  | ||||||
|     boolean found = false; |  | ||||||
|     pos = pos < size ? pos : Math.min(size, chars.length() - 1); |  | ||||||
|     // For back searches, skip any current whitespace so we start at the end of a word |  | ||||||
|     if (step < 0 && pos > 0) { |  | ||||||
|       if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && |  | ||||||
|           !spaceWords) { |  | ||||||
|         pos = skipSpace(chars, pos - 1, step, size) + 1; |  | ||||||
|       } |  | ||||||
|       if (pos > 0 && |  | ||||||
|           CharacterHelper.charType(chars.charAt(pos), bigWord) != |  | ||||||
|           CharacterHelper.charType(chars.charAt(pos - 1), bigWord)) { |  | ||||||
|         pos += step; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     int res = pos; |  | ||||||
|     if (pos < 0 || pos >= size) { |  | ||||||
|       return pos; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     CharacterHelper.CharacterType type = CharacterHelper.charType(chars.charAt(pos), bigWord); |  | ||||||
|     if (type == CharacterHelper.CharacterType.WHITESPACE && step < 0 && pos > 0 && !spaceWords) { |  | ||||||
|       type = CharacterHelper.charType(chars.charAt(pos - 1), bigWord); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pos += step; |  | ||||||
|     while (pos >= 0 && pos < size && !found) { |  | ||||||
|       CharacterHelper.CharacterType newType = CharacterHelper.charType(chars.charAt(pos), bigWord); |  | ||||||
|       if (newType != type) { |  | ||||||
|         if (newType == CharacterHelper.CharacterType.WHITESPACE && step >= 0 && !spaceWords) { |  | ||||||
|           pos = skipSpace(chars, pos, step, size); |  | ||||||
|           res = pos; |  | ||||||
|         } |  | ||||||
|         else if (step < 0) { |  | ||||||
|           res = pos + 1; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|           res = pos; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         type = CharacterHelper.charType(chars.charAt(res), bigWord); |  | ||||||
|         found = true; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       pos += step; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (found) { |  | ||||||
|       if (res < 0) //(pos <= 0) |  | ||||||
|       { |  | ||||||
|         res = 0; |  | ||||||
|       } |  | ||||||
|       else if (res >= size) //(pos >= size) |  | ||||||
|       { |  | ||||||
|         res = size - 1; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     else if (pos <= 0) { |  | ||||||
|       res = 0; |  | ||||||
|     } |  | ||||||
|     else if (pos >= size) { |  | ||||||
|       res = size; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return res; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public static @NotNull List<Pair<TextRange, NumberType>> findNumbersInRange(final @NotNull Editor editor, |   public static @NotNull List<Pair<TextRange, NumberType>> findNumbersInRange(final @NotNull Editor editor, | ||||||
|                                                                               @NotNull TextRange textRange, |                                                                               @NotNull TextRange textRange, | ||||||
|                                                                               final boolean alpha, |                                                                               final boolean alpha, | ||||||
| @@ -1648,10 +1556,10 @@ public class SearchHelper { | |||||||
|  |  | ||||||
|     if ((!onWordStart && !(startSpace && isOuter)) || hasSelection || (count > 1 && dir == -1)) { |     if ((!onWordStart && !(startSpace && isOuter)) || hasSelection || (count > 1 && dir == -1)) { | ||||||
|       if (dir == 1) { |       if (dir == 1) { | ||||||
|         start = findNextWord(chars, pos, max, -1, isBig, !isOuter); |         start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -1, isBig, !isOuter); | ||||||
|       } |       } | ||||||
|       else { |       else { | ||||||
|         start = findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter); |         start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       start = EditorHelper.normalizeOffset(editor, start, false); |       start = EditorHelper.normalizeOffset(editor, start, false); | ||||||
| @@ -1799,7 +1707,7 @@ public class SearchHelper { | |||||||
|     if (step > 0 && pos < size - 1) { |     if (step > 0 && pos < size - 1) { | ||||||
|       if (CharacterHelper.charType(chars.charAt(pos + 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && |       if (CharacterHelper.charType(chars.charAt(pos + 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE && | ||||||
|           !spaceWords) { |           !spaceWords) { | ||||||
|         pos = skipSpace(chars, pos + 1, step, size) - 1; |         pos = (int)(VimSearchHelperBase.Companion.skipSpace(chars, pos + 1, step, size) - 1); | ||||||
|       } |       } | ||||||
|       if (pos < size - 1 && |       if (pos < size - 1 && | ||||||
|           CharacterHelper.charType(chars.charAt(pos), bigWord) != |           CharacterHelper.charType(chars.charAt(pos), bigWord) != | ||||||
| @@ -1824,7 +1732,7 @@ public class SearchHelper { | |||||||
|           res = pos - 1; |           res = pos - 1; | ||||||
|         } |         } | ||||||
|         else if (newType == CharacterHelper.CharacterType.WHITESPACE && step < 0 && !spaceWords) { |         else if (newType == CharacterHelper.CharacterType.WHITESPACE && step < 0 && !spaceWords) { | ||||||
|           pos = skipSpace(chars, pos, step, size); |           pos = (int)VimSearchHelperBase.Companion.skipSpace(chars, pos, step, size); | ||||||
|           res = pos; |           res = pos; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
| @@ -1852,34 +1760,6 @@ public class SearchHelper { | |||||||
|     return res; |     return res; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Skip whitespace starting with the supplied position. |  | ||||||
|    * <p> |  | ||||||
|    * An empty line is considered a whitespace break. |  | ||||||
|    * |  | ||||||
|    * @param chars  The text as a character array |  | ||||||
|    * @param offset The starting position |  | ||||||
|    * @param step   The direction to move |  | ||||||
|    * @param size   The size of the document |  | ||||||
|    * @return The new position. This will be the first non-whitespace character found or an empty line |  | ||||||
|    */ |  | ||||||
|   private static int skipSpace(@NotNull CharSequence chars, int offset, int step, int size) { |  | ||||||
|     char prev = 0; |  | ||||||
|     while (offset >= 0 && offset < size) { |  | ||||||
|       final char c = chars.charAt(offset); |  | ||||||
|       if (c == '\n' && c == prev) { |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       if (CharacterHelper.charType(c, false) != CharacterHelper.CharacterType.WHITESPACE) { |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       prev = c; |  | ||||||
|       offset += step; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return offset < size ? offset : size - 1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * This locates the position with the document of the count-th occurrence of ch on the current line |    * This locates the position with the document of the count-th occurrence of ch on the current line | ||||||
|    * |    * | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/main/java/com/maddyhome/idea/vim/helper/StringHelper.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/main/java/com/maddyhome/idea/vim/helper/StringHelper.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | /* | ||||||
|  |  * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform | ||||||
|  |  * Copyright (C) 2003-2022 The IdeaVim authors | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 2 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  | package com.maddyhome.idea.vim.helper | ||||||
|  |  | ||||||
|  | import com.maddyhome.idea.vim.api.injector | ||||||
|  | import java.util.* | ||||||
|  | import java.util.stream.Collectors | ||||||
|  | import javax.swing.KeyStroke | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * COMPATIBILITY-LAYER: Created a helper class | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  |  */ | ||||||
|  | object StringHelper { | ||||||
|  |   @JvmStatic | ||||||
|  |   fun parseKeys(string: String): List<KeyStroke> { | ||||||
|  |     return injector.parser.parseKeys(string) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @JvmStatic | ||||||
|  |   fun parseKeys(vararg string: String): List<KeyStroke> { | ||||||
|  |     return Arrays.stream(string).flatMap { o: String -> injector.parser.parseKeys(o).stream() } | ||||||
|  |       .collect(Collectors.toList()) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @JvmStatic | ||||||
|  |   fun isCloseKeyStroke(stroke: KeyStroke): Boolean { | ||||||
|  |     return stroke.isCloseKeyStroke() | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -21,8 +21,11 @@ package com.maddyhome.idea.vim.helper | |||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| import com.intellij.openapi.actionSystem.DataContext | import com.intellij.openapi.actionSystem.DataContext | ||||||
| import com.intellij.openapi.actionSystem.PlatformDataKeys | import com.intellij.openapi.actionSystem.PlatformDataKeys | ||||||
|  | import com.intellij.openapi.command.CommandProcessor | ||||||
|  | import com.intellij.openapi.command.impl.UndoManagerImpl | ||||||
| import com.intellij.openapi.command.undo.UndoManager | import com.intellij.openapi.command.undo.UndoManager | ||||||
| import com.intellij.openapi.components.Service | import com.intellij.openapi.components.Service | ||||||
|  | import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.common.ChangesListener | import com.maddyhome.idea.vim.common.ChangesListener | ||||||
| @@ -39,27 +42,36 @@ import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService | |||||||
|  */ |  */ | ||||||
| @Service | @Service | ||||||
| class UndoRedoHelper : UndoRedoBase() { | class UndoRedoHelper : UndoRedoBase() { | ||||||
|  |   init { | ||||||
|  |     injector.optionService.addListener(IjVimOptionService.oldUndo, { UndoManagerImpl.ourNeverAskUser = !injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo) }, true) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   override fun undo(context: ExecutionContext): Boolean { |   override fun undo(context: ExecutionContext): Boolean { | ||||||
|     val ijContext = context.context as DataContext |     val ijContext = context.context as DataContext | ||||||
|     val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false |     val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false | ||||||
|     val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext) |     val editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false | ||||||
|  |     val vimEditor = editor.vim | ||||||
|  |     val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor) | ||||||
|     val undoManager = UndoManager.getInstance(project) |     val undoManager = UndoManager.getInstance(project) | ||||||
|     if (fileEditor != null && undoManager.isUndoAvailable(fileEditor)) { |     if (undoManager.isUndoAvailable(fileEditor)) { | ||||||
|       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { |       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { | ||||||
|         SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } |         SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } | ||||||
|       } else { |       } else { | ||||||
|         val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim |         performUntilFileChanges(vimEditor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) | ||||||
|         performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) |  | ||||||
|         editor?.carets()?.forEach { |         vimEditor.carets().forEach { | ||||||
|           val ijCaret = it.ij |           val ijCaret = it.ij | ||||||
|           val hasSelection = ijCaret.hasSelection() |           val hasSelection = ijCaret.hasSelection() | ||||||
|           if (hasSelection) { |           if (hasSelection) { | ||||||
|             val selectionStart = ijCaret.selectionStart |             val selectionStart = ijCaret.selectionStart | ||||||
|  |             CommandProcessor.getInstance().runUndoTransparentAction { | ||||||
|               it.ij.removeSelection() |               it.ij.removeSelection() | ||||||
|               it.ij.moveToOffset(selectionStart) |               it.ij.moveToOffset(selectionStart) | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|       return true |       return true | ||||||
|     } |     } | ||||||
|     return false |     return false | ||||||
| @@ -68,15 +80,18 @@ class UndoRedoHelper : UndoRedoBase() { | |||||||
|   override fun redo(context: ExecutionContext): Boolean { |   override fun redo(context: ExecutionContext): Boolean { | ||||||
|     val ijContext = context.context as DataContext |     val ijContext = context.context as DataContext | ||||||
|     val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false |     val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false | ||||||
|     val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext) |     val editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false | ||||||
|  |     val vimEditor = editor.vim | ||||||
|  |     val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor) | ||||||
|     val undoManager = UndoManager.getInstance(project) |     val undoManager = UndoManager.getInstance(project) | ||||||
|     if (fileEditor != null && undoManager.isRedoAvailable(fileEditor)) { |     if (undoManager.isRedoAvailable(fileEditor)) { | ||||||
|       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { |       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { | ||||||
|         SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } |         SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } | ||||||
|       } else { |       } else { | ||||||
|         val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim |         performUntilFileChanges(vimEditor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) | ||||||
|         performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) |         CommandProcessor.getInstance().runUndoTransparentAction { | ||||||
|         editor?.carets()?.forEach { it.ij.removeSelection() } |           vimEditor.carets().forEach { it.ij.removeSelection() } | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       return true |       return true | ||||||
|     } |     } | ||||||
| @@ -95,10 +110,15 @@ class UndoRedoHelper : UndoRedoBase() { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     val oldPath = editor.getPath() | ||||||
|     vimDocument.addChangeListener(changeListener) |     vimDocument.addChangeListener(changeListener) | ||||||
|     while (check() && !changeListener.hasChanged) { |     while (check() && !changeListener.hasChanged && !ifFilePathChanged(editor, oldPath)) { | ||||||
|       action.run() |       action.run() | ||||||
|     } |     } | ||||||
|     vimDocument.removeChangeListener(changeListener) |     vimDocument.removeChangeListener(changeListener) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private fun ifFilePathChanged(editor: IjVimEditor, oldPath: String?): Boolean { | ||||||
|  |     return editor.getPath() != oldPath | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,8 +27,9 @@ import com.intellij.openapi.editor.RangeMarker | |||||||
| import com.intellij.openapi.editor.markup.RangeHighlighter | import com.intellij.openapi.editor.markup.RangeHighlighter | ||||||
| import com.intellij.openapi.util.Key | import com.intellij.openapi.util.Key | ||||||
| import com.intellij.openapi.util.UserDataHolder | import com.intellij.openapi.util.UserDataHolder | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.api.CaretRegisterStorageBase | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.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 | ||||||
| @@ -73,6 +74,7 @@ var Caret.vimInsertStart: RangeMarker by userDataOr { | |||||||
|     this.offset |     this.offset | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  | var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor() | ||||||
|  |  | ||||||
| // ------------------ Editor | // ------------------ Editor | ||||||
| fun unInitializeEditor(editor: Editor) { | fun unInitializeEditor(editor: Editor) { | ||||||
|   | |||||||
| @@ -19,8 +19,6 @@ | |||||||
| package com.maddyhome.idea.vim.key | package com.maddyhome.idea.vim.key | ||||||
|  |  | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.common.Node |  | ||||||
| import com.maddyhome.idea.vim.common.addLeafs |  | ||||||
|  |  | ||||||
| fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) { | fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) { | ||||||
|   addLeafs(injector.parser.parseKeys(keys), actionHolder) |   addLeafs(injector.parser.parseKeys(keys), actionHolder) | ||||||
|   | |||||||
| @@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener | |||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
|  | import com.intellij.openapi.actionSystem.AnActionResult | ||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.actionSystem.IdeActions | import com.intellij.openapi.actionSystem.IdeActions | ||||||
| import com.intellij.openapi.actionSystem.ex.AnActionListener | import com.intellij.openapi.actionSystem.ex.AnActionListener | ||||||
| import com.intellij.openapi.editor.Caret | import com.intellij.openapi.editor.Caret | ||||||
| @@ -35,7 +35,6 @@ import com.maddyhome.idea.vim.group.visual.VimVisualTimer | |||||||
| import com.maddyhome.idea.vim.helper.fileSize | import com.maddyhome.idea.vim.helper.fileSize | ||||||
| import com.maddyhome.idea.vim.helper.inVisualMode | import com.maddyhome.idea.vim.helper.inVisualMode | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import org.jetbrains.annotations.NotNull |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A collection of hacks to improve the interaction with fancy AppCode templates |  * A collection of hacks to improve the interaction with fancy AppCode templates | ||||||
| @@ -50,16 +49,16 @@ object AppCodeTemplates { | |||||||
|  |  | ||||||
|     private var editor: Editor? = null |     private var editor: Editor? = null | ||||||
|  |  | ||||||
|     override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |     override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { | ||||||
|       if (!VimPlugin.isEnabled()) return |       if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|       val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) |       val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) | ||||||
|       if (hostEditor != null) { |       if (hostEditor != null) { | ||||||
|         editor = hostEditor |         editor = hostEditor | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |     override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { | ||||||
|       if (!VimPlugin.isEnabled()) return |       if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|       if (ActionManager.getInstance().getId(action) == IdeActions.ACTION_CHOOSE_LOOKUP_ITEM) { |       if (ActionManager.getInstance().getId(action) == IdeActions.ACTION_CHOOSE_LOOKUP_ITEM) { | ||||||
| @@ -77,8 +76,8 @@ object AppCodeTemplates { | |||||||
|  |  | ||||||
|   @JvmStatic |   @JvmStatic | ||||||
|   fun onMovement( |   fun onMovement( | ||||||
|     editor: @NotNull Editor, |     editor: Editor, | ||||||
|     caret: @NotNull Caret, |     caret: Caret, | ||||||
|     toRight: Boolean, |     toRight: Boolean, | ||||||
|   ) { |   ) { | ||||||
|     val offset = caret.offset |     val offset = caret.offset | ||||||
|   | |||||||
| @@ -19,8 +19,10 @@ | |||||||
| package com.maddyhome.idea.vim.listener | package com.maddyhome.idea.vim.listener | ||||||
|  |  | ||||||
| import com.intellij.codeInsight.lookup.Lookup | import com.intellij.codeInsight.lookup.Lookup | ||||||
|  | import com.intellij.codeInsight.lookup.LookupManager | ||||||
| import com.intellij.codeInsight.lookup.LookupManagerListener | import com.intellij.codeInsight.lookup.LookupManagerListener | ||||||
| import com.intellij.codeInsight.lookup.impl.LookupImpl | import com.intellij.codeInsight.lookup.impl.LookupImpl | ||||||
|  | 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 | ||||||
| @@ -29,26 +31,28 @@ import com.intellij.find.FindModelListener | |||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
|  | import com.intellij.openapi.actionSystem.AnActionResult | ||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.actionSystem.ex.AnActionListener | import com.intellij.openapi.actionSystem.ex.AnActionListener | ||||||
| import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet | import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.project.DumbAwareToggleAction | import com.intellij.openapi.project.DumbAwareToggleAction | ||||||
|  | import com.intellij.openapi.util.TextRange | ||||||
| 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.command.VimStateMachine | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.group.NotificationService |  | ||||||
| import com.maddyhome.idea.vim.helper.EditorDataContext | import com.maddyhome.idea.vim.helper.EditorDataContext | ||||||
| import com.maddyhome.idea.vim.helper.vimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.helper.inNormalMode | import com.maddyhome.idea.vim.helper.inNormalMode | ||||||
| import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | ||||||
|  | import com.maddyhome.idea.vim.helper.vimStateMachine | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants | import com.maddyhome.idea.vim.options.OptionConstants | ||||||
| import com.maddyhome.idea.vim.options.OptionScope | import com.maddyhome.idea.vim.options.OptionScope | ||||||
| import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt | ||||||
| import com.maddyhome.idea.vim.vimscript.model.options.helpers.IdeaRefactorModeHelper | import com.maddyhome.idea.vim.vimscript.model.options.helpers.IdeaRefactorModeHelper | ||||||
| import org.jetbrains.annotations.NonNls | import org.jetbrains.annotations.NonNls | ||||||
|  | import java.awt.event.KeyEvent | ||||||
|  | import javax.swing.KeyStroke | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @author Alex Plate |  * @author Alex Plate | ||||||
| @@ -60,27 +64,62 @@ object IdeaSpecifics { | |||||||
|     private val surrounderAction = |     private val surrounderAction = | ||||||
|       "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction" |       "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction" | ||||||
|     private var editor: Editor? = null |     private var editor: Editor? = null | ||||||
|     override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |     private var completionPrevDocumentLength: Int? = null | ||||||
|  |     private var completionPrevDocumentOffset: Int? = null | ||||||
|  |     override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { | ||||||
|       if (!VimPlugin.isEnabled()) return |       if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|       val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) |       val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) | ||||||
|       if (hostEditor != null) { |       if (hostEditor != null) { | ||||||
|         editor = hostEditor |         editor = hostEditor | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       //region Track action id |  | ||||||
|       if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) { |       if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) { | ||||||
|         if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) { |  | ||||||
|         val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId |         val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId | ||||||
|           VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) |         VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       //endregion |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |       if (hostEditor != null && action is ChooseItemAction && hostEditor.vimStateMachine?.isRecording == true) { | ||||||
|  |         val lookup = LookupManager.getActiveLookup(hostEditor) | ||||||
|  |         if (lookup != null) { | ||||||
|  |           val charsToRemove = hostEditor.caretModel.primaryCaret.offset - lookup.lookupStart | ||||||
|  |  | ||||||
|  |           val register = VimPlugin.getRegister() | ||||||
|  |           val backSpace = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0) | ||||||
|  |           repeat(charsToRemove) { | ||||||
|  |             register.recordKeyStroke(backSpace) | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           completionPrevDocumentLength = hostEditor.document.textLength - charsToRemove | ||||||
|  |           completionPrevDocumentOffset = lookup.lookupStart | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { | ||||||
|       if (!VimPlugin.isEnabled()) return |       if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|  |       val editor = editor | ||||||
|  |       if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) { | ||||||
|  |         val prevDocumentLength = completionPrevDocumentLength | ||||||
|  |         val prevDocumentOffset = completionPrevDocumentOffset | ||||||
|  |  | ||||||
|  |         if (prevDocumentLength != null && prevDocumentOffset != null) { | ||||||
|  |           val register = VimPlugin.getRegister() | ||||||
|  |           val addedTextLength = editor.document.textLength - prevDocumentLength | ||||||
|  |           val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset) | ||||||
|  |           val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0) | ||||||
|  |  | ||||||
|  |           register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength))) | ||||||
|  |           repeat(caretShift.coerceAtLeast(0)) { | ||||||
|  |             register.recordKeyStroke(leftArrow) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.completionPrevDocumentLength = null | ||||||
|  |         this.completionPrevDocumentOffset = null | ||||||
|  |       } | ||||||
|  |  | ||||||
|       //region Enter insert mode after surround with if |       //region Enter insert mode after surround with if | ||||||
|       if (surrounderAction == action.javaClass.name && surrounderItems.any { |       if (surrounderAction == action.javaClass.name && surrounderItems.any { | ||||||
|         action.templatePresentation.text.endsWith( |         action.templatePresentation.text.endsWith( | ||||||
| @@ -93,13 +132,13 @@ object IdeaSpecifics { | |||||||
|           while (commandState.mode != VimStateMachine.Mode.COMMAND) { |           while (commandState.mode != VimStateMachine.Mode.COMMAND) { | ||||||
|             commandState.popModes() |             commandState.popModes() | ||||||
|           } |           } | ||||||
|           VimPlugin.getChange().insertBeforeCursor(it.vim, dataContext.vim) |           VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim) | ||||||
|           KeyHandler.getInstance().reset(it.vim) |           KeyHandler.getInstance().reset(it.vim) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       //endregion |       //endregion | ||||||
|  |  | ||||||
|       editor = null |       this.editor = null | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener | |||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
| import com.intellij.openapi.actionSystem.AnAction | import com.intellij.openapi.actionSystem.AnAction | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
|  | import com.intellij.openapi.actionSystem.AnActionResult | ||||||
| import com.intellij.openapi.actionSystem.CommonDataKeys | import com.intellij.openapi.actionSystem.CommonDataKeys | ||||||
| import com.intellij.openapi.actionSystem.DataContext |  | ||||||
| import com.intellij.openapi.actionSystem.IdeActions | import com.intellij.openapi.actionSystem.IdeActions | ||||||
| import com.intellij.openapi.actionSystem.ex.AnActionListener | import com.intellij.openapi.actionSystem.ex.AnActionListener | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| @@ -36,16 +36,16 @@ import com.maddyhome.idea.vim.helper.getTopLevelEditor | |||||||
| class RiderActionListener : AnActionListener { | class RiderActionListener : AnActionListener { | ||||||
|  |  | ||||||
|   private var editor: Editor? = null |   private var editor: Editor? = null | ||||||
|   override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |   override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { | ||||||
|     if (!VimPlugin.isEnabled()) return |     if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|     val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR) |     val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR) | ||||||
|     if (hostEditor != null) { |     if (hostEditor != null) { | ||||||
|       editor = hostEditor |       editor = hostEditor | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { |   override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) { | ||||||
|     if (!VimPlugin.isEnabled()) return |     if (!VimPlugin.isEnabled()) return | ||||||
|  |  | ||||||
|     //region Extend Selection for Rider |     //region Extend Selection for Rider | ||||||
|   | |||||||
| @@ -36,9 +36,14 @@ import com.intellij.openapi.editor.event.SelectionEvent | |||||||
| import com.intellij.openapi.editor.event.SelectionListener | import com.intellij.openapi.editor.event.SelectionListener | ||||||
| import com.intellij.openapi.editor.ex.DocumentEx | import com.intellij.openapi.editor.ex.DocumentEx | ||||||
| import com.intellij.openapi.editor.impl.EditorComponentImpl | import com.intellij.openapi.editor.impl.EditorComponentImpl | ||||||
|  | import com.intellij.openapi.editor.impl.EditorImpl | ||||||
| import com.intellij.openapi.fileEditor.FileEditorManagerEvent | import com.intellij.openapi.fileEditor.FileEditorManagerEvent | ||||||
| import com.intellij.openapi.fileEditor.FileEditorManagerListener | import com.intellij.openapi.fileEditor.FileEditorManagerListener | ||||||
|  | import com.intellij.openapi.rd.createLifetime | ||||||
|  | import com.intellij.openapi.rd.createNestedDisposable | ||||||
|  | import com.intellij.openapi.util.Disposer | ||||||
| import com.intellij.util.ExceptionUtil | import com.intellij.util.ExceptionUtil | ||||||
|  | import com.jetbrains.rd.util.lifetime.intersect | ||||||
| import com.maddyhome.idea.vim.EventFacade | import com.maddyhome.idea.vim.EventFacade | ||||||
| import com.maddyhome.idea.vim.KeyHandler | import com.maddyhome.idea.vim.KeyHandler | ||||||
| import com.maddyhome.idea.vim.VimKeyListener | import com.maddyhome.idea.vim.VimKeyListener | ||||||
| @@ -73,8 +78,6 @@ import com.maddyhome.idea.vim.helper.vimLastColumn | |||||||
| import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipEvents | import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipEvents | ||||||
| import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents | import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents | ||||||
| import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add | import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add | ||||||
| import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.remove |  | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor |  | ||||||
| import com.maddyhome.idea.vim.newapi.vim | import com.maddyhome.idea.vim.newapi.vim | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants | import com.maddyhome.idea.vim.options.OptionConstants | ||||||
| import com.maddyhome.idea.vim.options.OptionScope | import com.maddyhome.idea.vim.options.OptionScope | ||||||
| @@ -122,9 +125,9 @@ object VimListenerManager { | |||||||
|       VimPlugin.getOptionService().addListener(OptionConstants.guicursorName, GuicursorChangeListener) |       VimPlugin.getOptionService().addListener(OptionConstants.guicursorName, GuicursorChangeListener) | ||||||
|       VimPlugin.getOptionService().addListener(OptionConstants.iskeywordName, KeywordOptionChangeListener, true) |       VimPlugin.getOptionService().addListener(OptionConstants.iskeywordName, KeywordOptionChangeListener, true) | ||||||
|  |  | ||||||
|       EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance()) |       EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable) | ||||||
|  |  | ||||||
|       EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance()) |       EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance().onOffDisposable) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun disable() { |     fun disable() { | ||||||
| @@ -136,10 +139,6 @@ object VimListenerManager { | |||||||
|       VimPlugin.getOptionService().removeListener(OptionConstants.showcmdName, ShowCmdOptionChangeListener) |       VimPlugin.getOptionService().removeListener(OptionConstants.showcmdName, ShowCmdOptionChangeListener) | ||||||
|       VimPlugin.getOptionService().removeListener(OptionConstants.guicursorName, GuicursorChangeListener) |       VimPlugin.getOptionService().removeListener(OptionConstants.guicursorName, GuicursorChangeListener) | ||||||
|       VimPlugin.getOptionService().removeListener(OptionConstants.iskeywordName, KeywordOptionChangeListener) |       VimPlugin.getOptionService().removeListener(OptionConstants.iskeywordName, KeywordOptionChangeListener) | ||||||
|  |  | ||||||
|       EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener) |  | ||||||
|  |  | ||||||
|       EditorFactory.getInstance().eventMulticaster.removeCaretListener(VimCaretListener) |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -157,17 +156,26 @@ object VimListenerManager { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun add(editor: Editor) { |     fun add(editor: Editor) { | ||||||
|  |       val pluginLifetime = VimPlugin.getInstance().createLifetime() | ||||||
|  |       val editorLifetime = (editor as EditorImpl).disposable.createLifetime() | ||||||
|  |       val disposable = editorLifetime.intersect(pluginLifetime).createNestedDisposable("MyLifetimedDisposable") | ||||||
|  |  | ||||||
|       editor.contentComponent.addKeyListener(VimKeyListener) |       editor.contentComponent.addKeyListener(VimKeyListener) | ||||||
|  |       Disposer.register(disposable) { editor.contentComponent.removeKeyListener(VimKeyListener) } | ||||||
|  |  | ||||||
|       val eventFacade = EventFacade.getInstance() |       val eventFacade = EventFacade.getInstance() | ||||||
|       eventFacade.addEditorMouseListener(editor, EditorMouseHandler) |       eventFacade.addEditorMouseListener(editor, EditorMouseHandler, disposable) | ||||||
|       eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler) |       eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable) | ||||||
|       eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler) |       eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable) | ||||||
|       eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener) |       eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable) | ||||||
|  |  | ||||||
|       VimPlugin.getEditor().editorCreated(editor) |       VimPlugin.getEditor().editorCreated(editor) | ||||||
|  |  | ||||||
|       VimPlugin.getChange().editorCreated(IjVimEditor(editor)) |       VimPlugin.getChange().editorCreated(editor, disposable) | ||||||
|  |  | ||||||
|  |       Disposer.register(disposable) { | ||||||
|  |         VimPlugin.getEditorIfCreated()?.editorDeinit(editor, true) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun remove(editor: Editor, isReleased: Boolean) { |     fun remove(editor: Editor, isReleased: Boolean) { | ||||||
| @@ -181,7 +189,7 @@ object VimListenerManager { | |||||||
|  |  | ||||||
|       VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased) |       VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased) | ||||||
|  |  | ||||||
|       VimPlugin.getChange().editorReleased(IjVimEditor(editor)) |       VimPlugin.getChange().editorReleased(editor) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -213,7 +221,6 @@ object VimListenerManager { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun editorReleased(event: EditorFactoryEvent) { |     override fun editorReleased(event: EditorFactoryEvent) { | ||||||
|       remove(event.editor, true) |  | ||||||
|       VimPlugin.getMark().editorReleased(event) |       VimPlugin.getMark().editorReleased(event) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -32,8 +32,8 @@ import com.maddyhome.idea.vim.api.VimChangeGroupBase | |||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.VimMotionGroupBase | import com.maddyhome.idea.vim.api.VimMotionGroupBase | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.EditorLine | import com.maddyhome.idea.vim.common.EditorLine | ||||||
| import com.maddyhome.idea.vim.common.IndentConfig | import com.maddyhome.idea.vim.common.IndentConfig | ||||||
| import com.maddyhome.idea.vim.common.OperatedRange | import com.maddyhome.idea.vim.common.OperatedRange | ||||||
| @@ -99,6 +99,7 @@ fun changeRange( | |||||||
|           vimCaret.moveToOffset(deletedInfo.leftOffset.point) |           vimCaret.moveToOffset(deletedInfo.leftOffset.point) | ||||||
|         } |         } | ||||||
|         is OperatedRange.Block -> TODO() |         is OperatedRange.Block -> TODO() | ||||||
|  |         else -> TODO() | ||||||
|       } |       } | ||||||
|       if (type == SelectionType.BLOCK_WISE) { |       if (type == SelectionType.BLOCK_WISE) { | ||||||
|         VimPlugin.getChange().setInsertRepeat(lines, col, false) |         VimPlugin.getChange().setInsertRepeat(lines, col, false) | ||||||
| @@ -179,7 +180,7 @@ fun insertLineAround(editor: VimEditor, context: ExecutionContext, shift: Int) { | |||||||
|       } |       } | ||||||
|       val position = EditorLine.Offset.init(editor.offsetToLogicalPosition(lineEndOffset).line + shift, editor) |       val position = EditorLine.Offset.init(editor.offsetToLogicalPosition(lineEndOffset).line + shift, editor) | ||||||
|  |  | ||||||
|       val insertedLine = editor.addLine(position) ?: continue |       val insertedLine = editor.addLine(position) | ||||||
|       VimPlugin.getChange().saveStrokes("\n") |       VimPlugin.getChange().saveStrokes("\n") | ||||||
|  |  | ||||||
|       var lineStart = editor.getLineRange(insertedLine).first |       var lineStart = editor.getLineRange(insertedLine).first | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ class IjClipboardManager : VimClipboardManager { | |||||||
|     return Pair(res, transferableData) |     return Pair(res, transferableData) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Suppress("UNCHECKED_CAST") | ||||||
|   override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Any? { |   override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Any? { | ||||||
|     val transferableData1 = (transferableData as List<TextBlockTransferableData>).toMutableList() |     val transferableData1 = (transferableData as List<TextBlockTransferableData>).toMutableList() | ||||||
|     try { |     try { | ||||||
| @@ -97,6 +98,7 @@ class IjClipboardManager : VimClipboardManager { | |||||||
|     return transferableData |     return transferableData | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Suppress("UNCHECKED_CAST") | ||||||
|   override fun preprocessText( |   override fun preprocessText( | ||||||
|     vimEditor: VimEditor, |     vimEditor: VimEditor, | ||||||
|     textRange: TextRange, |     textRange: TextRange, | ||||||
|   | |||||||
| @@ -33,11 +33,11 @@ class IjExecutionContextManager : ExecutionContextManagerBase() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   override fun onCaret(caret: VimCaret, prevContext: ExecutionContext): ExecutionContext { |   override fun onCaret(caret: VimCaret, prevContext: ExecutionContext): ExecutionContext { | ||||||
|     return IjExecutionContext(CaretSpecificDataContext(prevContext.ij, caret.ij)) |     return IjExecutionContext(CaretSpecificDataContext.create(prevContext.ij, caret.ij)) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext { |   override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext { | ||||||
|     return IjExecutionContext(CaretSpecificDataContext(context.ij, caret.ij)) |     return IjExecutionContext(CaretSpecificDataContext.create(context.ij, caret.ij)) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext { |   override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext { | ||||||
|   | |||||||
| @@ -22,7 +22,10 @@ import com.intellij.openapi.editor.Caret | |||||||
| import com.intellij.openapi.editor.LogicalPosition | import com.intellij.openapi.editor.LogicalPosition | ||||||
| import com.intellij.openapi.editor.VisualPosition | import com.intellij.openapi.editor.VisualPosition | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
|  | import com.maddyhome.idea.vim.api.CaretRegisterStorage | ||||||
|  | import com.maddyhome.idea.vim.api.CaretRegisterStorageBase | ||||||
| import com.maddyhome.idea.vim.api.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
|  | import com.maddyhome.idea.vim.api.VimCaretBase | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.VimLogicalPosition | import com.maddyhome.idea.vim.api.VimLogicalPosition | ||||||
| import com.maddyhome.idea.vim.api.VimVisualPosition | import com.maddyhome.idea.vim.api.VimVisualPosition | ||||||
| @@ -38,13 +41,23 @@ import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently | |||||||
| import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection | import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection | ||||||
| import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn | import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | ||||||
|  | import com.maddyhome.idea.vim.helper.registerStorage | ||||||
| import com.maddyhome.idea.vim.helper.vimInsertStart | import com.maddyhome.idea.vim.helper.vimInsertStart | ||||||
| import com.maddyhome.idea.vim.helper.vimLastColumn | import com.maddyhome.idea.vim.helper.vimLastColumn | ||||||
| import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange | import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange | ||||||
| import com.maddyhome.idea.vim.helper.vimLine | import com.maddyhome.idea.vim.helper.vimLine | ||||||
| import com.maddyhome.idea.vim.helper.vimSelectionStart | import com.maddyhome.idea.vim.helper.vimSelectionStart | ||||||
|  |  | ||||||
| class IjVimCaret(val caret: Caret) : VimCaret { | class IjVimCaret(val caret: Caret) : VimCaretBase() { | ||||||
|  |   override val registerStorage: CaretRegisterStorage | ||||||
|  |     get() { | ||||||
|  |       var storage = this.caret.registerStorage | ||||||
|  |       if (storage == null) { | ||||||
|  |         storage = CaretRegisterStorageBase() | ||||||
|  |         this.caret.registerStorage = storage | ||||||
|  |       } | ||||||
|  |       return storage | ||||||
|  |     } | ||||||
|   override val editor: VimEditor |   override val editor: VimEditor | ||||||
|     get() = IjVimEditor(caret.editor) |     get() = IjVimEditor(caret.editor) | ||||||
|   override val offset: Offset |   override val offset: Offset | ||||||
| @@ -74,6 +87,8 @@ class IjVimCaret(val caret: Caret) : VimCaret { | |||||||
|     } |     } | ||||||
|   override val vimLine: Int |   override val vimLine: Int | ||||||
|     get() = this.caret.vimLine |     get() = this.caret.vimLine | ||||||
|  |   override val isPrimary: Boolean | ||||||
|  |     get() = editor.primaryCaret().ij == this.caret | ||||||
|  |  | ||||||
|   override fun moveToOffset(offset: Int) { |   override fun moveToOffset(offset: Int) { | ||||||
|     // TODO: 17.12.2021 Unpack internal actions |     // TODO: 17.12.2021 Unpack internal actions | ||||||
|   | |||||||
| @@ -38,9 +38,9 @@ import com.maddyhome.idea.vim.api.VimLogicalPosition | |||||||
| import com.maddyhome.idea.vim.api.VimSelectionModel | import com.maddyhome.idea.vim.api.VimSelectionModel | ||||||
| import com.maddyhome.idea.vim.api.VimVisualPosition | import com.maddyhome.idea.vim.api.VimVisualPosition | ||||||
| import com.maddyhome.idea.vim.api.VirtualFile | import com.maddyhome.idea.vim.api.VirtualFile | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine |  | ||||||
| import com.maddyhome.idea.vim.command.OperatorArguments | import com.maddyhome.idea.vim.command.OperatorArguments | ||||||
| import com.maddyhome.idea.vim.command.SelectionType | import com.maddyhome.idea.vim.command.SelectionType | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.EditorLine | import com.maddyhome.idea.vim.common.EditorLine | ||||||
| import com.maddyhome.idea.vim.common.LiveRange | import com.maddyhome.idea.vim.common.LiveRange | ||||||
| import com.maddyhome.idea.vim.common.Offset | import com.maddyhome.idea.vim.common.Offset | ||||||
| @@ -62,7 +62,9 @@ import com.maddyhome.idea.vim.helper.updateCaretsVisualPosition | |||||||
| import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode | import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode | ||||||
| import com.maddyhome.idea.vim.helper.vimKeepingVisualOperatorAction | import com.maddyhome.idea.vim.helper.vimKeepingVisualOperatorAction | ||||||
| import com.maddyhome.idea.vim.helper.vimLastSelectionType | import com.maddyhome.idea.vim.helper.vimLastSelectionType | ||||||
|  | import org.jetbrains.annotations.ApiStatus | ||||||
|  |  | ||||||
|  | @ApiStatus.Internal | ||||||
| class IjVimEditor(editor: Editor) : MutableLinearEditor() { | class IjVimEditor(editor: Editor) : MutableLinearEditor() { | ||||||
|  |  | ||||||
|   // All the editor actions should be performed with top level editor!!! |   // All the editor actions should be performed with top level editor!!! | ||||||
|   | |||||||
| @@ -68,15 +68,15 @@ import com.maddyhome.idea.vim.helper.vimStateMachine | |||||||
| import com.maddyhome.idea.vim.history.VimHistory | import com.maddyhome.idea.vim.history.VimHistory | ||||||
| import com.maddyhome.idea.vim.macro.VimMacro | import com.maddyhome.idea.vim.macro.VimMacro | ||||||
| import com.maddyhome.idea.vim.mark.VimMarkGroup | import com.maddyhome.idea.vim.mark.VimMarkGroup | ||||||
| import com.maddyhome.idea.vim.options.OptionService |  | ||||||
| import com.maddyhome.idea.vim.put.VimPut | import com.maddyhome.idea.vim.put.VimPut | ||||||
| import com.maddyhome.idea.vim.register.VimRegisterGroup | import com.maddyhome.idea.vim.register.VimRegisterGroup | ||||||
| import com.maddyhome.idea.vim.ui.VimRcFileState | import com.maddyhome.idea.vim.ui.VimRcFileState | ||||||
| import com.maddyhome.idea.vim.undo.VimUndoRedo | import com.maddyhome.idea.vim.undo.VimUndoRedo | ||||||
| import com.maddyhome.idea.vim.vimscript.Executor | import com.maddyhome.idea.vim.vimscript.Executor | ||||||
| import com.maddyhome.idea.vim.vimscript.services.FunctionStorage | import com.maddyhome.idea.vim.vimscript.services.FunctionStorage | ||||||
|  | import com.maddyhome.idea.vim.vimscript.services.OptionService | ||||||
| import com.maddyhome.idea.vim.vimscript.services.PatternService | import com.maddyhome.idea.vim.vimscript.services.PatternService | ||||||
| import com.maddyhome.idea.vim.vimscript.services.VimVariableService | import com.maddyhome.idea.vim.vimscript.services.VariableService | ||||||
| import com.maddyhome.idea.vim.yank.VimYankGroup | import com.maddyhome.idea.vim.yank.VimYankGroup | ||||||
|  |  | ||||||
| class IjVimInjector : VimInjectorBase() { | class IjVimInjector : VimInjectorBase() { | ||||||
| @@ -161,7 +161,7 @@ class IjVimInjector : VimInjectorBase() { | |||||||
|  |  | ||||||
|   override val functionService: VimscriptFunctionService |   override val functionService: VimscriptFunctionService | ||||||
|     get() = FunctionStorage |     get() = FunctionStorage | ||||||
|   override val variableService: VimVariableService |   override val variableService: VariableService | ||||||
|     get() = service() |     get() = service() | ||||||
|   override val vimrcFileState: VimrcFileState |   override val vimrcFileState: VimrcFileState | ||||||
|     get() = VimRcFileState |     get() = VimRcFileState | ||||||
|   | |||||||
| @@ -37,19 +37,19 @@ class IjVimMessages : VimMessagesBase() { | |||||||
|   private var error = false |   private var error = false | ||||||
|   private var lastBeepTimeMillis = 0L |   private var lastBeepTimeMillis = 0L | ||||||
|  |  | ||||||
|   override fun showStatusBarMessage(msg: String?) { |   override fun showStatusBarMessage(message: String?) { | ||||||
|     if (ApplicationManager.getApplication().isUnitTestMode) { |     if (ApplicationManager.getApplication().isUnitTestMode) { | ||||||
|       message = msg |       this.message = message | ||||||
|     } |     } | ||||||
|     val pm = ProjectManager.getInstance() |     val pm = ProjectManager.getInstance() | ||||||
|     val projects = pm.openProjects |     val projects = pm.openProjects | ||||||
|     for (project in projects) { |     for (project in projects) { | ||||||
|       val bar = WindowManager.getInstance().getStatusBar(project) |       val bar = WindowManager.getInstance().getStatusBar(project) | ||||||
|       if (bar != null) { |       if (bar != null) { | ||||||
|         if (msg.isNullOrEmpty()) { |         if (message.isNullOrEmpty()) { | ||||||
|           bar.info = "" |           bar.info = "" | ||||||
|         } else { |         } else { | ||||||
|           bar.info = "VIM - $msg" |           bar.info = "VIM - $message" | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -3,14 +3,14 @@ package com.maddyhome.idea.vim.newapi | |||||||
| import com.intellij.openapi.components.Service | import com.intellij.openapi.components.Service | ||||||
| import com.maddyhome.idea.vim.api.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.VimSearchHelper | import com.maddyhome.idea.vim.api.VimSearchHelperBase | ||||||
| import com.maddyhome.idea.vim.common.TextRange | import com.maddyhome.idea.vim.common.TextRange | ||||||
| import com.maddyhome.idea.vim.helper.SearchHelper | import com.maddyhome.idea.vim.helper.SearchHelper | ||||||
| import com.maddyhome.idea.vim.helper.SearchOptions | import com.maddyhome.idea.vim.helper.SearchOptions | ||||||
| import java.util.* | import java.util.* | ||||||
|  |  | ||||||
| @Service | @Service | ||||||
| class IjVimSearchHelper : VimSearchHelper { | class IjVimSearchHelper : VimSearchHelperBase() { | ||||||
|   override fun findNextParagraph(editor: VimEditor, caret: VimCaret, count: Int, allowBlanks: Boolean): Int { |   override fun findNextParagraph(editor: VimEditor, caret: VimCaret, count: Int, allowBlanks: Boolean): Int { | ||||||
|     return SearchHelper.findNextParagraph( |     return SearchHelper.findNextParagraph( | ||||||
|       (editor as IjVimEditor).editor, |       (editor as IjVimEditor).editor, | ||||||
| @@ -121,15 +121,6 @@ class IjVimSearchHelper : VimSearchHelper { | |||||||
|     return SearchHelper.findNextWordEnd(chars, pos, size, count, bigWord, spaceWords) |     return SearchHelper.findNextWordEnd(chars, pos, size, count, bigWord, spaceWords) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override fun findNextWord(editor: VimEditor, searchFrom: Int, count: Int, bigWord: Boolean): Int { |  | ||||||
|     return SearchHelper.findNextWord( |  | ||||||
|       (editor as IjVimEditor).editor, |  | ||||||
|       searchFrom, |  | ||||||
|       count, |  | ||||||
|       bigWord |  | ||||||
|     ) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   override fun findPattern( |   override fun findPattern( | ||||||
|     editor: VimEditor, |     editor: VimEditor, | ||||||
|     pattern: String?, |     pattern: String?, | ||||||
|   | |||||||
| @@ -22,18 +22,25 @@ import com.maddyhome.idea.vim.api.injector | |||||||
| import com.maddyhome.idea.vim.options.OptionConstants | import com.maddyhome.idea.vim.options.OptionConstants | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName | import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName | ||||||
| import com.maddyhome.idea.vim.options.OptionConstants.Companion.smartcaseName | import com.maddyhome.idea.vim.options.OptionConstants.Companion.smartcaseName | ||||||
|  | import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutName | ||||||
|  | import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutlenName | ||||||
| import com.maddyhome.idea.vim.options.OptionScope | import com.maddyhome.idea.vim.options.OptionScope | ||||||
| import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper | import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper | ||||||
| import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService | import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * COMPATIBILITY-LAYER: Added a class and package |  * COMPATIBILITY-LAYER: Added a class and package | ||||||
|  |  * Please see: https://jb.gg/zo8n0r | ||||||
|  */ |  */ | ||||||
| object OptionsManager { | object OptionsManager { | ||||||
|   val ignorecase: ToggleOption |   val ignorecase: ToggleOption | ||||||
|     get() = (injector.optionService as IjVimOptionService).getRawOption(ignorecaseName) as ToggleOption |     get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(ignorecaseName) as ToggleOption | ||||||
|   val smartcase: ToggleOption |   val smartcase: ToggleOption | ||||||
|     get() = (injector.optionService as IjVimOptionService).getRawOption(smartcaseName) as ToggleOption |     get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(smartcaseName) as ToggleOption | ||||||
|  |   val timeout: ToggleOption | ||||||
|  |     get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(timeoutName) as ToggleOption | ||||||
|  |   val timeoutlen: NumberOption | ||||||
|  |     get() = (injector.optionService as IjVimOptionService).getOptionByNameOrAbbr(timeoutlenName) as NumberOption | ||||||
|   val iskeyword: KeywordOption |   val iskeyword: KeywordOption | ||||||
|     get() = KeywordOption(KeywordOptionHelper) |     get() = KeywordOption(KeywordOptionHelper) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.statistic | package com.maddyhome.idea.vim.statistic | ||||||
|  |  | ||||||
|  | import com.intellij.internal.statistic.collectors.fus.actions.persistence.ActionRuleValidator | ||||||
| import com.intellij.internal.statistic.eventLog.EventLogGroup | import com.intellij.internal.statistic.eventLog.EventLogGroup | ||||||
| import com.intellij.internal.statistic.eventLog.events.EventFields | import com.intellij.internal.statistic.eventLog.events.EventFields | ||||||
| import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector | import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector | ||||||
| @@ -25,8 +26,14 @@ import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesColle | |||||||
| internal class ActionTracker : CounterUsagesCollector() { | internal class ActionTracker : CounterUsagesCollector() { | ||||||
|   companion object { |   companion object { | ||||||
|     private val GROUP = EventLogGroup("vim.actions", 1) |     private val GROUP = EventLogGroup("vim.actions", 1) | ||||||
|     private val TRACKED_ACTIONS = GROUP.registerEvent("tracked", EventFields.StringValidatedByCustomRule("action_id", "action")) |     private val TRACKED_ACTIONS = GROUP.registerEvent( | ||||||
|     private val COPIED_ACTIONS = GROUP.registerEvent("copied", EventFields.StringValidatedByCustomRule("action_id", "action")) |       "tracked", | ||||||
|  |       EventFields.StringValidatedByCustomRule("action_id", ActionRuleValidator::class.java) | ||||||
|  |     ) | ||||||
|  |     private val COPIED_ACTIONS = GROUP.registerEvent( | ||||||
|  |       "copied", | ||||||
|  |       EventFields.StringValidatedByCustomRule("action_id", ActionRuleValidator::class.java) | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     fun logTrackedAction(actionId: String) { |     fun logTrackedAction(actionId: String) { | ||||||
|       TRACKED_ACTIONS.log(actionId) |       TRACKED_ACTIONS.log(actionId) | ||||||
|   | |||||||
| @@ -21,15 +21,14 @@ package com.maddyhome.idea.vim.statistic | |||||||
| import com.intellij.internal.statistic.beans.MetricEvent | import com.intellij.internal.statistic.beans.MetricEvent | ||||||
| import com.intellij.internal.statistic.eventLog.EventLogGroup | import com.intellij.internal.statistic.eventLog.EventLogGroup | ||||||
| import com.intellij.internal.statistic.eventLog.events.EventFields | import com.intellij.internal.statistic.eventLog.events.EventFields | ||||||
| import com.intellij.internal.statistic.eventLog.events.EventPair |  | ||||||
| import com.intellij.internal.statistic.eventLog.events.StringListEventField |  | ||||||
| import com.intellij.internal.statistic.eventLog.events.VarargEventId |  | ||||||
| import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector | import com.intellij.internal.statistic.service.fus.collectors.ApplicationUsagesCollector | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.key.ShortcutOwner | import com.maddyhome.idea.vim.key.ShortcutOwner | ||||||
| import com.maddyhome.idea.vim.key.ShortcutOwnerInfo | import com.maddyhome.idea.vim.key.ShortcutOwnerInfo | ||||||
|  | import java.awt.event.InputEvent | ||||||
| import java.awt.event.InputEvent.CTRL_DOWN_MASK | import java.awt.event.InputEvent.CTRL_DOWN_MASK | ||||||
| import java.awt.event.InputEvent.SHIFT_DOWN_MASK | import java.awt.event.InputEvent.SHIFT_DOWN_MASK | ||||||
|  | import java.awt.event.KeyEvent | ||||||
| import javax.swing.KeyStroke | import javax.swing.KeyStroke | ||||||
|  |  | ||||||
| internal class ShortcutConflictState : ApplicationUsagesCollector() { | internal class ShortcutConflictState : ApplicationUsagesCollector() { | ||||||
| @@ -37,93 +36,15 @@ internal class ShortcutConflictState : ApplicationUsagesCollector() { | |||||||
|   override fun getGroup(): EventLogGroup = GROUP |   override fun getGroup(): EventLogGroup = GROUP | ||||||
|  |  | ||||||
|   override fun getMetrics(): Set<MetricEvent> { |   override fun getMetrics(): Set<MetricEvent> { | ||||||
|     return setOf( |     val metrics = mutableSetOf<MetricEvent>() | ||||||
|       HANDLERS.metric( |     keyStrokes.forEach { keystroke -> | ||||||
|         CTRL_1 withKeyStroke KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK), |       getHandlersForShortcut(keystroke) | ||||||
|         CTRL_2 withKeyStroke KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK), |         .filter { !setOf(HandledModes.INSERT_UNDEFINED, HandledModes.NORMAL_UNDEFINED, HandledModes.VISUAL_AND_SELECT_UNDEFINED).contains(it) } | ||||||
|         CTRL_3 withKeyStroke KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK), |         .forEach { mode -> | ||||||
|         CTRL_4 withKeyStroke KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK), |           metrics += HANDLER.metric(keystroke.toReadableString(), mode) | ||||||
|         CTRL_5 withKeyStroke KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_6 withKeyStroke KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_7 withKeyStroke KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_8 withKeyStroke KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_9 withKeyStroke KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_0 withKeyStroke KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK), |  | ||||||
|  |  | ||||||
|         CTRL_SHIFT_1 withKeyStroke KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_2 withKeyStroke KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_3 withKeyStroke KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_4 withKeyStroke KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_5 withKeyStroke KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_6 withKeyStroke KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_7 withKeyStroke KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_8 withKeyStroke KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_9 withKeyStroke KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_0 withKeyStroke KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|  |  | ||||||
|         CTRL_A withKeyStroke KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_B withKeyStroke KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_C withKeyStroke KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_D withKeyStroke KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_E withKeyStroke KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_F withKeyStroke KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_G withKeyStroke KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_H withKeyStroke KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_I withKeyStroke KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_J withKeyStroke KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_K withKeyStroke KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_L withKeyStroke KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_M withKeyStroke KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_N withKeyStroke KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_O withKeyStroke KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_P withKeyStroke KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_Q withKeyStroke KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_R withKeyStroke KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_S withKeyStroke KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_T withKeyStroke KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_U withKeyStroke KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_V withKeyStroke KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_W withKeyStroke KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_X withKeyStroke KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_Y withKeyStroke KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_Z withKeyStroke KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_BR1 withKeyStroke KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK), |  | ||||||
|         CTRL_BR2 withKeyStroke KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK), |  | ||||||
|  |  | ||||||
|         CTRL_SHIFT_A withKeyStroke KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_B withKeyStroke KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_C withKeyStroke KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_D withKeyStroke KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_E withKeyStroke KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_F withKeyStroke KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_G withKeyStroke KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_H withKeyStroke KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_I withKeyStroke KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_J withKeyStroke KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_K withKeyStroke KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_L withKeyStroke KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_M withKeyStroke KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_N withKeyStroke KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_O withKeyStroke KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_P withKeyStroke KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_Q withKeyStroke KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_R withKeyStroke KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_S withKeyStroke KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_T withKeyStroke KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_U withKeyStroke KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_V withKeyStroke KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_W withKeyStroke KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_X withKeyStroke KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_Y withKeyStroke KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_Z withKeyStroke KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_BR1 withKeyStroke KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|         CTRL_SHIFT_BR2 withKeyStroke KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), |  | ||||||
|       ) |  | ||||||
|     ) |  | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|   private infix fun StringListEventField.withKeyStroke(ks: KeyStroke): EventPair<List<String>> { |     return metrics | ||||||
|     return this.with(getHandlersForShortcut(ks).map { it.name }) |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private fun getHandlersForShortcut(shortcut: KeyStroke): List<HandledModes> { |   private fun getHandlersForShortcut(shortcut: KeyStroke): List<HandledModes> { | ||||||
| @@ -162,173 +83,105 @@ internal class ShortcutConflictState : ApplicationUsagesCollector() { | |||||||
|  |  | ||||||
|   companion object { |   companion object { | ||||||
|     private val GROUP = EventLogGroup("vim.handlers", 1) |     private val GROUP = EventLogGroup("vim.handlers", 1) | ||||||
|     private val values = HandledModes.values().map { it.name } |  | ||||||
|  |  | ||||||
|     private val CTRL_1 = EventFields.StringList("Ctrl-1", values) |     private val keyStrokes = listOf( | ||||||
|     private val CTRL_2 = EventFields.StringList("Ctrl-2", values) |       KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_3 = EventFields.StringList("Ctrl-3", values) |       KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_4 = EventFields.StringList("Ctrl-4", values) |       KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_5 = EventFields.StringList("Ctrl-5", values) |       KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_6 = EventFields.StringList("Ctrl-6", values) |       KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_7 = EventFields.StringList("Ctrl-7", values) |       KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_8 = EventFields.StringList("Ctrl-8", values) |       KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_9 = EventFields.StringList("Ctrl-9", values) |       KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_0 = EventFields.StringList("Ctrl-0", values) |       KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK), | ||||||
|  |       KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK), | ||||||
|  |  | ||||||
|     private val CTRL_SHIFT_1 = EventFields.StringList("Ctrl-Shift-1", values) |       KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_2 = EventFields.StringList("Ctrl-Shift-2", values) |       KeyStroke.getKeyStroke('2'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_3 = EventFields.StringList("Ctrl-Shift-3", values) |       KeyStroke.getKeyStroke('3'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_4 = EventFields.StringList("Ctrl-Shift-4", values) |       KeyStroke.getKeyStroke('4'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_5 = EventFields.StringList("Ctrl-Shift-5", values) |       KeyStroke.getKeyStroke('5'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_6 = EventFields.StringList("Ctrl-Shift-6", values) |       KeyStroke.getKeyStroke('6'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_7 = EventFields.StringList("Ctrl-Shift-7", values) |       KeyStroke.getKeyStroke('7'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_8 = EventFields.StringList("Ctrl-Shift-8", values) |       KeyStroke.getKeyStroke('8'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_9 = EventFields.StringList("Ctrl-Shift-9", values) |       KeyStroke.getKeyStroke('9'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_0 = EventFields.StringList("Ctrl-Shift-0", values) |       KeyStroke.getKeyStroke('0'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|  |  | ||||||
|     private val CTRL_A = EventFields.StringList("Ctrl-A", values) |       KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_B = EventFields.StringList("Ctrl-B", values) |       KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_C = EventFields.StringList("Ctrl-C", values) |       KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_D = EventFields.StringList("Ctrl-D", values) |       KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_E = EventFields.StringList("Ctrl-E", values) |       KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_F = EventFields.StringList("Ctrl-F", values) |       KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_G = EventFields.StringList("Ctrl-G", values) |       KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_H = EventFields.StringList("Ctrl-H", values) |       KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_I = EventFields.StringList("Ctrl-I", values) |       KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_J = EventFields.StringList("Ctrl-J", values) |       KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_K = EventFields.StringList("Ctrl-K", values) |       KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_L = EventFields.StringList("Ctrl-L", values) |       KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_M = EventFields.StringList("Ctrl-M", values) |       KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_N = EventFields.StringList("Ctrl-N", values) |       KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_O = EventFields.StringList("Ctrl-O", values) |       KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_P = EventFields.StringList("Ctrl-P", values) |       KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_Q = EventFields.StringList("Ctrl-Q", values) |       KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_R = EventFields.StringList("Ctrl-R", values) |       KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_S = EventFields.StringList("Ctrl-S", values) |       KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_T = EventFields.StringList("Ctrl-T", values) |       KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_U = EventFields.StringList("Ctrl-U", values) |       KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_V = EventFields.StringList("Ctrl-V", values) |       KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_W = EventFields.StringList("Ctrl-W", values) |       KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_X = EventFields.StringList("Ctrl-X", values) |       KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_Y = EventFields.StringList("Ctrl-Y", values) |       KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_Z = EventFields.StringList("Ctrl-Z", values) |       KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_BR1 = EventFields.StringList("Ctrl-[", values) |       KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK), | ||||||
|     private val CTRL_BR2 = EventFields.StringList("Ctrl-]", values) |       KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK), | ||||||
|  |  | ||||||
|     private val CTRL_SHIFT_A = EventFields.StringList("Ctrl-Shift-A", values) |       KeyStroke.getKeyStroke('A'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_B = EventFields.StringList("Ctrl-Shift-B", values) |       KeyStroke.getKeyStroke('B'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_C = EventFields.StringList("Ctrl-Shift-C", values) |       KeyStroke.getKeyStroke('C'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_D = EventFields.StringList("Ctrl-Shift-D", values) |       KeyStroke.getKeyStroke('D'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_E = EventFields.StringList("Ctrl-Shift-E", values) |       KeyStroke.getKeyStroke('E'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_F = EventFields.StringList("Ctrl-Shift-F", values) |       KeyStroke.getKeyStroke('F'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_G = EventFields.StringList("Ctrl-Shift-G", values) |       KeyStroke.getKeyStroke('G'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_H = EventFields.StringList("Ctrl-Shift-H", values) |       KeyStroke.getKeyStroke('H'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_I = EventFields.StringList("Ctrl-Shift-I", values) |       KeyStroke.getKeyStroke('I'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_J = EventFields.StringList("Ctrl-Shift-J", values) |       KeyStroke.getKeyStroke('J'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_K = EventFields.StringList("Ctrl-Shift-K", values) |       KeyStroke.getKeyStroke('K'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_L = EventFields.StringList("Ctrl-Shift-L", values) |       KeyStroke.getKeyStroke('L'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_M = EventFields.StringList("Ctrl-Shift-M", values) |       KeyStroke.getKeyStroke('M'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_N = EventFields.StringList("Ctrl-Shift-N", values) |       KeyStroke.getKeyStroke('N'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_O = EventFields.StringList("Ctrl-Shift-O", values) |       KeyStroke.getKeyStroke('O'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_P = EventFields.StringList("Ctrl-Shift-P", values) |       KeyStroke.getKeyStroke('P'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_Q = EventFields.StringList("Ctrl-Shift-Q", values) |       KeyStroke.getKeyStroke('Q'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_R = EventFields.StringList("Ctrl-Shift-R", values) |       KeyStroke.getKeyStroke('R'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_S = EventFields.StringList("Ctrl-Shift-S", values) |       KeyStroke.getKeyStroke('S'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_T = EventFields.StringList("Ctrl-Shift-T", values) |       KeyStroke.getKeyStroke('T'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_U = EventFields.StringList("Ctrl-Shift-U", values) |       KeyStroke.getKeyStroke('U'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_V = EventFields.StringList("Ctrl-Shift-V", values) |       KeyStroke.getKeyStroke('V'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_W = EventFields.StringList("Ctrl-Shift-W", values) |       KeyStroke.getKeyStroke('W'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_X = EventFields.StringList("Ctrl-Shift-X", values) |       KeyStroke.getKeyStroke('X'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_Y = EventFields.StringList("Ctrl-Shift-Y", values) |       KeyStroke.getKeyStroke('Y'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_Z = EventFields.StringList("Ctrl-Shift-Z", values) |       KeyStroke.getKeyStroke('Z'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_BR1 = EventFields.StringList("Ctrl-Shift-[", values) |       KeyStroke.getKeyStroke('['.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|     private val CTRL_SHIFT_BR2 = EventFields.StringList("Ctrl-Shift-]", values) |       KeyStroke.getKeyStroke(']'.code, CTRL_DOWN_MASK + SHIFT_DOWN_MASK), | ||||||
|  |  | ||||||
|     private val HANDLERS: VarargEventId = GROUP.registerVarargEvent( |  | ||||||
|       "vim.handlers", |  | ||||||
|       CTRL_1, |  | ||||||
|       CTRL_2, |  | ||||||
|       CTRL_3, |  | ||||||
|       CTRL_4, |  | ||||||
|       CTRL_5, |  | ||||||
|       CTRL_6, |  | ||||||
|       CTRL_7, |  | ||||||
|       CTRL_8, |  | ||||||
|       CTRL_9, |  | ||||||
|       CTRL_0, |  | ||||||
|  |  | ||||||
|       CTRL_SHIFT_1, |  | ||||||
|       CTRL_SHIFT_2, |  | ||||||
|       CTRL_SHIFT_3, |  | ||||||
|       CTRL_SHIFT_4, |  | ||||||
|       CTRL_SHIFT_5, |  | ||||||
|       CTRL_SHIFT_6, |  | ||||||
|       CTRL_SHIFT_7, |  | ||||||
|       CTRL_SHIFT_8, |  | ||||||
|       CTRL_SHIFT_9, |  | ||||||
|       CTRL_SHIFT_0, |  | ||||||
|  |  | ||||||
|       CTRL_A, |  | ||||||
|       CTRL_B, |  | ||||||
|       CTRL_C, |  | ||||||
|       CTRL_D, |  | ||||||
|       CTRL_E, |  | ||||||
|       CTRL_F, |  | ||||||
|       CTRL_G, |  | ||||||
|       CTRL_H, |  | ||||||
|       CTRL_I, |  | ||||||
|       CTRL_J, |  | ||||||
|       CTRL_K, |  | ||||||
|       CTRL_L, |  | ||||||
|       CTRL_M, |  | ||||||
|       CTRL_N, |  | ||||||
|       CTRL_O, |  | ||||||
|       CTRL_P, |  | ||||||
|       CTRL_Q, |  | ||||||
|       CTRL_R, |  | ||||||
|       CTRL_S, |  | ||||||
|       CTRL_T, |  | ||||||
|       CTRL_U, |  | ||||||
|       CTRL_V, |  | ||||||
|       CTRL_W, |  | ||||||
|       CTRL_X, |  | ||||||
|       CTRL_Y, |  | ||||||
|       CTRL_Z, |  | ||||||
|       CTRL_BR1, |  | ||||||
|       CTRL_BR2, |  | ||||||
|  |  | ||||||
|       CTRL_SHIFT_A, |  | ||||||
|       CTRL_SHIFT_B, |  | ||||||
|       CTRL_SHIFT_C, |  | ||||||
|       CTRL_SHIFT_D, |  | ||||||
|       CTRL_SHIFT_E, |  | ||||||
|       CTRL_SHIFT_F, |  | ||||||
|       CTRL_SHIFT_G, |  | ||||||
|       CTRL_SHIFT_H, |  | ||||||
|       CTRL_SHIFT_I, |  | ||||||
|       CTRL_SHIFT_J, |  | ||||||
|       CTRL_SHIFT_K, |  | ||||||
|       CTRL_SHIFT_L, |  | ||||||
|       CTRL_SHIFT_M, |  | ||||||
|       CTRL_SHIFT_N, |  | ||||||
|       CTRL_SHIFT_O, |  | ||||||
|       CTRL_SHIFT_P, |  | ||||||
|       CTRL_SHIFT_Q, |  | ||||||
|       CTRL_SHIFT_R, |  | ||||||
|       CTRL_SHIFT_S, |  | ||||||
|       CTRL_SHIFT_T, |  | ||||||
|       CTRL_SHIFT_U, |  | ||||||
|       CTRL_SHIFT_V, |  | ||||||
|       CTRL_SHIFT_W, |  | ||||||
|       CTRL_SHIFT_X, |  | ||||||
|       CTRL_SHIFT_Y, |  | ||||||
|       CTRL_SHIFT_Z, |  | ||||||
|       CTRL_SHIFT_BR1, |  | ||||||
|       CTRL_SHIFT_BR2, |  | ||||||
|     ) |     ) | ||||||
|  |     private val KEY_STROKE = EventFields.String("key_stroke", keyStrokes.map { it.toReadableString() }) | ||||||
|  |     private val HANDLER_MODE = EventFields.Enum<HandledModes>("handler") | ||||||
|  |     private val HANDLER = GROUP.registerEvent("vim.handler", KEY_STROKE, HANDLER_MODE) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | private fun KeyStroke.toReadableString(): String { | ||||||
|  |   val result = StringBuilder() | ||||||
|  |   val modifiers = this.modifiers | ||||||
|  |   if (modifiers > 0) { | ||||||
|  |     result.append(InputEvent.getModifiersExText(modifiers)) | ||||||
|  |       .append("+") | ||||||
|  |   } | ||||||
|  |   result.append(KeyEvent.getKeyText(this.keyCode)) | ||||||
|  |   return result.toString() | ||||||
|  | } | ||||||
|  |  | ||||||
| private enum class HandledModes { | private enum class HandledModes { | ||||||
|   NORMAL_UNDEFINED, |   NORMAL_UNDEFINED, | ||||||
|   NORMAL_IDE, |   NORMAL_IDE, | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user