mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-11-04 01:40:12 +01:00 
			
		
		
		
	Compare commits
	
		
			120 Commits
		
	
	
		
			customized
			...
			976791ac95
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						976791ac95
	
				 | 
					
					
						|||
| 
						
						
							
						
						9b30831b2f
	
				 | 
					
					
						|||
| 
						
						
							
						
						0c3544c1fe
	
				 | 
					
					
						|||
| 
						
						
							
						
						29813f12fb
	
				 | 
					
					
						|||
| 
						
						
							
						
						0bb5739adc
	
				 | 
					
					
						|||
| 
						
						
							
						
						4e5e94cd98
	
				 | 
					
					
						|||
| 
						
						
							
						
						8b6925e5e4
	
				 | 
					
					
						|||
| 
						
						
							
						
						e451ebf361
	
				 | 
					
					
						|||
| 
						
						
							
						
						056d704297
	
				 | 
					
					
						|||
| 
						
						
							
						
						dbb0f79113
	
				 | 
					
					
						|||
| 
						
						
							
						
						1bc6dfac1c
	
				 | 
					
					
						|||
| 
						
						
							
						
						de449adcb9
	
				 | 
					
					
						|||
| 
						
						
							
						
						2ef9742b71
	
				 | 
					
					
						|||
| 
						
						
							
						
						a2833aa088
	
				 | 
					
					
						|||
| 
						
						
							
						
						13ebac83c6
	
				 | 
					
					
						|||
| 
						 | 
					c3134b9426 | ||
| 
						 | 
					06c036d373 | ||
| 
						 | 
					2f8bd29725 | ||
| 
						 | 
					1eae211b41 | ||
| 
						 | 
					b02eb7a422 | ||
| 
						 | 
					3db31e9347 | ||
| 
						 | 
					1dc6045ae1 | ||
| 
						 | 
					2436164b1e | ||
| 
						 | 
					c13fc8a805 | ||
| 
						 | 
					41025d78de | ||
| 
						 | 
					b3ad222cdc | ||
| 
						 | 
					efd9ed0a5f | ||
| 
						 | 
					9d20061924 | ||
| 
						 | 
					ddfe8cf361 | ||
| 
						 | 
					93c83f773a | ||
| 
						 | 
					876e16fa9e | ||
| 
						 | 
					37067d5c72 | ||
| 
						 | 
					083ac8cfa3 | ||
| 
						 | 
					fe6c1ae452 | ||
| 
						 | 
					30165f5047 | ||
| 
						 | 
					3046c61447 | ||
| 
						 | 
					ced50bb2e8 | ||
| 
						 | 
					dee84bcc63 | ||
| 
						 | 
					0f0bafb66a | ||
| 
						 | 
					7cdc3611a5 | ||
| 
						 | 
					6eda6aebba | ||
| 
						 | 
					2d23c81ebb | ||
| 
						 | 
					5602058849 | ||
| 
						 | 
					b1ec021c1e | ||
| 
						 | 
					7073b2410b | ||
| 
						 | 
					ab9068bc0a | ||
| 
						 | 
					0c66fb474e | ||
| 
						 | 
					fef6c651ea | ||
| 
						 | 
					620f54344f | ||
| 
						 | 
					ef1259a87a | ||
| 
						 | 
					5ef4af6b55 | ||
| 
						 | 
					6d17304e4e | ||
| 
						 | 
					2e4062b5db | ||
| 
						 | 
					b294bdd013 | ||
| 
						 | 
					dc95c7fc2c | ||
| 
						 | 
					dfe8c43c33 | ||
| 
						 | 
					3e54ad5a68 | ||
| 
						 | 
					288c66d8a2 | ||
| 
						 | 
					44c8a97f44 | ||
| 
						 | 
					60c27b1dea | ||
| 
						 | 
					ce8b77b240 | ||
| 
						 | 
					718c5fb30e | ||
| 419160724c | |||
| 
						 | 
					c905dfe6d8 | ||
| 
						 | 
					70eb008412 | ||
| 
						 | 
					93feaadacf | ||
| 
						 | 
					0b7610607d | ||
| 
						 | 
					922fea5395 | ||
| 
						 | 
					1841b7c4e6 | ||
| 
						 | 
					ed966faaf4 | ||
| 
						 | 
					03efeed6ae | ||
| 
						 | 
					675c5ae480 | ||
| 
						 | 
					d575b22e2e | ||
| 
						 | 
					5e4ee1b60f | ||
| 
						 | 
					d8ce20c2f9 | ||
| 
						 | 
					b164dc1b55 | ||
| 
						 | 
					530eba3d00 | ||
| 
						 | 
					808066f2e2 | ||
| 
						 | 
					cb3e683c8e | ||
| 
						 | 
					6ff57775ed | ||
| 
						 | 
					6c07687a86 | ||
| 
						 | 
					497a8c19c5 | ||
| 
						 | 
					c13f7468ef | ||
| 
						 | 
					847872cdb6 | ||
| 
						 | 
					f0abe5d80d | ||
| 
						 | 
					465c5b9e77 | ||
| fb78cdd304 | |||
| 
						 | 
					5b17fe2410 | ||
| 
						 | 
					5fd54dccd3 | ||
| 
						 | 
					1695afd915 | ||
| 
						 | 
					5ab549ae96 | ||
| 
						 | 
					35123e7c1e | ||
| 
						 | 
					1badade841 | ||
| 
						 | 
					b357625529 | ||
| 
						 | 
					9ccd39d724 | ||
| 
						 | 
					c876079e04 | ||
| 
						 | 
					162c1c59fe | ||
| 
						 | 
					06ef1c1182 | ||
| 
						 | 
					a9ba9789fd | ||
| 
						 | 
					fdd32cb954 | ||
| 
						 | 
					9fd7d86998 | ||
| 
						 | 
					5973903313 | ||
| 
						 | 
					75e4b19b88 | ||
| 
						 | 
					af7bdb55a1 | ||
| 
						 | 
					69af9aeff0 | ||
| 
						 | 
					88f4192d61 | ||
| 
						 | 
					96db8a326e | ||
| 
						 | 
					8c06767fdc | ||
| 
						 | 
					25877e369b | ||
| 
						 | 
					0271a475a2 | ||
| 
						 | 
					eef3ab5a15 | ||
| 
						 | 
					26f48c5820 | ||
| 
						 | 
					236ca36c79 | ||
| 
						 | 
					405b9ba7ea | ||
| 
						 | 
					ab9bd76d34 | ||
| 
						 | 
					677da7d80a | ||
| 
						 | 
					b3ad2fd715 | ||
| 
						 | 
					97ca6ce5b8 | ||
| 
						 | 
					e1abc4374e | ||
| 
						 | 
					9eeeb15c6c | 
							
								
								
									
										1
									
								
								.github/workflows/checkNewPlugins.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/checkNewPlugins.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Fetch origin repo
 | 
					      - name: Fetch origin repo
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/closeYoutrackOnCommit.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/closeYoutrackOnCommit.yml
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v3
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/integrationsTest.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/integrationsTest.yml
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/kover.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/kover.yml
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/mergeDependabotPR.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/mergeDependabotPR.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ permissions:
 | 
				
			|||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  dependabot:
 | 
					  dependabot:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    if: ${{ github.actor == 'dependabot[bot]' }}
 | 
					    if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'JetBrains/ideavim' }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Auto-merge Dependabot PR
 | 
					      - name: Auto-merge Dependabot PR
 | 
				
			||||||
        run: gh pr merge --auto --rebase "$PR_URL"
 | 
					        run: gh pr merge --auto --rebase "$PR_URL"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ on:
 | 
				
			|||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if: github.event.pull_request.merged == true
 | 
					    if: github.event.pull_request.merged == true && github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/runUiTests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/runUiTests.yml
									
									
									
									
										vendored
									
									
								
							@@ -5,6 +5,7 @@ on:
 | 
				
			|||||||
      - cron: '0 12 * * *'
 | 
					      - cron: '0 12 * * *'
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build-for-ui-test-mac-os:
 | 
					  build-for-ui-test-mac-os:
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
    runs-on: macos-latest
 | 
					    runs-on: macos-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/syncDoc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/syncDoc.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Fetch origin repo
 | 
					      - name: Fetch origin repo
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/updateAffectedRate.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/updateAffectedRate.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Fetch origin repo
 | 
					      - name: Fetch origin repo
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/updateAuthors.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/updateAuthors.yml
									
									
									
									
										vendored
									
									
								
							@@ -15,6 +15,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v3
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/updateChangelog.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/updateChangelog.yml
									
									
									
									
										vendored
									
									
								
							@@ -15,6 +15,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v3
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/updateFormatting.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/updateFormatting.yml
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,7 @@ jobs:
 | 
				
			|||||||
  build:
 | 
					  build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    if: github.repository == 'JetBrains/ideavim'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -23,6 +23,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Generated by gradle task "generateGrammarSource"
 | 
					# Generated by gradle task "generateGrammarSource"
 | 
				
			||||||
src/main/java/com/maddyhome/idea/vim/vimscript/parser/generated
 | 
					src/main/java/com/maddyhome/idea/vim/vimscript/parser/generated
 | 
				
			||||||
 | 
					# Generated JSONs for lazy classloading
 | 
				
			||||||
 | 
					/vim-engine/src/main/resources/ksp-generated
 | 
				
			||||||
 | 
					/src/main/resources/ksp-generated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Created by github automation
 | 
					# Created by github automation
 | 
				
			||||||
settings.xml
 | 
					settings.xml
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.teamcity/_Self/Constants.kt
									
									
									
									
										vendored
									
									
								
							@@ -5,13 +5,11 @@ 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 = "2.4.0"
 | 
					  const val GITHUB_TESTS = "2023.1.2"
 | 
				
			||||||
 | 
					  const val NVIM_TESTS = "2023.1.2"
 | 
				
			||||||
  const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT"
 | 
					  const val PROPERTY_TESTS = "2023.1.2"
 | 
				
			||||||
  const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT"
 | 
					  const val LONG_RUNNING_TESTS = "2023.1.2"
 | 
				
			||||||
  const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT"
 | 
					  const val QODANA_TESTS = "2023.1.2"
 | 
				
			||||||
  const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT"
 | 
					 | 
				
			||||||
  const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT"
 | 
					 | 
				
			||||||
  const val RELEASE = "2023.1.2"
 | 
					  const val RELEASE = "2023.1.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const val RELEASE_DEV = "2023.1.2"
 | 
					  const val RELEASE_DEV = "2023.1.2"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							@@ -23,6 +23,8 @@ object Project : Project({
 | 
				
			|||||||
  vcsRoot(GitHubPullRequest)
 | 
					  vcsRoot(GitHubPullRequest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Active tests
 | 
					  // Active tests
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("2023.2", "<default>", version = "2023.2.3"))
 | 
				
			||||||
 | 
					  buildType(TestingBuildType("2023.1", "<default>", version = "2023.1.5"))
 | 
				
			||||||
  buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
					  buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
				
			||||||
  buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
					  buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.teamcity/_Self/buildTypes/ReleasePlugin.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.teamcity/_Self/buildTypes/ReleasePlugin.kt
									
									
									
									
										vendored
									
									
								
							@@ -118,6 +118,7 @@ sealed class ReleasePlugin(private val releaseType: String) : IdeaVimBuildType({
 | 
				
			|||||||
      then
 | 
					      then
 | 
				
			||||||
        git checkout release
 | 
					        git checkout release
 | 
				
			||||||
        echo checkout release branch
 | 
					        echo checkout release branch
 | 
				
			||||||
 | 
					        git branch --set-upstream-to=origin/release release
 | 
				
			||||||
        git push --tags
 | 
					        git push --tags
 | 
				
			||||||
        git push origin --force
 | 
					        git push origin --force
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								.teamcity/patches/buildTypes/ReleaseMinor.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.teamcity/patches/buildTypes/ReleaseMinor.kts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package patches.buildTypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.*
 | 
				
			||||||
 | 
					import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					This patch script was generated by TeamCity on settings change in UI.
 | 
				
			||||||
 | 
					To apply the patch, change the buildType with id = 'ReleaseMinor'
 | 
				
			||||||
 | 
					accordingly, and delete the patch script.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					changeBuildType(RelativeId("ReleaseMinor")) {
 | 
				
			||||||
 | 
					    params {
 | 
				
			||||||
 | 
					        expect {
 | 
				
			||||||
 | 
					            password("env.ORG_GRADLE_PROJECT_youtrackToken", "credentialsJSON:3cd3e867-282c-451f-b958-bc95d56a8450", display = ParameterDisplay.HIDDEN)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        update {
 | 
				
			||||||
 | 
					            password("env.ORG_GRADLE_PROJECT_youtrackToken", "credentialsJSON:7bc0eb3a-b86a-4ebd-b622-d4ef12d7e1d3", display = ParameterDisplay.HIDDEN)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -483,6 +483,10 @@ Contributors:
 | 
				
			|||||||
  [![icon][github]](https://github.com/ludwig-jb)
 | 
					  [![icon][github]](https://github.com/ludwig-jb)
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
  ludwig-jb
 | 
					  ludwig-jb
 | 
				
			||||||
 | 
					* [![icon][mail]](mailto:pvydmuch@gmail.com)
 | 
				
			||||||
 | 
					  [![icon][github]](https://github.com/pWydmuch)
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					  pWydmuch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Previous contributors:
 | 
					Previous contributors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										42
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								CHANGES.md
									
									
									
									
									
								
							@@ -25,11 +25,53 @@ usual beta standards.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## To Be Released
 | 
					## To Be Released
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Fixes:
 | 
				
			||||||
 | 
					* [VIM-3130](https://youtrack.jetbrains.com/issue/VIM-3130) Change the build version to 2023.1.2
 | 
				
			||||||
 | 
					* [VIM-3168](https://youtrack.jetbrains.com/issue/VIM-3168) Do not switch to block caret after enter if the IdeaVim is disabled
 | 
				
			||||||
 | 
					* [VIM-3165](https://youtrack.jetbrains.com/issue/VIM-3165) Do not process enter key as IdeaVim shortcut if it's not an actual keypress
 | 
				
			||||||
 | 
					* [VIM-3159](https://youtrack.jetbrains.com/issue/VIM-3159) Shift-enter now works in normal mode again
 | 
				
			||||||
 | 
					* [VIM-3157](https://youtrack.jetbrains.com/issue/VIM-3157) Do not invoke enter in invokeLater for python console
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.7.0, 2023-11-07
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Fixes:
 | 
				
			||||||
 | 
					* [VIM-2933](https://youtrack.jetbrains.com/issue/VIM-2933) Reloading/sourcing .ideavimrc does not initialize new plugins
 | 
				
			||||||
 | 
					* [VIM-3138](https://youtrack.jetbrains.com/issue/VIM-3138) Do not try to register disposer if the caret is already disposed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Merged PRs:
 | 
				
			||||||
 | 
					* [734](https://github.com/JetBrains/ideavim/pull/734) by [Matt Ellis](https://github.com/citizenmatt): Support `~/` on Windows
 | 
				
			||||||
 | 
					* [736](https://github.com/JetBrains/ideavim/pull/736) by [chylex](https://github.com/chylex): Fix(VIM-2933): Reloading/sourcing .ideavimrc does not initialize new plugins
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.6.3, 2023-10-30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Changes:
 | 
				
			||||||
 | 
					- 2.6.0 and 2.6.1 releases are broken. Version 2.6.3 reverts IdeaVim plugin to the working state as for 2.5.1.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.6.0, 2023-10-27
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This version of IdeaVim contains a lot of issues. Version 2.6.3 reverts these changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Features:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `ShowHoverInfo` action can be used in mappings to open a tooltip that is shown by
 | 
				
			||||||
 | 
					  mouse hovering | [VIM-2106](https://youtrack.jetbrains.com/issue/VIM-2106)
 | 
				
			||||||
 | 
					* `has` Vim Script function supports the most common OS checks: win32, win64, linux, mac, macunix, osx, osxdarwin, bsd, sun, unix
 | 
				
			||||||
 | 
					  * See https://github.com/JetBrains/ideavim#vim-script for details about Vim Script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Fixes:
 | 
					### Fixes:
 | 
				
			||||||
* [VIM-3060](https://youtrack.jetbrains.com/issue/VIM-3060) Clipboard interaction stopped working
 | 
					* [VIM-3060](https://youtrack.jetbrains.com/issue/VIM-3060) Clipboard interaction stopped working
 | 
				
			||||||
 | 
					* [VIM-3095](https://youtrack.jetbrains.com/issue/VIM-3095) Fix missing ellipsis digraph
 | 
				
			||||||
 | 
					* [VIM-2562](https://youtrack.jetbrains.com/issue/VIM-2562) Fix hang with multi-width chars in command line
 | 
				
			||||||
 | 
					* [VIM-696](https://youtrack.jetbrains.com/issue/VIM-696) Vim selection issue after undo
 | 
				
			||||||
 | 
					* [VIM-1639](https://youtrack.jetbrains.com/issue/VIM-1639) Ctrl-o and Ctrl-i jumping in files of different projects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Merged PRs:
 | 
					### Merged PRs:
 | 
				
			||||||
* [697](https://github.com/JetBrains/ideavim/pull/697) by [Matt Ellis](https://github.com/citizenmatt): Support per-window "global" values for local-to-window options
 | 
					* [697](https://github.com/JetBrains/ideavim/pull/697) by [Matt Ellis](https://github.com/citizenmatt): Support per-window "global" values for local-to-window options
 | 
				
			||||||
 | 
					* [717](https://github.com/JetBrains/ideavim/pull/717) by [Matt Ellis](https://github.com/citizenmatt): Fix(VIM-2562): Fix hang with multi-width chars in command line
 | 
				
			||||||
 | 
					* [732](https://github.com/JetBrains/ideavim/pull/732) by [pWydmuch](https://github.com/pWydmuch): Fix md links in doc
 | 
				
			||||||
 | 
					* [733](https://github.com/JetBrains/ideavim/pull/733) by [Matt Ellis](https://github.com/citizenmatt): Add support for ShowHoverInfo action to 2023.1 and 2023.2
 | 
				
			||||||
 | 
					* [729](https://github.com/JetBrains/ideavim/pull/729) by [chylex](https://github.com/chylex): Add operating system type to `has()` function
 | 
				
			||||||
 | 
					* [726](https://github.com/JetBrains/ideavim/pull/726) by [Matt Ellis](https://github.com/citizenmatt): Fix range for fall back comment mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 2.5.0, 2023-09-01
 | 
					## 2.5.0, 2023-09-01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -255,8 +255,7 @@ Ex commands or via `:map` command mappings:
 | 
				
			|||||||
##### Some popular actions:
 | 
					##### Some popular actions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
QuickJavaDoc - Quick Documentation (not only for java, all languages)
 | 
					ShowHoverInfo - Quick Documentation and Error Description
 | 
				
			||||||
ShowErrorDescription - Show description of the error under the caret (cursor hovering)
 | 
					 | 
				
			||||||
QuickImplementations - Quick Definition
 | 
					QuickImplementations - Quick Definition
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  kotlin("jvm")
 | 
					  kotlin("jvm")
 | 
				
			||||||
 | 
					  kotlin("plugin.serialization") version "1.8.21"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group = "com.intellij"
 | 
					group = "com.intellij"
 | 
				
			||||||
@@ -18,6 +19,6 @@ repositories {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  compileOnly("com.google.devtools.ksp:symbol-processing-api:1.9.10-1.0.13")
 | 
					  compileOnly("com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14")
 | 
				
			||||||
  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.0")
 | 
					  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.0")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.intellij.vim.annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO support numpad keys parsing, see :keycodes
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * It's not necessary a Vim command
 | 
				
			||||||
 | 
					 * This annotation may be used for:
 | 
				
			||||||
 | 
					 * - commands
 | 
				
			||||||
 | 
					 * - motions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Target(AnnotationTarget.CLASS)
 | 
				
			||||||
 | 
					@Retention(AnnotationRetention.SOURCE)
 | 
				
			||||||
 | 
					annotation class CommandOrMotion(val keys: Array<String>, vararg val modes: Mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					annotation class TextObject(val keys: String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Mode(val abbrev: Char) {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Normal mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  NORMAL('N'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Visual mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  VISUAL('X'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Select mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  SELECT('S'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Operator Pending mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  OP_PENDING('O'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Insert mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  INSERT('I'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates this key mapping applies to Command Line mode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  CMD_LINE('C'),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.intellij.vim.processors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class CommandBean(val keys: String, val `class`: String, val modes: String)
 | 
				
			||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.intellij.vim.processors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.KspExperimental
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.getAnnotationsByType
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.Resolver
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.SymbolProcessor
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.symbol.KSAnnotated
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.symbol.KSClassDeclaration
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.symbol.KSFile
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.symbol.KSVisitorVoid
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import kotlinx.serialization.encodeToString
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import java.nio.file.Files
 | 
				
			||||||
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.writeText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironment): SymbolProcessor {
 | 
				
			||||||
 | 
					  private val visitor = CommandOrMotionVisitor()
 | 
				
			||||||
 | 
					  private val commands = mutableListOf<CommandBean>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val json = Json { prettyPrint = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun process(resolver: Resolver): List<KSAnnotated> {
 | 
				
			||||||
 | 
					    resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val generatedDirPath = Path(environment.options["generated_directory"]!!)
 | 
				
			||||||
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
 | 
				
			||||||
 | 
					    val fileContent = json.encodeToString(commands)
 | 
				
			||||||
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return emptyList()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private inner class CommandOrMotionVisitor : KSVisitorVoid() {
 | 
				
			||||||
 | 
					    @OptIn(KspExperimental::class)
 | 
				
			||||||
 | 
					    override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
 | 
				
			||||||
 | 
					      val commandAnnotation = classDeclaration.getAnnotationsByType(CommandOrMotion::class).firstOrNull() ?: return
 | 
				
			||||||
 | 
					      for (key in commandAnnotation.keys) {
 | 
				
			||||||
 | 
					        commands.add(
 | 
				
			||||||
 | 
					          CommandBean(key, classDeclaration.qualifiedName!!.asString(), commandAnnotation.modes.map { it.abbrev }.joinToString(separator = ""))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun visitFile(file: KSFile, data: Unit) {
 | 
				
			||||||
 | 
					      file.declarations.forEach { it.accept(this, Unit) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -20,6 +20,7 @@ import com.google.devtools.ksp.symbol.KSVisitorVoid
 | 
				
			|||||||
import com.intellij.vim.annotations.ExCommand
 | 
					import com.intellij.vim.annotations.ExCommand
 | 
				
			||||||
import kotlinx.serialization.encodeToString
 | 
					import kotlinx.serialization.encodeToString
 | 
				
			||||||
import kotlinx.serialization.json.Json
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import java.nio.file.Files
 | 
				
			||||||
import kotlin.io.path.Path
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
import kotlin.io.path.writeText
 | 
					import kotlin.io.path.writeText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,7 +32,11 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun process(resolver: Resolver): List<KSAnnotated> {
 | 
					  override fun process(resolver: Resolver): List<KSAnnotated> {
 | 
				
			||||||
    resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
 | 
					    resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
 | 
				
			||||||
    val filePath = Path(environment.options["generated_directory"]!!, environment.options["ex_commands_file"]!!)
 | 
					
 | 
				
			||||||
 | 
					    val generatedDirPath = Path(environment.options["generated_directory"]!!)
 | 
				
			||||||
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
 | 
				
			||||||
    val fileContent = json.encodeToString(commandToClass)
 | 
					    val fileContent = json.encodeToString(commandToClass)
 | 
				
			||||||
    filePath.writeText(fileContent)
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import com.google.devtools.ksp.symbol.KSVisitorVoid
 | 
				
			|||||||
import com.intellij.vim.annotations.VimscriptFunction
 | 
					import com.intellij.vim.annotations.VimscriptFunction
 | 
				
			||||||
import kotlinx.serialization.encodeToString
 | 
					import kotlinx.serialization.encodeToString
 | 
				
			||||||
import kotlinx.serialization.json.Json
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import java.nio.file.Files
 | 
				
			||||||
import kotlin.io.path.Path
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
import kotlin.io.path.writeText
 | 
					import kotlin.io.path.writeText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,7 +32,11 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun process(resolver: Resolver): List<KSAnnotated> {
 | 
					  override fun process(resolver: Resolver): List<KSAnnotated> {
 | 
				
			||||||
    resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
 | 
					    resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
 | 
				
			||||||
    val filePath = Path(environment.options["generated_directory"]!!, environment.options["vimscript_functions_file"]!!)
 | 
					
 | 
				
			||||||
 | 
					    val generatedDirPath = Path(environment.options["generated_directory"]!!)
 | 
				
			||||||
 | 
					    Files.createDirectories(generatedDirPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
 | 
				
			||||||
    val fileContent = json.encodeToString(nameToClass)
 | 
					    val fileContent = json.encodeToString(nameToClass)
 | 
				
			||||||
    filePath.writeText(fileContent)
 | 
					    filePath.writeText(fileContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.intellij.vim.providers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.SymbolProcessor
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
 | 
				
			||||||
 | 
					import com.google.devtools.ksp.processing.SymbolProcessorProvider
 | 
				
			||||||
 | 
					import com.intellij.vim.processors.CommandOrMotionProcessor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CommandOrMotionProcessorProvider : SymbolProcessorProvider {
 | 
				
			||||||
 | 
					  override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
 | 
				
			||||||
 | 
					    return CommandOrMotionProcessor(environment)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,2 +1,3 @@
 | 
				
			|||||||
com.intellij.vim.providers.VimscriptFunctionProcessorProvider
 | 
					com.intellij.vim.providers.CommandOrMotionProcessorProvider
 | 
				
			||||||
com.intellij.vim.providers.ExCommandProcessorProvider
 | 
					com.intellij.vim.providers.ExCommandProcessorProvider
 | 
				
			||||||
 | 
					com.intellij.vim.providers.VimscriptFunctionProcessorProvider
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,11 +52,11 @@ buildscript {
 | 
				
			|||||||
        classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.7.0.202309050840-r")
 | 
					        classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.7.0.202309050840-r")
 | 
				
			||||||
        classpath("org.kohsuke:github-api:1.305")
 | 
					        classpath("org.kohsuke:github-api:1.305")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        classpath("io.ktor:ktor-client-core:2.3.4")
 | 
					        classpath("io.ktor:ktor-client-core:2.3.6")
 | 
				
			||||||
        classpath("io.ktor:ktor-client-cio:2.3.4")
 | 
					        classpath("io.ktor:ktor-client-cio:2.3.5")
 | 
				
			||||||
        classpath("io.ktor:ktor-client-auth:2.3.4")
 | 
					        classpath("io.ktor:ktor-client-auth:2.3.6")
 | 
				
			||||||
        classpath("io.ktor:ktor-client-content-negotiation:2.3.4")
 | 
					        classpath("io.ktor:ktor-client-content-negotiation:2.3.6")
 | 
				
			||||||
        classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.4")
 | 
					        classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.6")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This comes from the changelog plugin
 | 
					        // This comes from the changelog plugin
 | 
				
			||||||
//        classpath("org.jetbrains:markdown:0.3.1")
 | 
					//        classpath("org.jetbrains:markdown:0.3.1")
 | 
				
			||||||
@@ -69,7 +69,7 @@ plugins {
 | 
				
			|||||||
    kotlin("jvm") version "1.8.21"
 | 
					    kotlin("jvm") version "1.8.21"
 | 
				
			||||||
    application
 | 
					    application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    id("org.jetbrains.intellij") version "1.15.0"
 | 
					    id("org.jetbrains.intellij") version "1.16.0"
 | 
				
			||||||
    id("org.jetbrains.changelog") version "2.2.0"
 | 
					    id("org.jetbrains.changelog") version "2.2.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
 | 
					    // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
 | 
				
			||||||
@@ -82,9 +82,10 @@ plugins {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ksp {
 | 
					ksp {
 | 
				
			||||||
  arg("generated_directory", "$projectDir/src/main/resources")
 | 
					  arg("generated_directory", "$projectDir/src/main/resources/ksp-generated")
 | 
				
			||||||
  arg("vimscript_functions_file", "intellij_vimscript_functions.json")
 | 
					  arg("vimscript_functions_file", "intellij_vimscript_functions.json")
 | 
				
			||||||
  arg("ex_commands_file", "intellij_ex_commands.json")
 | 
					  arg("ex_commands_file", "intellij_ex_commands.json")
 | 
				
			||||||
 | 
					  arg("commands_file", "intellij_commands.json")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
afterEvaluate {
 | 
					afterEvaluate {
 | 
				
			||||||
@@ -136,13 +137,13 @@ dependencies {
 | 
				
			|||||||
    api(project(":vim-engine"))
 | 
					    api(project(":vim-engine"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ksp(project(":annotation-processors"))
 | 
					    ksp(project(":annotation-processors"))
 | 
				
			||||||
    compileOnly(project(":annotation-processors"))
 | 
					    implementation(project(":annotation-processors"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    testApi("com.squareup.okhttp3:okhttp:4.11.0")
 | 
					    testApi("com.squareup.okhttp3:okhttp:4.12.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
 | 
					    testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
 | 
				
			||||||
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
 | 
					    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
 | 
				
			||||||
    testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.0")
 | 
					    testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
configurations {
 | 
					configurations {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
Welcome to the IdeaVim wiki!
 | 
					Welcome to the IdeaVim wiki!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- List of IdeaVim plugins: [[plugins|IdeaVim Plugins]]
 | 
					- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins.md)
 | 
				
			||||||
- Examples of `ideajoin` option (also known as "smart join"): [["ideajoin" examples|ideajoin-examples]]
 | 
					- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples.md)
 | 
				
			||||||
- List of "set" commands: [["set" commands|set-commands]]
 | 
					- List of "set" commands: ["set" commands](set-commands.md)
 | 
				
			||||||
- Docs about "select" mode in vim: [[select mode|Select-mode]]
 | 
					- Docs about "select" mode in vim: [select mode](Select-mode.md)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,7 +77,7 @@ Original plugin: [NERDTree](https://github.com/preservim/nerdtree).
 | 
				
			|||||||
   
 | 
					   
 | 
				
			||||||
### Instructions
 | 
					### Instructions
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
[[See here|NERDTree-support]].
 | 
					[See here](NERDTree-support.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</details>
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# suppress inspection "UnusedProperty" for whole file
 | 
					# suppress inspection "UnusedProperty" for whole file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ideaVersion=2023.2.1
 | 
					ideaVersion=2023.2
 | 
				
			||||||
downloadIdeaSources=true
 | 
					downloadIdeaSources=true
 | 
				
			||||||
instrumentPluginCode=true
 | 
					instrumentPluginCode=true
 | 
				
			||||||
version=chylex-16
 | 
					version=chylex-21
 | 
				
			||||||
javaVersion=17
 | 
					javaVersion=17
 | 
				
			||||||
remoteRobotVersion=0.11.17
 | 
					remoteRobotVersion=0.11.17
 | 
				
			||||||
antlrVersion=4.10.1
 | 
					antlrVersion=4.10.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,13 +20,13 @@ repositories {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.10")
 | 
					  compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation("io.ktor:ktor-client-core:2.3.4")
 | 
					  implementation("io.ktor:ktor-client-core:2.3.6")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-cio:2.3.4")
 | 
					  implementation("io.ktor:ktor-client-cio:2.3.5")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-content-negotiation:2.3.4")
 | 
					  implementation("io.ktor:ktor-client-content-negotiation:2.3.6")
 | 
				
			||||||
  implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.4")
 | 
					  implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.6")
 | 
				
			||||||
  implementation("io.ktor:ktor-client-auth:2.3.4")
 | 
					  implementation("io.ktor:ktor-client-auth:2.3.6")
 | 
				
			||||||
  implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
					  implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This is needed for jgit to connect to ssh
 | 
					  // This is needed for jgit to connect to ssh
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@
 | 
				
			|||||||
package scripts.release
 | 
					package scripts.release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.vdurmont.semver4j.Semver
 | 
					import com.vdurmont.semver4j.Semver
 | 
				
			||||||
 | 
					import org.eclipse.jgit.api.CreateBranchCommand
 | 
				
			||||||
import org.eclipse.jgit.api.Git
 | 
					import org.eclipse.jgit.api.Git
 | 
				
			||||||
import org.eclipse.jgit.lib.ObjectId
 | 
					import org.eclipse.jgit.lib.ObjectId
 | 
				
			||||||
import org.eclipse.jgit.lib.Repository
 | 
					import org.eclipse.jgit.lib.Repository
 | 
				
			||||||
@@ -84,9 +85,14 @@ internal fun getVersion(projectDir: String, onlyStable: Boolean): Pair<Semver, O
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal fun Git.checkoutBranch(name: String) {
 | 
					internal fun Git.checkoutBranch(name: String) {
 | 
				
			||||||
 | 
					  println("Checking out $name")
 | 
				
			||||||
  val shouldCreateBranch = this.branchList().call().any { it.name == "refs/heads/$name" }.not()
 | 
					  val shouldCreateBranch = this.branchList().call().any { it.name == "refs/heads/$name" }.not()
 | 
				
			||||||
  checkout()
 | 
					  val checkoutCommand = checkout()
 | 
				
			||||||
    .setCreateBranch(shouldCreateBranch)
 | 
					    .setCreateBranch(shouldCreateBranch)
 | 
				
			||||||
    .setName(name)
 | 
					    .setName(name)
 | 
				
			||||||
    .call()
 | 
					  if (shouldCreateBranch) {
 | 
				
			||||||
 | 
					    // Without starting point the branch will be created on HEAD.
 | 
				
			||||||
 | 
					    checkoutCommand.setStartPoint("origin/$name").setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  checkoutCommand.call()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,79 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2003-2023 The IdeaVim authors
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Use of this source code is governed by an MIT-style
 | 
					 | 
				
			||||||
 * license that can be found in the LICENSE.txt file or at
 | 
					 | 
				
			||||||
 * https://opensource.org/licenses/MIT.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
package com.maddyhome.idea.vim;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager;
 | 
					 | 
				
			||||||
import com.intellij.openapi.extensions.ExtensionPointName;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.group.KeyGroup;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.ActionBeanClass;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.key.MappingOwner;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimActionsInitiator;
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.swing.*;
 | 
					 | 
				
			||||||
import java.awt.event.KeyEvent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class RegisterActions {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public static final ExtensionPointName<ActionBeanClass> VIM_ACTIONS_EP =
 | 
					 | 
				
			||||||
    ExtensionPointName.create("IdeaVIM.vimAction");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Register all the key/action mappings for the plugin.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  public static void registerActions() {
 | 
					 | 
				
			||||||
    registerVimCommandActions();
 | 
					 | 
				
			||||||
    registerEmptyShortcuts();
 | 
					 | 
				
			||||||
    registerEpListener();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static void registerEpListener() {
 | 
					 | 
				
			||||||
    // IdeaVim doesn't support contribution to VIM_ACTIONS_EP extension point, so technically we can skip this update,
 | 
					 | 
				
			||||||
    //   but let's support dynamic plugins in a more classic way and reload actions on every EP change.
 | 
					 | 
				
			||||||
    VIM_ACTIONS_EP.addChangeListener(() -> {
 | 
					 | 
				
			||||||
      unregisterActions();
 | 
					 | 
				
			||||||
      registerActions();
 | 
					 | 
				
			||||||
    }, VimPlugin.getInstance());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public static @Nullable EditorActionHandlerBase findAction(@NotNull String id) {
 | 
					 | 
				
			||||||
    return VIM_ACTIONS_EP.getExtensionList(ApplicationManager.getApplication()).stream()
 | 
					 | 
				
			||||||
        .filter(vimActionBean -> vimActionBean.getActionId().equals(id)).findFirst().map(ActionBeanClass::getInstance)
 | 
					 | 
				
			||||||
        .orElse(null);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public static @NotNull EditorActionHandlerBase findActionOrDie(@NotNull String id) {
 | 
					 | 
				
			||||||
    EditorActionHandlerBase action = findAction(id);
 | 
					 | 
				
			||||||
    if (action == null) throw new RuntimeException("Action " + id + " is not registered");
 | 
					 | 
				
			||||||
    return action;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public static void unregisterActions() {
 | 
					 | 
				
			||||||
    KeyGroup keyGroup = VimPlugin.getKeyIfCreated();
 | 
					 | 
				
			||||||
    if (keyGroup != null) {
 | 
					 | 
				
			||||||
      keyGroup.unregisterCommandActions();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static void registerVimCommandActions() {
 | 
					 | 
				
			||||||
    KeyGroup parser = VimPlugin.getKey();
 | 
					 | 
				
			||||||
    VIM_ACTIONS_EP.getExtensionList(ApplicationManager.getApplication()).stream().map(IjVimActionsInitiator::new)
 | 
					 | 
				
			||||||
        .forEach(parser::registerCommandAction);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static void registerEmptyShortcuts() {
 | 
					 | 
				
			||||||
    final KeyGroup parser = VimPlugin.getKey();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The {char1} <BS> {char2} shortcut is handled directly by KeyHandler#handleKey, so doesn't have an action. But we
 | 
					 | 
				
			||||||
    // still need to register the shortcut, to make sure the editor doesn't swallow it.
 | 
					 | 
				
			||||||
    parser
 | 
					 | 
				
			||||||
      .registerShortcutWithoutAction(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), MappingOwner.IdeaVim.System.INSTANCE);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										100
									
								
								src/main/java/com/maddyhome/idea/vim/RegisterActions.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/main/java/com/maddyhome/idea/vim/RegisterActions.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.extensions.ExtensionPointName
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.action.EngineCommandProvider
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.action.IntellijCommandProvider
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.ActionBeanClass
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.MappingOwner
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.IjVimActionsInitiator
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public object RegisterActions {
 | 
				
			||||||
 | 
					  @Deprecated("Please use @CommandOrMotion annotation instead")
 | 
				
			||||||
 | 
					  internal val VIM_ACTIONS_EP: ExtensionPointName<ActionBeanClass> = ExtensionPointName.create("IdeaVIM.vimAction")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Register all the key/action mappings for the plugin.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @JvmStatic
 | 
				
			||||||
 | 
					  public fun registerActions() {
 | 
				
			||||||
 | 
					    registerVimCommandActions()
 | 
				
			||||||
 | 
					    if (!injector.globalIjOptions().commandOrMotionAnnotation) {
 | 
				
			||||||
 | 
					      registerEmptyShortcuts()
 | 
				
			||||||
 | 
					      registerEpListener()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Deprecated("Moving to annotations approach instead of xml")
 | 
				
			||||||
 | 
					  private fun registerEpListener() {
 | 
				
			||||||
 | 
					    // IdeaVim doesn't support contribution to VIM_ACTIONS_EP extension point, so technically we can skip this update,
 | 
				
			||||||
 | 
					    //   but let's support dynamic plugins in a more classic way and reload actions on every EP change.
 | 
				
			||||||
 | 
					    VIM_ACTIONS_EP.addChangeListener({
 | 
				
			||||||
 | 
					      unregisterActions()
 | 
				
			||||||
 | 
					      registerActions()
 | 
				
			||||||
 | 
					    }, VimPlugin.getInstance())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public fun findAction(id: String): EditorActionHandlerBase? {
 | 
				
			||||||
 | 
					    if (injector.globalIjOptions().commandOrMotionAnnotation) {
 | 
				
			||||||
 | 
					      val commandBean = EngineCommandProvider.getCommands().firstOrNull { it.actionId == id }
 | 
				
			||||||
 | 
					        ?: IntellijCommandProvider.getCommands().firstOrNull { it.actionId == id } ?: return null
 | 
				
			||||||
 | 
					      return commandBean.instance
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return VIM_ACTIONS_EP.getExtensionList(ApplicationManager.getApplication()).stream()
 | 
				
			||||||
 | 
					        .filter { vimActionBean: ActionBeanClass -> vimActionBean.actionId == id }
 | 
				
			||||||
 | 
					        .findFirst().map { obj: ActionBeanClass -> obj.instance }
 | 
				
			||||||
 | 
					        .orElse(null)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public fun findActionOrDie(id: String): EditorActionHandlerBase {
 | 
				
			||||||
 | 
					    return findAction(id) ?: throw RuntimeException("Action $id is not registered")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @JvmStatic
 | 
				
			||||||
 | 
					  public fun unregisterActions() {
 | 
				
			||||||
 | 
					    val keyGroup = VimPlugin.getKeyIfCreated()
 | 
				
			||||||
 | 
					    keyGroup?.unregisterCommandActions()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun registerVimCommandActions() {
 | 
				
			||||||
 | 
					    val parser = VimPlugin.getKey()
 | 
				
			||||||
 | 
					    if (injector.globalIjOptions().commandOrMotionAnnotation) {
 | 
				
			||||||
 | 
					      EngineCommandProvider.getCommands().forEach { parser.registerCommandAction(it) }
 | 
				
			||||||
 | 
					      IntellijCommandProvider.getCommands().forEach { parser.registerCommandAction(it) }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      VIM_ACTIONS_EP.getExtensionList(ApplicationManager.getApplication()).stream().map { bean: ActionBeanClass? ->
 | 
				
			||||||
 | 
					        IjVimActionsInitiator(
 | 
				
			||||||
 | 
					          bean!!
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					        .forEach { actionHolder: IjVimActionsInitiator? ->
 | 
				
			||||||
 | 
					          parser.registerCommandAction(
 | 
				
			||||||
 | 
					            actionHolder!!
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // todo do we really need this?
 | 
				
			||||||
 | 
					  private fun registerEmptyShortcuts() {
 | 
				
			||||||
 | 
					    val parser = VimPlugin.getKey()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The {char1} <BS> {char2} shortcut is handled directly by KeyHandler#handleKey, so doesn't have an action. But we
 | 
				
			||||||
 | 
					    // still need to register the shortcut, to make sure the editor doesn't swallow it.
 | 
				
			||||||
 | 
					    parser
 | 
				
			||||||
 | 
					      .registerShortcutWithoutAction(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), MappingOwner.IdeaVim.System)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -306,11 +306,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
 | 
				
			|||||||
   * This is required to ensure that all options are correctly initialised and registered. Must be before any commands
 | 
					   * This is required to ensure that all options are correctly initialised and registered. Must be before any commands
 | 
				
			||||||
   * are executed.</li>
 | 
					   * are executed.</li>
 | 
				
			||||||
   * <li>~/.ideavimrc execution<br>
 | 
					   * <li>~/.ideavimrc execution<br>
 | 
				
			||||||
   * <ul>
 | 
					 | 
				
			||||||
   * <li>4.1 executes commands from the .ideavimrc file and 4.2 initializes extensions.</li>
 | 
					 | 
				
			||||||
   * <li>4.1 MUST BE BEFORE 4.2. This is a flow of vim/IdeaVim initialization, firstly .ideavimrc is executed and then
 | 
					 | 
				
			||||||
   * the extensions are initialized.</li>
 | 
					 | 
				
			||||||
   * </ul>
 | 
					 | 
				
			||||||
   * </li>
 | 
					   * </li>
 | 
				
			||||||
   * <li>Components initialization<br>
 | 
					   * <li>Components initialization<br>
 | 
				
			||||||
   * This should happen after ideavimrc execution because VimListenerManager accesses `number` option
 | 
					   * This should happen after ideavimrc execution because VimListenerManager accesses `number` option
 | 
				
			||||||
@@ -339,13 +334,9 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
 | 
				
			|||||||
    VimInjectorKt.getInjector().getOptionGroup().initialiseOptions();
 | 
					    VimInjectorKt.getInjector().getOptionGroup().initialiseOptions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 4) ~/.ideavimrc execution
 | 
					    // 4) ~/.ideavimrc execution
 | 
				
			||||||
    // 4.1) Execute ~/.ideavimrc
 | 
					 | 
				
			||||||
    // Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
 | 
					    // Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
 | 
				
			||||||
    registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
 | 
					    registerIdeavimrc(VimInjectorKt.getInjector().getFallbackWindow());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 4.2) Initialize extensions. Always after 4.1
 | 
					 | 
				
			||||||
    VimExtensionRegistrar.enableDelayedExtensions();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Turing on should be performed after all commands registration
 | 
					    // Turing on should be performed after all commands registration
 | 
				
			||||||
    getSearch().turnOn();
 | 
					    getSearch().turnOn();
 | 
				
			||||||
    VimListenerManager.INSTANCE.turnOn();
 | 
					    VimListenerManager.INSTANCE.turnOn();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action
 | 
					package com.maddyhome.idea.vim.action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
@@ -14,6 +16,7 @@ import com.maddyhome.idea.vim.command.Command
 | 
				
			|||||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
					import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = [":"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
 | 
				
			||||||
internal class ExEntryAction : VimActionHandler.SingleExecution() {
 | 
					internal class ExEntryAction : VimActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.OTHER_READONLY
 | 
					  override val type: Command.Type = Command.Type.OTHER_READONLY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public object IntellijCommandProvider : CommandProvider {
 | 
				
			||||||
 | 
					  override val commandListFileName: String = "intellij_commands.json"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.codeInsight.hint.HintManagerImpl
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.ActionManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.AnAction
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.AnActionEvent
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.CommonDataKeys
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.PerformWithDocumentsCommitted
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.PopupAction
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.impl.ActionConfigurationCustomizer
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.EditorMouseHoverPopupManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.event.EditorMouseEvent
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.event.EditorMouseEventArea
 | 
				
			||||||
 | 
					import com.intellij.openapi.project.DumbAware
 | 
				
			||||||
 | 
					import java.awt.event.MouseEvent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// [VERSION UPDATE] 233+ Remove class
 | 
				
			||||||
 | 
					// The ShowHoverInfo action is built into the platform (using a nicer EditorMouseHoverPopupManager API)
 | 
				
			||||||
 | 
					public class VimActionConfigurationCustomizer : ActionConfigurationCustomizer {
 | 
				
			||||||
 | 
					  public override fun customize(actionManager: ActionManager) {
 | 
				
			||||||
 | 
					    // If the ShowHoverInfo action doesn't exist in the platform, add our own implementation
 | 
				
			||||||
 | 
					    if (actionManager.getAction("ShowHoverInfo") == null) {
 | 
				
			||||||
 | 
					      actionManager.registerAction("ShowHoverInfo", VimShowHoverInfoAction())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private class VimShowHoverInfoAction : AnAction(), HintManagerImpl.ActionToIgnore, PopupAction, DumbAware,
 | 
				
			||||||
 | 
					    PerformWithDocumentsCommitted {
 | 
				
			||||||
 | 
					    override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun update(e: AnActionEvent) {
 | 
				
			||||||
 | 
					      val dataContext = e.dataContext
 | 
				
			||||||
 | 
					      val editor = CommonDataKeys.EDITOR.getData(dataContext)
 | 
				
			||||||
 | 
					      if (editor == null) {
 | 
				
			||||||
 | 
					        e.presentation.isEnabledAndVisible = false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
 | 
					      val editor = CommonDataKeys.EDITOR.getData(e.dataContext) ?: return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val editorMouseEvent = createFakeEditorMouseEvent(editor)
 | 
				
			||||||
 | 
					      EditorMouseHoverPopupManager.getInstance().showInfoTooltip(editorMouseEvent)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun createFakeEditorMouseEvent(editor: Editor): EditorMouseEvent {
 | 
				
			||||||
 | 
					      val xy = editor.offsetToXY(editor.caretModel.offset)
 | 
				
			||||||
 | 
					      val mouseEvent =
 | 
				
			||||||
 | 
					        MouseEvent(editor.component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, xy.x, xy.y, 0, false)
 | 
				
			||||||
 | 
					      val editorMouseEvent = EditorMouseEvent(
 | 
				
			||||||
 | 
					        editor,
 | 
				
			||||||
 | 
					        mouseEvent,
 | 
				
			||||||
 | 
					        EditorMouseEventArea.EDITING_AREA,
 | 
				
			||||||
 | 
					        editor.caretModel.offset,
 | 
				
			||||||
 | 
					        editor.caretModel.logicalPosition,
 | 
				
			||||||
 | 
					        editor.caretModel.visualPosition,
 | 
				
			||||||
 | 
					        true,
 | 
				
			||||||
 | 
					        null,
 | 
				
			||||||
 | 
					        null,
 | 
				
			||||||
 | 
					        null
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      return editorMouseEvent
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,10 +14,14 @@ 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.AnActionWrapper
 | 
					import com.intellij.openapi.actionSystem.AnActionWrapper
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.IdeActions
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.KeyboardShortcut
 | 
				
			||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
 | 
					import com.intellij.openapi.actionSystem.PlatformDataKeys
 | 
				
			||||||
import com.intellij.openapi.application.invokeLater
 | 
					import com.intellij.openapi.application.invokeLater
 | 
				
			||||||
import com.intellij.openapi.diagnostic.logger
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.keymap.KeymapManager
 | 
				
			||||||
import com.intellij.openapi.progress.ProcessCanceledException
 | 
					import com.intellij.openapi.progress.ProcessCanceledException
 | 
				
			||||||
import com.intellij.openapi.project.DumbAware
 | 
					import com.intellij.openapi.project.DumbAware
 | 
				
			||||||
import com.intellij.openapi.util.Key
 | 
					import com.intellij.openapi.util.Key
 | 
				
			||||||
@@ -28,7 +32,6 @@ import com.maddyhome.idea.vim.api.globalOptions
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.group.IjOptionConstants
 | 
					import com.maddyhome.idea.vim.group.IjOptionConstants
 | 
				
			||||||
import com.maddyhome.idea.vim.group.IjOptions
 | 
					import com.maddyhome.idea.vim.group.IjOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.enableOctopus
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.isOctopusEnabled
 | 
					import com.maddyhome.idea.vim.handler.isOctopusEnabled
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.HandlerInjector
 | 
					import com.maddyhome.idea.vim.helper.HandlerInjector
 | 
				
			||||||
@@ -95,25 +98,25 @@ internal class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatib
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  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
 | 
				
			||||||
    val actionEnableStatus = isEnabled(e)
 | 
					    val keyStroke = getKeyStroke(e)
 | 
				
			||||||
 | 
					    val actionEnableStatus = isEnabled(e, keyStroke)
 | 
				
			||||||
    e.presentation.isEnabled = actionEnableStatus.isEnabled
 | 
					    e.presentation.isEnabled = actionEnableStatus.isEnabled
 | 
				
			||||||
    actionEnableStatus.printLog()
 | 
					    actionEnableStatus.printLog(keyStroke)
 | 
				
			||||||
    if (start != null) {
 | 
					    if (start != null) {
 | 
				
			||||||
      val keyStroke = getKeyStroke(e)
 | 
					 | 
				
			||||||
      val duration = System.currentTimeMillis() - start
 | 
					      val duration = System.currentTimeMillis() - start
 | 
				
			||||||
      LOG.info("VimShortcut update '$keyStroke': $duration ms")
 | 
					      LOG.info("VimShortcut update '$keyStroke': $duration ms")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun isEnabled(e: AnActionEvent): ActionEnableStatus {
 | 
					  private fun isEnabled(e: AnActionEvent, keyStroke: KeyStroke?): ActionEnableStatus {
 | 
				
			||||||
    if (!VimPlugin.isEnabled()) return ActionEnableStatus.no("IdeaVim is disabled", LogLevel.DEBUG)
 | 
					    if (!VimPlugin.isEnabled()) return ActionEnableStatus.no("IdeaVim is disabled", LogLevel.DEBUG)
 | 
				
			||||||
    val editor = getEditor(e)
 | 
					    val editor = getEditor(e)
 | 
				
			||||||
    val keyStroke = getKeyStroke(e)
 | 
					 | 
				
			||||||
    if (editor != null && keyStroke != null) {
 | 
					    if (editor != null && keyStroke != null) {
 | 
				
			||||||
      if (enableOctopus) {
 | 
					      if (isOctopusEnabled(keyStroke, editor)) {
 | 
				
			||||||
        if (isOctopusEnabled(keyStroke, editor)) {
 | 
					        return ActionEnableStatus.no(
 | 
				
			||||||
          return ActionEnableStatus.no("Octopus handler is enabled", LogLevel.DEBUG)
 | 
					          "Processing VimShortcutKeyAction for the key that is used in the octopus handler",
 | 
				
			||||||
        }
 | 
					          LogLevel.ERROR
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (editor.isIdeaVimDisabledHere) {
 | 
					      if (editor.isIdeaVimDisabledHere) {
 | 
				
			||||||
        return ActionEnableStatus.no("IdeaVim is disabled in this place", LogLevel.INFO)
 | 
					        return ActionEnableStatus.no("IdeaVim is disabled in this place", LogLevel.INFO)
 | 
				
			||||||
@@ -160,8 +163,12 @@ internal class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatib
 | 
				
			|||||||
        return ActionEnableStatus.no("App code template is active", LogLevel.INFO)
 | 
					        return ActionEnableStatus.no("App code template is active", LogLevel.INFO)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_HOME || keyCode == KeyEvent.VK_END) {
 | 
					      val nextTemplateVariableShortcuts = KeymapManager.getInstance().activeKeymap.getShortcuts(IdeActions.ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE)
 | 
				
			||||||
        return ActionEnableStatus.no("Special keys", LogLevel.INFO)
 | 
					      if (nextTemplateVariableShortcuts.any { it is KeyboardShortcut && it.firstKeyStroke == keyStroke }) {
 | 
				
			||||||
 | 
					        val handler = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE)
 | 
				
			||||||
 | 
					        if (handler.isEnabled(editor, null, e.dataContext)) {
 | 
				
			||||||
 | 
					          return ActionEnableStatus.no("Next template variable or finish in-place refactoring", LogLevel.INFO)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if (editor.inInsertMode) {
 | 
					      if (editor.inInsertMode) {
 | 
				
			||||||
@@ -365,10 +372,12 @@ private class ActionEnableStatus(
 | 
				
			|||||||
  val message: String,
 | 
					  val message: String,
 | 
				
			||||||
  val logLevel: LogLevel,
 | 
					  val logLevel: LogLevel,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  fun printLog() {
 | 
					  fun printLog(keyStroke: KeyStroke?) {
 | 
				
			||||||
 | 
					    val message = "IdeaVim keys are enabled = $isEnabled for key '$keyStroke': $message"
 | 
				
			||||||
    when (logLevel) {
 | 
					    when (logLevel) {
 | 
				
			||||||
      LogLevel.INFO -> LOG.info("IdeaVim keys are enabled = $isEnabled: $message")
 | 
					      LogLevel.INFO -> LOG.info(message)
 | 
				
			||||||
      LogLevel.DEBUG -> LOG.debug("IdeaVim keys are enabled = $isEnabled: $message")
 | 
					      LogLevel.DEBUG -> LOG.debug(message)
 | 
				
			||||||
 | 
					      LogLevel.ERROR -> LOG.error(message)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -381,5 +390,5 @@ private class ActionEnableStatus(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private enum class LogLevel {
 | 
					private enum class LogLevel {
 | 
				
			||||||
  DEBUG, INFO,
 | 
					  DEBUG, INFO, ERROR,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change
 | 
					package com.maddyhome.idea.vim.action.change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
@@ -47,6 +49,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
 | 
				
			|||||||
  return result
 | 
					  return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["g@"], modes = [Mode.NORMAL])
 | 
				
			||||||
internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
					internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
 | 
					  override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -97,6 +100,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["g@"], modes = [Mode.VISUAL])
 | 
				
			||||||
internal class VisualOperatorAction : VisualOperatorActionHandler.ForEachCaret() {
 | 
					internal class VisualOperatorAction : VisualOperatorActionHandler.ForEachCaret() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
 | 
					  override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change
 | 
					package com.maddyhome.idea.vim.action.change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
import com.intellij.openapi.command.CommandProcessor
 | 
					import com.intellij.openapi.command.CommandProcessor
 | 
				
			||||||
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
 | 
				
			||||||
@@ -18,6 +20,7 @@ import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.vimStateMachine
 | 
					import com.maddyhome.idea.vim.helper.vimStateMachine
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["."], modes = [Mode.NORMAL])
 | 
				
			||||||
internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
					internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.OTHER_WRITABLE
 | 
					  override val type: Command.Type = Command.Type.OTHER_WRITABLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change.delete
 | 
					package com.maddyhome.idea.vim.action.change.delete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
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
 | 
				
			||||||
@@ -17,6 +19,7 @@ import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			|||||||
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
 | 
					import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ijOptions
 | 
					import com.maddyhome.idea.vim.newapi.ijOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["gJ"], modes = [Mode.NORMAL])
 | 
				
			||||||
public class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecution() {
 | 
					public class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
  override fun runAsMulticaret(
 | 
					  override fun runAsMulticaret(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change.delete
 | 
					package com.maddyhome.idea.vim.action.change.delete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
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
 | 
				
			||||||
@@ -16,6 +18,7 @@ import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			|||||||
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
 | 
					import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ijOptions
 | 
					import com.maddyhome.idea.vim.newapi.ijOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["J"], modes = [Mode.NORMAL])
 | 
				
			||||||
public class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution() {
 | 
					public class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change.delete
 | 
					package com.maddyhome.idea.vim.action.change.delete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
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
 | 
				
			||||||
@@ -23,6 +25,7 @@ import java.util.*
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author vlan
 | 
					 * @author vlan
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["gJ"], modes = [Mode.VISUAL])
 | 
				
			||||||
public class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution() {
 | 
					public class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.change.delete
 | 
					package com.maddyhome.idea.vim.action.change.delete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
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
 | 
				
			||||||
@@ -23,6 +25,7 @@ import java.util.*
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author vlan
 | 
					 * @author vlan
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["J"], modes = [Mode.VISUAL])
 | 
				
			||||||
public class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExecution() {
 | 
					public class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.action.editor
 | 
					package com.maddyhome.idea.vim.action.editor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
import com.intellij.openapi.actionSystem.IdeActions
 | 
					import com.intellij.openapi.actionSystem.IdeActions
 | 
				
			||||||
import com.maddyhome.idea.vim.action.ComplicatedKeysAction
 | 
					import com.maddyhome.idea.vim.action.ComplicatedKeysAction
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
@@ -23,6 +25,7 @@ import java.awt.event.KeyEvent
 | 
				
			|||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<C-H>", "<BS>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE), ComplicatedKeysAction {
 | 
					internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
				
			||||||
    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK)),
 | 
					    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK)),
 | 
				
			||||||
@@ -31,6 +34,7 @@ internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BA
 | 
				
			|||||||
  override val type: Command.Type = Command.Type.DELETE
 | 
					  override val type: Command.Type = Command.Type.DELETE
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE), ComplicatedKeysAction {
 | 
					internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
				
			||||||
    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)),
 | 
					    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)),
 | 
				
			||||||
@@ -39,6 +43,7 @@ internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELET
 | 
				
			|||||||
  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<Down>", "<kDown>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN), ComplicatedKeysAction {
 | 
					internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
				
			||||||
    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
 | 
					    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
 | 
				
			||||||
@@ -48,6 +53,7 @@ internal class VimEditorDown : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CA
 | 
				
			|||||||
  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_CLEAR_STROKES)
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_CLEAR_STROKES)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<Tab>", "<C-I>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorTab : IdeActionHandler(IdeActions.ACTION_EDITOR_TAB), ComplicatedKeysAction {
 | 
					internal class VimEditorTab : IdeActionHandler(IdeActions.ACTION_EDITOR_TAB), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
				
			||||||
    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_DOWN_MASK)),
 | 
					    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_DOWN_MASK)),
 | 
				
			||||||
@@ -57,6 +63,7 @@ internal class VimEditorTab : IdeActionHandler(IdeActions.ACTION_EDITOR_TAB), Co
 | 
				
			|||||||
  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<Up>", "<kUp>"], modes = [Mode.INSERT])
 | 
				
			||||||
internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_UP), ComplicatedKeysAction {
 | 
					internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_UP), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
 | 
				
			||||||
    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
 | 
					    listOf(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
 | 
				
			||||||
@@ -66,6 +73,7 @@ internal class VimEditorUp : IdeActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARE
 | 
				
			|||||||
  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_CLEAR_STROKES)
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_CLEAR_STROKES)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["K"], modes = [Mode.NORMAL])
 | 
				
			||||||
internal class VimQuickJavaDoc : VimActionHandler.SingleExecution() {
 | 
					internal class VimQuickJavaDoc : VimActionHandler.SingleExecution() {
 | 
				
			||||||
  override val type: Command.Type = Command.Type.OTHER_READONLY
 | 
					  override val type: Command.Type = Command.Type.OTHER_READONLY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package com.maddyhome.idea.vim.action.ex
 | 
					package com.maddyhome.idea.vim.action.ex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.action.ComplicatedKeysAction
 | 
					import com.maddyhome.idea.vim.action.ComplicatedKeysAction
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
@@ -23,6 +25,7 @@ import javax.swing.KeyStroke
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * The mapping for this action means that the ex command is executed as a write action
 | 
					 * The mapping for this action means that the ex command is executed as a write action
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["<CR>", "<C-M>", "<C-J>"], modes = [Mode.CMD_LINE])
 | 
				
			||||||
public class ProcessExEntryAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction {
 | 
					public class ProcessExEntryAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction {
 | 
				
			||||||
  override val keyStrokesSet: Set<List<KeyStroke>> =
 | 
					  override val keyStrokesSet: Set<List<KeyStroke>> =
 | 
				
			||||||
    parseKeysSet("<CR>", "<C-M>", 0x0a.toChar().toString(), 0x0d.toChar().toString())
 | 
					    parseKeysSet("<CR>", "<C-M>", 0x0a.toChar().toString(), 0x0d.toChar().toString())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,6 +82,31 @@ internal object VimExtensionRegistrar : VimExtensionRegistrator {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * During vim initialization process, it firstly loads the .vimrc file, then executes scripts from the plugins folder.
 | 
				
			||||||
 | 
					   * This practically means that the .vimrc file is initialized first, then the plugins are loaded.
 | 
				
			||||||
 | 
					   * See `:h initialization`
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * In IdeaVim we don't have a separate plugins folder to load it after .ideavimrc load. However, we can collect
 | 
				
			||||||
 | 
					   *   the list of plugins mentioned in the .ideavimrc and load them after .ideavimrc execution is finished.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * Why this matters? Because this affects the order of commands are executed. For example:
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * plug 'tommcdo/vim-exchange'
 | 
				
			||||||
 | 
					   * let g:exchange_no_mappings=1
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * Here the user will expect that the exchange plugin won't have default mappings. However, if we load vim-exchange
 | 
				
			||||||
 | 
					   *    immediately, this variable won't be initialized at the moment of plugin initialization.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * There is also a tricky case for mappings override:
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * plug 'tommcdo/vim-exchange'
 | 
				
			||||||
 | 
					   * map X <Plug>(ExchangeLine)
 | 
				
			||||||
 | 
					   * ```
 | 
				
			||||||
 | 
					   * For this case, a plugin with a good implementation detects that there is already a defined mapping for
 | 
				
			||||||
 | 
					   *   `<Plug>(ExchangeLine)` and doesn't register the default cxx mapping. However, such detection requires the mapping
 | 
				
			||||||
 | 
					   *   to be defined before the plugin initialization.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  fun enableDelayedExtensions() {
 | 
					  fun enableDelayedExtensions() {
 | 
				
			||||||
    delayedExtensionEnabling.forEach {
 | 
					    delayedExtensionEnabling.forEach {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ 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.project.Project
 | 
				
			||||||
import com.intellij.openapi.util.Ref
 | 
					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
 | 
				
			||||||
@@ -74,19 +75,26 @@ internal class CommentaryExtension : VimExtension {
 | 
				
			|||||||
          listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE)
 | 
					          listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val res = Ref.create<Boolean>(true)
 | 
					        val project = editor.ij.project!!
 | 
				
			||||||
        AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[0], {
 | 
					        val callback = { afterCommenting(mode, editor, resetCaret, range) }
 | 
				
			||||||
          res.set(injector.actionExecutor.executeAction(actions[0], context))
 | 
					        actions.any { executeActionWithCallbackOnSuccess(it, project, context, callback) }
 | 
				
			||||||
        }, { 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 executeActionWithCallbackOnSuccess(
 | 
				
			||||||
 | 
					      action: String,
 | 
				
			||||||
 | 
					      project: Project,
 | 
				
			||||||
 | 
					      context: ExecutionContext,
 | 
				
			||||||
 | 
					      callback: () -> Unit,
 | 
				
			||||||
 | 
					    ): Boolean {
 | 
				
			||||||
 | 
					      val res = Ref.create<Boolean>(false)
 | 
				
			||||||
 | 
					      AsyncActionExecutionService.getInstance(project).withExecutionAfterAction(
 | 
				
			||||||
 | 
					        action,
 | 
				
			||||||
 | 
					        { res.set(injector.actionExecutor.executeAction(action, context)) },
 | 
				
			||||||
 | 
					        { if (res.get()) callback() })
 | 
				
			||||||
 | 
					      return res.get()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun afterCommenting(
 | 
					    private fun afterCommenting(
 | 
				
			||||||
      mode: Mode,
 | 
					      mode: Mode,
 | 
				
			||||||
      editor: VimEditor,
 | 
					      editor: VimEditor,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package com.maddyhome.idea.vim.extension.surround
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.util.text.CharSequenceSubSequence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal data class RepeatedCharSequence(val text: CharSequence, val count: Int) : CharSequence {
 | 
				
			||||||
 | 
					  override val length = text.length * count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun get(index: Int): Char {
 | 
				
			||||||
 | 
					    if (index < 0 || index >= length) throw IndexOutOfBoundsException()
 | 
				
			||||||
 | 
					    return text[index % text.length]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
 | 
				
			||||||
 | 
					    return CharSequenceSubSequence(this, startIndex, endIndex)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun toString(): String {
 | 
				
			||||||
 | 
					    return text.repeat(count)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    fun of(text: CharSequence, count: Int): CharSequence {
 | 
				
			||||||
 | 
					      return when (count) {
 | 
				
			||||||
 | 
					        0 -> ""
 | 
				
			||||||
 | 
					        1 -> text
 | 
				
			||||||
 | 
					        else -> RepeatedCharSequence(text, count)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -19,10 +19,7 @@ import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.api.setChangeMarks
 | 
					import com.maddyhome.idea.vim.api.setChangeMarks
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode
 | 
					import com.maddyhome.idea.vim.command.MappingMode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.selectionType
 | 
					 | 
				
			||||||
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
 | 
				
			||||||
@@ -34,7 +31,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.setRegisterForCaret
 | 
					import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.mode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
 | 
					import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
 | 
				
			||||||
import com.maddyhome.idea.vim.key.OperatorFunction
 | 
					import com.maddyhome.idea.vim.key.OperatorFunction
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
					import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
				
			||||||
@@ -43,6 +39,10 @@ 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 com.maddyhome.idea.vim.put.PutData
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.selectionType
 | 
				
			||||||
import org.jetbrains.annotations.NonNls
 | 
					import org.jetbrains.annotations.NonNls
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
@@ -83,7 +83,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
    override val isRepeatable = true
 | 
					    override val isRepeatable = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
					    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
      setOperatorFunction(Operator(supportsMultipleCursors = false)) // TODO
 | 
					      setOperatorFunction(Operator(supportsMultipleCursors = false, count = 1)) // TODO
 | 
				
			||||||
      executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
 | 
					      executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -104,7 +104,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
        val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
 | 
					        val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
 | 
				
			||||||
        if (lastNonWhiteSpaceOffset != null) {
 | 
					        if (lastNonWhiteSpaceOffset != null) {
 | 
				
			||||||
          val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
 | 
					          val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
 | 
				
			||||||
          performSurround(pair, range, it)
 | 
					          performSurround(pair, range, it, count = operatorArguments.count1)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
//        it.moveToOffset(lineStartOffset)
 | 
					//        it.moveToOffset(lineStartOffset)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -125,7 +125,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
  private class VSurroundHandler : ExtensionHandler {
 | 
					  private class VSurroundHandler : ExtensionHandler {
 | 
				
			||||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
					    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
				
			||||||
      // NB: Operator ignores SelectionType anyway
 | 
					      // NB: Operator ignores SelectionType anyway
 | 
				
			||||||
      if (!Operator(supportsMultipleCursors = true).apply(editor, context, editor.mode.selectionType)) {
 | 
					      if (!Operator(supportsMultipleCursors = true, count = operatorArguments.count1).apply(editor, context, editor.mode.selectionType)) {
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      runWriteAction {
 | 
					      runWriteAction {
 | 
				
			||||||
@@ -261,7 +261,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction {
 | 
					  private class Operator(private val supportsMultipleCursors: Boolean, private val count: Int) : OperatorFunction {
 | 
				
			||||||
    override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
 | 
					    override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
 | 
				
			||||||
      val editor = vimEditor.ij
 | 
					      val editor = vimEditor.ij
 | 
				
			||||||
      val c = getChar(editor)
 | 
					      val c = getChar(editor)
 | 
				
			||||||
@@ -273,11 +273,11 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
        val change = VimPlugin.getChange()
 | 
					        val change = VimPlugin.getChange()
 | 
				
			||||||
        if (supportsMultipleCursors) {
 | 
					        if (supportsMultipleCursors) {
 | 
				
			||||||
          editor.runWithEveryCaretAndRestore {
 | 
					          editor.runWithEveryCaretAndRestore {
 | 
				
			||||||
            applyOnce(editor, change, pair)
 | 
					            applyOnce(editor, change, pair, count)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
          applyOnce(editor, change, pair)
 | 
					          applyOnce(editor, change, pair, count)
 | 
				
			||||||
          // Jump back to start
 | 
					          // Jump back to start
 | 
				
			||||||
          executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
 | 
					          executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -285,18 +285,15 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
      return true
 | 
					      return true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>) {
 | 
					    private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
 | 
				
			||||||
      // XXX: Will it work with line-wise or block-wise selections?
 | 
					      // XXX: Will it work with line-wise or block-wise selections?
 | 
				
			||||||
      val primaryCaret = editor.caretModel.primaryCaret
 | 
					      val primaryCaret = editor.caretModel.primaryCaret
 | 
				
			||||||
      val range = getSurroundRange(primaryCaret.vim)
 | 
					      val range = getSurroundRange(primaryCaret.vim)
 | 
				
			||||||
      if (range != null) {
 | 
					      if (range != null) {
 | 
				
			||||||
        change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, pair.first)
 | 
					        val start = RepeatedCharSequence.of(pair.first, count)
 | 
				
			||||||
        change.insertText(
 | 
					        val end = RepeatedCharSequence.of(pair.second, count)
 | 
				
			||||||
          IjVimEditor(editor),
 | 
					        change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, start)
 | 
				
			||||||
          IjVimCaret(primaryCaret),
 | 
					        change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + start.length, end)
 | 
				
			||||||
          range.endOffset + pair.first.length,
 | 
					 | 
				
			||||||
          pair.second
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -378,15 +375,15 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, tagsOnNewLines: Boolean = false) {
 | 
					    private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) {
 | 
				
			||||||
      runWriteAction {
 | 
					      runWriteAction {
 | 
				
			||||||
        val editor = caret.editor
 | 
					        val editor = caret.editor
 | 
				
			||||||
        val change = VimPlugin.getChange()
 | 
					        val change = VimPlugin.getChange()
 | 
				
			||||||
        val leftSurround = pair.first + if (tagsOnNewLines) "\n" else ""
 | 
					        val leftSurround = RepeatedCharSequence.of(pair.first + if (tagsOnNewLines) "\n" else "", count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val isEOF = range.endOffset == editor.text().length
 | 
					        val isEOF = range.endOffset == editor.text().length
 | 
				
			||||||
        val hasNewLine = editor.endsWithNewLine()
 | 
					        val hasNewLine = editor.endsWithNewLine()
 | 
				
			||||||
        val rightSurround = if (tagsOnNewLines) {
 | 
					        val rightSurround = (if (tagsOnNewLines) {
 | 
				
			||||||
          if (isEOF && !hasNewLine) {
 | 
					          if (isEOF && !hasNewLine) {
 | 
				
			||||||
            "\n" + pair.second
 | 
					            "\n" + pair.second
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
@@ -394,7 +391,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          pair.second
 | 
					          pair.second
 | 
				
			||||||
        }
 | 
					        }).let { RepeatedCharSequence.of(it, count) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        change.insertText(editor, caret, range.startOffset, leftSurround)
 | 
					        change.insertText(editor, caret, range.startOffset, leftSurround)
 | 
				
			||||||
        change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
 | 
					        change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,14 @@ import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
				
			|||||||
import com.intellij.openapi.diagnostic.logger
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import com.intellij.openapi.editor.LogicalPosition
 | 
					import com.intellij.openapi.editor.LogicalPosition
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.actions.EnterAction
 | 
				
			||||||
import com.intellij.openapi.editor.event.EditorMouseEvent
 | 
					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.ui.MessageType
 | 
					import com.intellij.openapi.ui.MessageType
 | 
				
			||||||
import com.intellij.openapi.ui.popup.Balloon
 | 
					import com.intellij.openapi.ui.popup.Balloon
 | 
				
			||||||
import com.intellij.openapi.ui.popup.JBPopupFactory
 | 
					import com.intellij.openapi.ui.popup.JBPopupFactory
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.UserDataHolder
 | 
				
			||||||
import com.intellij.openapi.util.text.StringUtil
 | 
					import com.intellij.openapi.util.text.StringUtil
 | 
				
			||||||
import com.intellij.psi.codeStyle.CodeStyleManager
 | 
					import com.intellij.psi.codeStyle.CodeStyleManager
 | 
				
			||||||
import com.intellij.psi.util.PsiUtilBase
 | 
					import com.intellij.psi.util.PsiUtilBase
 | 
				
			||||||
@@ -52,6 +54,7 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
 | 
				
			|||||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
 | 
					import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.Motion
 | 
					import com.maddyhome.idea.vim.handler.Motion
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
 | 
					import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.commandContinuation
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.CharacterHelper
 | 
					import com.maddyhome.idea.vim.helper.CharacterHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.CharacterHelper.changeCase
 | 
					import com.maddyhome.idea.vim.helper.CharacterHelper.changeCase
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
 | 
					import com.maddyhome.idea.vim.helper.CharacterHelper.charType
 | 
				
			||||||
@@ -69,8 +72,10 @@ import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
				
			|||||||
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.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
 | 
					import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.mode
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.commands.SortOption
 | 
					import com.maddyhome.idea.vim.vimscript.model.commands.SortOption
 | 
				
			||||||
import org.jetbrains.annotations.TestOnly
 | 
					import org.jetbrains.annotations.TestOnly
 | 
				
			||||||
import java.math.BigInteger
 | 
					import java.math.BigInteger
 | 
				
			||||||
@@ -116,6 +121,35 @@ public class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
    injector.scroll.scrollCaretIntoView(vimEditor)
 | 
					    injector.scroll.scrollCaretIntoView(vimEditor)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * If this is REPLACE mode we need to turn off OVERWRITE before and then turn OVERWRITE back on after sending the
 | 
				
			||||||
 | 
					   * "ENTER" key.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  override fun processEnter(
 | 
				
			||||||
 | 
					    editor: VimEditor,
 | 
				
			||||||
 | 
					    caret: VimCaret,
 | 
				
			||||||
 | 
					    context: ExecutionContext,
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    if (editor.mode is Mode.REPLACE) {
 | 
				
			||||||
 | 
					      editor.insertMode = true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      val continuation = (context.context as UserDataHolder).getUserData(commandContinuation)
 | 
				
			||||||
 | 
					      val ijEditor = editor.ij
 | 
				
			||||||
 | 
					      val ij = context.ij
 | 
				
			||||||
 | 
					      val ijCaret = caret.ij
 | 
				
			||||||
 | 
					      if (continuation != null) {
 | 
				
			||||||
 | 
					        continuation.execute(ijEditor, ijCaret, ij)
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        EnterAction().handler.execute(ijEditor, ijCaret, ij)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      if (editor.mode is Mode.REPLACE) {
 | 
				
			||||||
 | 
					        editor.insertMode = false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun getDeleteRangeAndType2(
 | 
					  override fun getDeleteRangeAndType2(
 | 
				
			||||||
    editor: VimEditor,
 | 
					    editor: VimEditor,
 | 
				
			||||||
    caret: VimCaret,
 | 
					    caret: VimCaret,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,14 +89,17 @@ public class FileGroup extends VimFileBase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Nullable VirtualFile findFile(@NotNull String filename, @NotNull Project project) {
 | 
					  @Nullable VirtualFile findFile(@NotNull String filename, @NotNull Project project) {
 | 
				
			||||||
    VirtualFile found;
 | 
					    VirtualFile found;
 | 
				
			||||||
    if (filename.length() > 2 && filename.charAt(0) == '~' && filename.charAt(1) == File.separatorChar) {
 | 
					    // Vim supports both ~/ and ~\ (tested on Mac and Windows). On Windows, it supports forward- and back-slashes, but
 | 
				
			||||||
      String homefile = filename.substring(2);
 | 
					    // it only supports forward slash on Unix (tested on Mac)
 | 
				
			||||||
 | 
					    // VFS works with both directory separators (tested on Mac and Windows)
 | 
				
			||||||
 | 
					    if (filename.startsWith("~/") || filename.startsWith("~\\")) {
 | 
				
			||||||
 | 
					      String relativePath = filename.substring(2);
 | 
				
			||||||
      String dir = System.getProperty("user.home");
 | 
					      String dir = System.getProperty("user.home");
 | 
				
			||||||
      if (logger.isDebugEnabled()) {
 | 
					      if (logger.isDebugEnabled()) {
 | 
				
			||||||
        logger.debug("home dir file");
 | 
					        logger.debug("home dir file");
 | 
				
			||||||
        logger.debug("looking for " + homefile + " in " + dir);
 | 
					        logger.debug("looking for " + relativePath + " in " + dir);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      found = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(dir, homefile));
 | 
					      found = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(dir, relativePath));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      found = LocalFileSystem.getInstance().findFileByIoFile(new File(filename));
 | 
					      found = LocalFileSystem.getInstance().findFileByIoFile(new File(filename));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,11 +31,11 @@ public open class GlobalIjOptions(scope: OptionAccessScope) : OptionsPropertiesB
 | 
				
			|||||||
  public var visualdelay: Int by optionProperty(IjOptions.visualdelay)
 | 
					  public var visualdelay: Int by optionProperty(IjOptions.visualdelay)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Temporary options to control work-in-progress behaviour
 | 
					  // Temporary options to control work-in-progress behaviour
 | 
				
			||||||
  public var octopushandler: Boolean by optionProperty(IjOptions.octopushandler)
 | 
					 | 
				
			||||||
  public var oldundo: Boolean by optionProperty(IjOptions.oldundo)
 | 
					  public var oldundo: Boolean by optionProperty(IjOptions.oldundo)
 | 
				
			||||||
  public var unifyjumps: Boolean by optionProperty(IjOptions.unifyjumps)
 | 
					  public var unifyjumps: Boolean by optionProperty(IjOptions.unifyjumps)
 | 
				
			||||||
  public var exCommandAnnotation: Boolean by optionProperty(IjOptions.exCommandAnnotation)
 | 
					  public var exCommandAnnotation: Boolean by optionProperty(IjOptions.exCommandAnnotation)
 | 
				
			||||||
  public var vimscriptFunctionAnnotation: Boolean by optionProperty(IjOptions.vimscriptFunctionAnnotation)
 | 
					  public var vimscriptFunctionAnnotation: Boolean by optionProperty(IjOptions.vimscriptFunctionAnnotation)
 | 
				
			||||||
 | 
					  public var commandOrMotionAnnotation: Boolean by optionProperty(IjOptions.commandOrMotionAnnotation)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,12 +80,12 @@ public object IjOptions {
 | 
				
			|||||||
      "lookupkeys",
 | 
					      "lookupkeys",
 | 
				
			||||||
      "<Tab>,<Down>,<Up>,<Enter>,<Left>,<Right>,<C-Down>,<C-Up>,<PageUp>,<PageDown>,<C-J>,<C-Q>")
 | 
					      "<Tab>,<Down>,<Up>,<Enter>,<Left>,<Right>,<C-Down>,<C-Up>,<PageUp>,<PageDown>,<C-J>,<C-Q>")
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
  public val octopushandler: ToggleOption = addOption(ToggleOption("octopushandler", GLOBAL, "octopushandler", false))
 | 
					 | 
				
			||||||
  public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", true))
 | 
					 | 
				
			||||||
  public val trackactionids: ToggleOption = addOption(ToggleOption("trackactionids", GLOBAL, "tai", false))
 | 
					  public val trackactionids: ToggleOption = addOption(ToggleOption("trackactionids", GLOBAL, "tai", false))
 | 
				
			||||||
  public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true))
 | 
					  public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true))
 | 
				
			||||||
  public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true))
 | 
					 | 
				
			||||||
  public val visualdelay: UnsignedNumberOption = addOption(UnsignedNumberOption("visualdelay", GLOBAL, "visualdelay", 100))
 | 
					  public val visualdelay: UnsignedNumberOption = addOption(UnsignedNumberOption("visualdelay", GLOBAL, "visualdelay", 100))
 | 
				
			||||||
 | 
					  public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", true, isTemporary = true))
 | 
				
			||||||
 | 
					  public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isTemporary = true))
 | 
				
			||||||
 | 
					  public val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isTemporary = true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This needs to be Option<out VimDataType> so that it can work with derived option types, such as NumberOption, which
 | 
					  // This needs to be Option<out VimDataType> so that it can work with derived option types, such as NumberOption, which
 | 
				
			||||||
  // derives from Option<VimInt>
 | 
					  // derives from Option<VimInt>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import com.maddyhome.idea.vim.EventFacade;
 | 
				
			|||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
import com.maddyhome.idea.vim.action.ComplicatedKeysAction;
 | 
					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.action.change.LazyVimCommand;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.*;
 | 
					import com.maddyhome.idea.vim.api.*;
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode;
 | 
					import com.maddyhome.idea.vim.command.MappingMode;
 | 
				
			||||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
					import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
				
			||||||
@@ -208,6 +209,25 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
    registerRequiredShortcut(Collections.singletonList(keyStroke), owner);
 | 
					    registerRequiredShortcut(Collections.singletonList(keyStroke), owner);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void registerCommandAction(@NotNull LazyVimCommand command) {
 | 
				
			||||||
 | 
					    if (ApplicationManager.getApplication().isUnitTestMode()) {
 | 
				
			||||||
 | 
					      initIdentityChecker();
 | 
				
			||||||
 | 
					      for (List<KeyStroke> keys : command.getKeys()) {
 | 
				
			||||||
 | 
					        checkCommand(command.getModes(), command, keys);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (List<KeyStroke> keyStrokes : command.getKeys()) {
 | 
				
			||||||
 | 
					      registerRequiredShortcut(keyStrokes, MappingOwner.IdeaVim.System.INSTANCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (MappingMode mappingMode : command.getModes()) {
 | 
				
			||||||
 | 
					        Node<VimActionsInitiator> node = getKeyRoot(mappingMode);
 | 
				
			||||||
 | 
					        NodesKt.addLeafs(node, keyStrokes, command);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Deprecated
 | 
				
			||||||
  public void registerCommandAction(@NotNull VimActionsInitiator actionHolder) {
 | 
					  public void registerCommandAction(@NotNull VimActionsInitiator actionHolder) {
 | 
				
			||||||
    IjVimActionsInitiator holder = (IjVimActionsInitiator)actionHolder;
 | 
					    IjVimActionsInitiator holder = (IjVimActionsInitiator)actionHolder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -254,7 +274,9 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private void registerRequiredShortcut(@NotNull List<KeyStroke> keys, MappingOwner owner) {
 | 
					  private void registerRequiredShortcut(@NotNull List<KeyStroke> keys, MappingOwner owner) {
 | 
				
			||||||
    for (KeyStroke key : keys) {
 | 
					    for (KeyStroke key : keys) {
 | 
				
			||||||
      if (key.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
 | 
					      if (key.getKeyChar() == KeyEvent.CHAR_UNDEFINED &&
 | 
				
			||||||
 | 
					          key.getKeyCode() != KeyEvent.VK_ESCAPE &&
 | 
				
			||||||
 | 
					          key.getKeyCode() != KeyEvent.VK_ENTER) {
 | 
				
			||||||
        getRequiredShortcutKeys().add(new RequiredShortcut(key, owner));
 | 
					        getRequiredShortcutKeys().add(new RequiredShortcut(key, owner));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ import java.util.Set;
 | 
				
			|||||||
@Deprecated
 | 
					@Deprecated
 | 
				
			||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.3")
 | 
					@ApiStatus.ScheduledForRemoval(inVersion = "2.3")
 | 
				
			||||||
public class MarkGroup {
 | 
					public class MarkGroup {
 | 
				
			||||||
  public List<Jump> jumps = VimInjectorKt.injector.getJumpService().getJumps();
 | 
					  public List<Jump> jumps = VimInjectorKt.injector.getJumpService().getJumps("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void saveJumpLocation(@NotNull Editor editor) {
 | 
					  public void saveJumpLocation(@NotNull Editor editor) {
 | 
				
			||||||
    VimInjectorKt.injector.getJumpService().saveJumpLocation(new IjVimEditor(editor));
 | 
					    VimInjectorKt.injector.getJumpService().saveJumpLocation(new IjVimEditor(editor));
 | 
				
			||||||
@@ -54,7 +54,7 @@ public class MarkGroup {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @Nullable
 | 
					  @Nullable
 | 
				
			||||||
  public Jump getJump(int count) {
 | 
					  public Jump getJump(int count) {
 | 
				
			||||||
    return VimInjectorKt.injector.getJumpService().getJump(count);
 | 
					    return VimInjectorKt.injector.getJumpService().getJump("", count);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Nullable
 | 
					  @Nullable
 | 
				
			||||||
@@ -115,7 +115,7 @@ public class MarkGroup {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public int getJumpSpot() {
 | 
					  public int getJumpSpot() {
 | 
				
			||||||
    return VimInjectorKt.injector.getJumpService().getJumpSpot();
 | 
					    return VimInjectorKt.injector.getJumpService().getJumpSpot("");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void updateMarkFromDelete(@Nullable VimEditor editor,
 | 
					  public void updateMarkFromDelete(@Nullable VimEditor editor,
 | 
				
			||||||
@@ -133,6 +133,6 @@ public class MarkGroup {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void dropLastJump() {
 | 
					  public void dropLastJump() {
 | 
				
			||||||
    VimInjectorKt.injector.getJumpService().dropLastJump();
 | 
					    VimInjectorKt.injector.getJumpService().dropLastJump("");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,8 @@ 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.addJump
 | 
					import com.maddyhome.idea.vim.api.addJump
 | 
				
			||||||
import com.maddyhome.idea.vim.api.anyNonWhitespace
 | 
					import com.maddyhome.idea.vim.api.anyNonWhitespace
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.getJump
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.getJumpSpot
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
 | 
					import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
 | 
				
			||||||
import com.maddyhome.idea.vim.api.getVisualLineCount
 | 
					import com.maddyhome.idea.vim.api.getVisualLineCount
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
@@ -163,8 +165,8 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun moveCaretToJump(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Motion {
 | 
					  override fun moveCaretToJump(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Motion {
 | 
				
			||||||
    val jumpService = injector.jumpService
 | 
					    val jumpService = injector.jumpService
 | 
				
			||||||
    val spot = jumpService.getJumpSpot()
 | 
					    val spot = jumpService.getJumpSpot(editor)
 | 
				
			||||||
    val (line, col, fileName) = jumpService.getJump(count) ?: return Motion.Error
 | 
					    val (line, col, fileName) = jumpService.getJump(editor, count) ?: return Motion.Error
 | 
				
			||||||
    val vf = EditorHelper.getVirtualFile(editor.ij) ?: return Motion.Error
 | 
					    val vf = EditorHelper.getVirtualFile(editor.ij) ?: return Motion.Error
 | 
				
			||||||
    val lp = BufferPosition(line, col, false)
 | 
					    val lp = BufferPosition(line, col, false)
 | 
				
			||||||
    val lpNative = LogicalPosition(line, col, false)
 | 
					    val lpNative = LogicalPosition(line, col, false)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,7 @@ public class ProcessGroup extends VimProcessGroupBase {
 | 
				
			|||||||
    injector.getMarkService().setVisualSelectionMarks(editor);
 | 
					    injector.getMarkService().setVisualSelectionMarks(editor);
 | 
				
			||||||
    VimStateMachine.Companion.getInstance(editor).setMode(Mode.CMD_LINE.INSTANCE);
 | 
					    VimStateMachine.Companion.getInstance(editor).setMode(Mode.CMD_LINE.INSTANCE);
 | 
				
			||||||
    ExEntryPanel panel = ExEntryPanel.getInstance();
 | 
					    ExEntryPanel panel = ExEntryPanel.getInstance();
 | 
				
			||||||
    panel.activate(((IjVimEditor) editor).getEditor(), ((IjEditorExecutionContext) context).getContext(), ":", initText, cmd.getCount());
 | 
					    panel.activate(((IjVimEditor) editor).getEditor(), ((IjEditorExecutionContext) context).getContext(), ":", initText, 1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
@@ -116,7 +116,7 @@ public class ProcessGroup extends VimProcessGroupBase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      logger.debug("processing command");
 | 
					      logger.debug("processing command");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      String text = panel.getText();
 | 
					      final 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
 | 
				
			||||||
@@ -127,15 +127,7 @@ public class ProcessGroup extends VimProcessGroupBase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread());
 | 
					      if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      int repeat = 1;
 | 
					      VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE);
 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    catch (ExException e) {
 | 
					    catch (ExException e) {
 | 
				
			||||||
      VimPlugin.showMessage(e.getMessage());
 | 
					      VimPlugin.showMessage(e.getMessage());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ import com.intellij.openapi.components.Storage
 | 
				
			|||||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 | 
					import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.PlaceInfo
 | 
					import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.PlaceInfo
 | 
				
			||||||
import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.RecentPlacesListener
 | 
					import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.RecentPlacesListener
 | 
				
			||||||
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
import com.intellij.openapi.util.text.StringUtil
 | 
					import com.intellij.openapi.util.text.StringUtil
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimJumpServiceBase
 | 
					import com.maddyhome.idea.vim.api.VimJumpServiceBase
 | 
				
			||||||
@@ -40,39 +41,51 @@ internal class VimJumpServiceImpl : VimJumpServiceBase(), PersistentStateCompone
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // We do not delete old project records.
 | 
				
			||||||
 | 
					  // Rationale: It's more likely that users will want to review their old projects and access their jump history 
 | 
				
			||||||
 | 
					  // (e.g., recent files), than for the 100 jumps (max number of records) to consume enough space to be noticeable.
 | 
				
			||||||
  override fun getState(): Element {
 | 
					  override fun getState(): Element {
 | 
				
			||||||
    val jumpsElem = Element("jumps")
 | 
					    val projectsElem = Element("projects")
 | 
				
			||||||
    for (jump in jumps) {
 | 
					    for ((project, jumps) in projectToJumps) {
 | 
				
			||||||
      val jumpElem = Element("jump")
 | 
					      val projectElement = Element("project").setAttribute("id", project)
 | 
				
			||||||
      jumpElem.setAttribute("line", jump.line.toString())
 | 
					      for (jump in jumps) {
 | 
				
			||||||
      jumpElem.setAttribute("column", jump.col.toString())
 | 
					        val jumpElem = Element("jump")
 | 
				
			||||||
      jumpElem.setAttribute("filename", StringUtil.notNullize(jump.filepath))
 | 
					        jumpElem.setAttribute("line", jump.line.toString())
 | 
				
			||||||
      jumpsElem.addContent(jumpElem)
 | 
					        jumpElem.setAttribute("column", jump.col.toString())
 | 
				
			||||||
      if (logger.isDebug()) {
 | 
					        jumpElem.setAttribute("filename", StringUtil.notNullize(jump.filepath))
 | 
				
			||||||
        logger.debug("saved jump = $jump")
 | 
					        projectElement.addContent(jumpElem)
 | 
				
			||||||
 | 
					        if (logger.isDebug()) {
 | 
				
			||||||
 | 
					          logger.debug("saved jump = $jump")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      projectsElem.addContent(projectElement)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return jumpsElem
 | 
					    return projectsElem
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun loadState(state: Element) {
 | 
					  override fun loadState(state: Element) {
 | 
				
			||||||
    val jumpList = state.getChildren("jump")
 | 
					    val projectElements = state.getChildren("project")
 | 
				
			||||||
    for (jumpElement in jumpList) {
 | 
					    for (projectElement in projectElements) {
 | 
				
			||||||
      val jump = Jump(
 | 
					      val jumps = mutableListOf<Jump>()
 | 
				
			||||||
        Integer.parseInt(jumpElement.getAttributeValue("line")),
 | 
					      val jumpElements = projectElement.getChildren("jump")
 | 
				
			||||||
        Integer.parseInt(jumpElement.getAttributeValue("column")),
 | 
					      for (jumpElement in jumpElements) {
 | 
				
			||||||
        jumpElement.getAttributeValue("filename"),
 | 
					        val jump = Jump(
 | 
				
			||||||
      )
 | 
					          Integer.parseInt(jumpElement.getAttributeValue("line")),
 | 
				
			||||||
      jumps.add(jump)
 | 
					          Integer.parseInt(jumpElement.getAttributeValue("column")),
 | 
				
			||||||
    }
 | 
					          jumpElement.getAttributeValue("filename"),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    if (logger.isDebug()) {
 | 
					        jumps.add(jump)
 | 
				
			||||||
      logger.debug("jumps=$jumps")
 | 
					      }
 | 
				
			||||||
 | 
					      if (logger.isDebug()) {
 | 
				
			||||||
 | 
					        logger.debug("jumps=$jumps")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      val projectId = projectElement.getAttributeValue("id")
 | 
				
			||||||
 | 
					      projectToJumps[projectId] = jumps
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class JumpsListener : RecentPlacesListener {
 | 
					internal class JumpsListener(val project: Project) : RecentPlacesListener {
 | 
				
			||||||
  override fun recentPlaceAdded(changePlace: PlaceInfo, isChanged: Boolean) {
 | 
					  override fun recentPlaceAdded(changePlace: PlaceInfo, isChanged: Boolean) {
 | 
				
			||||||
    if (!injector.globalIjOptions().unifyjumps) return
 | 
					    if (!injector.globalIjOptions().unifyjumps) return
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -81,7 +94,7 @@ internal class JumpsListener : RecentPlacesListener {
 | 
				
			|||||||
      if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
 | 
					      if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
 | 
				
			||||||
      // we do not want jumps that were processed before
 | 
					      // we do not want jumps that were processed before
 | 
				
			||||||
      val jump = buildJump(changePlace) ?: return
 | 
					      val jump = buildJump(changePlace) ?: return
 | 
				
			||||||
      jumpService.addJump(jump, true)
 | 
					      jumpService.addJump(project.basePath ?: IjVimEditor.DEFAULT_PROJECT_ID, jump, true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,7 +106,7 @@ internal class JumpsListener : RecentPlacesListener {
 | 
				
			|||||||
      if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
 | 
					      if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
 | 
				
			||||||
      // we do not want jumps that were processed before
 | 
					      // we do not want jumps that were processed before
 | 
				
			||||||
      val jump = buildJump(changePlace) ?: return
 | 
					      val jump = buildJump(changePlace) ?: return
 | 
				
			||||||
      jumpService.removeJump(jump)
 | 
					      jumpService.removeJump(project.basePath ?: IjVimEditor.DEFAULT_PROJECT_ID, jump)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import com.intellij.serviceContainer.BaseKeyedLazyInstance
 | 
				
			|||||||
import com.intellij.util.SmartList
 | 
					import com.intellij.util.SmartList
 | 
				
			||||||
import com.intellij.util.xmlb.annotations.Attribute
 | 
					import com.intellij.util.xmlb.annotations.Attribute
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode
 | 
					import com.maddyhome.idea.vim.command.MappingMode
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -36,6 +37,8 @@ import javax.swing.KeyStroke
 | 
				
			|||||||
 *   The reason is startup performance. Using the extension points you don't even have to load classes of actions.
 | 
					 *   The reason is startup performance. Using the extension points you don't even have to load classes of actions.
 | 
				
			||||||
 *   So, all actions are loaded on demand, including classes in classloader.
 | 
					 *   So, all actions are loaded on demand, including classes in classloader.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated(message = "Please use CommandOrMotion annotation")
 | 
				
			||||||
 | 
					@ScheduledForRemoval(inVersion = "2.9.0")
 | 
				
			||||||
internal class ActionBeanClass : BaseKeyedLazyInstance<EditorActionHandlerBase>() {
 | 
					internal class ActionBeanClass : BaseKeyedLazyInstance<EditorActionHandlerBase>() {
 | 
				
			||||||
  @Attribute("implementation")
 | 
					  @Attribute("implementation")
 | 
				
			||||||
  var implementation: String? = null
 | 
					  var implementation: String? = null
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionHandlerBean
 | 
				
			||||||
 | 
					import com.intellij.openapi.extensions.ExtensionPointName
 | 
				
			||||||
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
 | 
					import com.intellij.openapi.startup.StartupActivity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Logs the chain of handlers for esc and enter
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * As we made a migration to the new way of handling esc keys (VIM-2974), we may face several issues around that
 | 
				
			||||||
 | 
					 * One of the possible issues is that some plugin may also register a shortcut for this key and do not pass
 | 
				
			||||||
 | 
					 * the control to the next handler. In this way, the esc won't work, but there will be no exceptions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a logger that logs the chain of handlers.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Strictly speaking, such access to the extension point is not allowed by the platform. But we can't do this thing
 | 
				
			||||||
 | 
					 *   otherwise, so let's use it as long as we can.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class EditorHandlersChainLogger : StartupActivity {
 | 
				
			||||||
 | 
					  @Suppress("UnresolvedPluginConfigReference")
 | 
				
			||||||
 | 
					  private val editorHandlers = ExtensionPointName<EditorActionHandlerBean>("com.intellij.editorActionHandler")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun runActivity(project: Project) {
 | 
				
			||||||
 | 
					    val escHandlers = editorHandlers.extensionList
 | 
				
			||||||
 | 
					      .filter { it.action == "EditorEscape" }
 | 
				
			||||||
 | 
					      .joinToString("\n") { it.implementationClass }
 | 
				
			||||||
 | 
					    val enterHandlers = editorHandlers.extensionList
 | 
				
			||||||
 | 
					      .filter { it.action == "EditorEnter" }
 | 
				
			||||||
 | 
					      .joinToString("\n") { it.implementationClass }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LOG.info("Esc handlers chain:\n$escHandlers")
 | 
				
			||||||
 | 
					    LOG.info("Enter handlers chain:\n$enterHandlers")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    val LOG = logger<EditorHandlersChainLogger>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -8,27 +8,65 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.handler
 | 
					package com.maddyhome.idea.vim.handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.codeInsight.editorActions.AutoHardWrapHandler
 | 
				
			||||||
 | 
					import com.intellij.codeInsight.lookup.LookupManager
 | 
				
			||||||
 | 
					import com.intellij.ide.DataManager
 | 
				
			||||||
import com.intellij.openapi.actionSystem.DataContext
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.application.invokeLater
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.intellij.openapi.editor.Caret
 | 
					import com.intellij.openapi.editor.Caret
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionHandler
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.impl.CaretModelImpl
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.Key
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.UserDataHolder
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.removeUserData
 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.api.key
 | 
					import com.maddyhome.idea.vim.api.key
 | 
				
			||||||
import com.maddyhome.idea.vim.command.CommandState
 | 
					import com.maddyhome.idea.vim.group.IjOptionConstants
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.mode
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimStateMachine
 | 
					import com.maddyhome.idea.vim.helper.inNormalMode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.isPrimaryEditor
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.actionStartedFromVim
 | 
					import com.maddyhome.idea.vim.newapi.actionStartedFromVim
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.mode
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal val commandContinuation = Key.create<EditorActionHandler>("commandContinuation")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler that corrects the shape of the caret in python notebooks.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * By default, py notebooks show a thin caret after entering the cell.
 | 
				
			||||||
 | 
					 *   However, we're in normal mode, so this handler fixes it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class CaretShapeEnterEditorHandler(private val nextHandler: EditorActionHandler) : EditorActionHandler() {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    if (VimPlugin.isEnabled()) {
 | 
				
			||||||
 | 
					      invokeLater {
 | 
				
			||||||
 | 
					        editor.updateCaretsVisualAttributes()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This handler doesn't work in tests for ex commands
 | 
					 * This handler doesn't work in tests for ex commands
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal abstract class OctopusHandler(private val nextHandler: EditorActionHandler) : EditorActionHandler() {
 | 
					internal abstract class OctopusHandler(private val nextHandler: EditorActionHandler?) : EditorActionHandler() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  abstract fun executeHandler(editor: Editor, caret: Caret?, dataContext: DataContext?)
 | 
					  abstract fun executeHandler(editor: Editor, caret: Caret?, dataContext: DataContext?)
 | 
				
			||||||
  open fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
					  open fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
				
			||||||
@@ -37,64 +75,228 @@ internal abstract class OctopusHandler(private val nextHandler: EditorActionHand
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  final override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
					  final override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
    if (isThisHandlerEnabled(editor, caret, dataContext)) {
 | 
					    if (isThisHandlerEnabled(editor, caret, dataContext)) {
 | 
				
			||||||
      executeHandler(editor, caret, dataContext)
 | 
					      val executeInInvokeLater = executeInInvokeLater(editor)
 | 
				
			||||||
 | 
					      val executionHandler = {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          (dataContext as? UserDataHolder)?.putUserData(commandContinuation, nextHandler)
 | 
				
			||||||
 | 
					          executeHandler(editor, caret, dataContext)
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					          (dataContext as? UserDataHolder)?.removeUserData(commandContinuation)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (executeInInvokeLater) {
 | 
				
			||||||
 | 
					        // This `invokeLater` is used to escape the potential `runForEachCaret` function.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // The `runForEachCaret` function is disallowed to be called recursively. However, with this new handler, we lose
 | 
				
			||||||
 | 
					        //   control if we execute the code inside this function or not. See IDEA-300030 for details.
 | 
				
			||||||
 | 
					        // This means the code in IdeaVim MUST NOT call `runForEachCaret` function. While this is possible for most cases,
 | 
				
			||||||
 | 
					        //   the user may make a mapping to some intellij action where the `runForEachCaret` is called. This breaks
 | 
				
			||||||
 | 
					        //   the condition (see VIM-3103 for example).
 | 
				
			||||||
 | 
					        // Since we can't make sure we don't execute `runForEachCaret`, we have to "escape" out of this function. This is
 | 
				
			||||||
 | 
					        //   done by scheduling the execution of our code later via the invokeLater function.
 | 
				
			||||||
 | 
					        ApplicationManager.getApplication().invokeLater(executionHandler)
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        executionHandler()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      nextHandler.execute(editor, caret, dataContext)
 | 
					      nextHandler?.execute(editor, caret, dataContext)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Suppress("RedundantIf")
 | 
					  private fun executeInInvokeLater(editor: Editor): Boolean {
 | 
				
			||||||
 | 
					    // Currently we have a workaround for the PY console VIM-3157
 | 
				
			||||||
 | 
					    if (FileDocumentManager.getInstance().getFile(editor.document)?.name == "Python Console.py") return false
 | 
				
			||||||
 | 
					    return (editor.caretModel as? CaretModelImpl)?.isIteratingOverCarets ?: true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun isThisHandlerEnabled(editor: Editor, caret: Caret?, dataContext: DataContext?): Boolean {
 | 
					  private fun isThisHandlerEnabled(editor: Editor, caret: Caret?, dataContext: DataContext?): Boolean {
 | 
				
			||||||
    if (!VimPlugin.isEnabled()) return false
 | 
					    if (!VimPlugin.isEnabled()) return false
 | 
				
			||||||
    if (!isHandlerEnabled(editor, dataContext)) return false
 | 
					    if (!isHandlerEnabled(editor, dataContext)) return false
 | 
				
			||||||
    if (dataContext?.actionStartedFromVim == true) return false
 | 
					    if (isNotActualKeyPress(dataContext)) return false
 | 
				
			||||||
    if (!enableOctopus) return false
 | 
					 | 
				
			||||||
    return true
 | 
					    return true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * In some cases IJ runs handlers to imitate "enter" or other key. In such cases we should not process it on the
 | 
				
			||||||
 | 
					   *   IdeaVim side because the user may have mappings on enter the we'll get an unexpected behaviour.
 | 
				
			||||||
 | 
					   * This method should return true if we detect that this handler is called in such case and this is not an
 | 
				
			||||||
 | 
					   *   actual keypress from the user.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  private fun isNotActualKeyPress(dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    if (dataContext != null) {
 | 
				
			||||||
 | 
					      // This flag is set when the enter handlers are executed as a part of moving the comment on the new line
 | 
				
			||||||
 | 
					      val dataManager = DataManager.getInstance()
 | 
				
			||||||
 | 
					      if (dataManager.loadFromDataContext(dataContext, AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY) == true) {
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (dataManager.loadFromDataContext(dataContext, ShiftEnterDetector.Util.key) == true) {
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dataContext?.actionStartedFromVim == true) return true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
					  final override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
    return isThisHandlerEnabled(editor, caret, dataContext) || nextHandler.isEnabled(editor, caret, dataContext)
 | 
					    return isThisHandlerEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					      || nextHandler?.isEnabled(editor, caret, dataContext) == true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Known conflicts & solutions:
 | 
					 * Known conflicts & solutions:
 | 
				
			||||||
 * - Smart step into - set handler after
 | 
					 * - Smart step into - set handler after
 | 
				
			||||||
 * - Python notebooks - set handler before - test needed!
 | 
					 * - Python notebooks - set handler after
 | 
				
			||||||
 * - Ace jump - set handler after
 | 
					 * - Ace jump - set handler after
 | 
				
			||||||
 * - Lookup - doesn't intersect with enter anymore
 | 
					 * - Lookup - doesn't intersect with enter anymore
 | 
				
			||||||
 * - App code - set handler after
 | 
					 * - App code - set handler after
 | 
				
			||||||
 * - Template - doesn't intersect with enter anymore
 | 
					 * - Template - doesn't intersect with enter anymore
 | 
				
			||||||
 | 
					 * - rd.client.editor.enter - set handler before. Otherwise, rider will add new line on enter even in normal mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This rule is disabled due to VIM-3124
 | 
				
			||||||
 | 
					 * - before terminalEnter - not necessary, but terminalEnter causes "file is read-only" tooltip for readonly files VIM-3122
 | 
				
			||||||
 | 
					 * - `first` is set to satisfy sorting condition "before terminalEnter".
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DO NOT add handlers that force to add "first" ordering. This doesn't work with jupyterCommandModeEnterKeyHandler (see VIM-3124)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal class VimEnterHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
					internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandler(nextHandler) {
 | 
				
			||||||
  override val key: String = "<CR>"
 | 
					  override val key: String = "<CR>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    if (!super.isHandlerEnabled(editor, dataContext)) return false
 | 
				
			||||||
 | 
					    // This is important for one-line editors, to turn off enter.
 | 
				
			||||||
 | 
					    // Some one-line editors rely on the fact that there are no enter actions registered. For example, hash search in git
 | 
				
			||||||
 | 
					    // See VIM-2974 for example where it was broken
 | 
				
			||||||
 | 
					    return !editor.isOneLineMode
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun executeHandler(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    if (caret == null || caret === editor.caretModel.primaryCaret)
 | 
				
			||||||
 | 
					    super.executeHandler(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Known conflicts & solutions:
 | 
					 * Known conflicts & solutions:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - Smart step into - set handler after
 | 
					 * - Smart step into - set handler after
 | 
				
			||||||
 * - Python notebooks - set handler before - test needed
 | 
					 * - Python notebooks - set handler before - yes, we have `<CR>` as "after" and `<esc>` as before. I'm not completely sure
 | 
				
			||||||
 | 
					 *   why this combination is correct, but other versions don't work.
 | 
				
			||||||
 * - Ace jump - set handler after
 | 
					 * - Ace jump - set handler after
 | 
				
			||||||
 * - Lookup - It disappears after putting our esc before templateEscape. But I'm not sure why it works like that
 | 
					 * - Lookup - It disappears after putting our esc before templateEscape. But I'm not sure why it works like that
 | 
				
			||||||
 * - App code - Need to review
 | 
					 * - App code - Need to review
 | 
				
			||||||
 * - Template - Need to review
 | 
					 * - Template - Need to review
 | 
				
			||||||
 | 
					 * - before backend.escape - to handle our handlers before Rider processing. Also, without this rule, we get problems like VIM-3146
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
					internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
				
			||||||
  override val key: String = "<Esc>"
 | 
					  override val key: String = "<Esc>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Also, we need to pass esc to IDE if we're in normal mode and there is nothing to cancel
 | 
					 | 
				
			||||||
   * (e.g. we still can cancel numbers, or cancel the replace character mode)
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
					  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
				
			||||||
    return editor.mode != CommandState.Mode.COMMAND ||
 | 
					    val ideaVimSupportDialog =
 | 
				
			||||||
      editor.vimStateMachine?.commandBuilder?.count != 0 ||
 | 
					      injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
 | 
				
			||||||
      editor.vimStateMachine?.isReplaceCharacter == true
 | 
					
 | 
				
			||||||
 | 
					    return editor.isPrimaryEditor() ||
 | 
				
			||||||
 | 
					      EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode ||
 | 
				
			||||||
 | 
					      ideaVimSupportDialog && !editor.vim.mode.inNormalMode
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal abstract class VimKeyHandler(nextHandler: EditorActionHandler) : OctopusHandler(nextHandler) {
 | 
					/**
 | 
				
			||||||
 | 
					 * Rider uses a separate handler for esc to close the completion. IdeaOnlyEscapeHandlerAction is especially
 | 
				
			||||||
 | 
					 *   designer to get all the esc presses, and if there is a completion close it and do not pass the execution further.
 | 
				
			||||||
 | 
					 *   This doesn't work the same as in IJ.
 | 
				
			||||||
 | 
					 * In IdeaVim, we'd like to exit insert mode on closing completion. This is a requirement as the change of this
 | 
				
			||||||
 | 
					 *   behaviour causes a lot of complaining from users. Since the rider handler gets execution control, we don't
 | 
				
			||||||
 | 
					 *    receive an event and don't exit the insert mode.
 | 
				
			||||||
 | 
					 * To fix it, this special handler exists only for rider and stands before the rider's handler. We don't execute the
 | 
				
			||||||
 | 
					 *   handler from rider because the autocompletion is closed automatically anyway.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class VimEscForRiderHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
				
			||||||
 | 
					  override val key: String = "<Esc>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return LookupManager.getActiveLookup(editor) != null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Empty logger for esc presses
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * As we made a migration to the new way of handling esc keys (VIM-2974), we may face several issues around that
 | 
				
			||||||
 | 
					 * One of the possible issues is that some plugin may also register a shortcut for this key and do not pass
 | 
				
			||||||
 | 
					 * the control to the next handler. In this way, the esc won't work, but there will be no exceptions.
 | 
				
			||||||
 | 
					 * This handler, that should stand in front of handlers change, just logs the event of pressing the key
 | 
				
			||||||
 | 
					 * and passes the execution.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class VimEscLoggerHandler(private val nextHandler: EditorActionHandler) : EditorActionHandler() {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    LOG.info("Esc pressed")
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    val LOG = logger<VimEscLoggerHandler>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Workaround to support shift-enter in normal mode.
 | 
				
			||||||
 | 
					 * IJ executes enter handler on shift-enter. This causes an issue that IdeaVim thinks that this is just an enter key.
 | 
				
			||||||
 | 
					 * This thing should be refactored, but for now we'll use this workaround VIM-3159
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class ShiftEnterDetector(private val nextHandler: EditorActionHandler) : EditorActionHandler() {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    DataManager.getInstance().saveInDataContext(dataContext, Util.key, true)
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  object Util {
 | 
				
			||||||
 | 
					    val key = Key.create<Boolean>("vim.is.shift.enter")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    val LOG = logger<VimEscLoggerHandler>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Empty logger for enter presses
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * As we made a migration to the new way of handling enter keys (VIM-2974), we may face several issues around that
 | 
				
			||||||
 | 
					 * One of the possible issues is that some plugin may also register a shortcut for this key and do not pass
 | 
				
			||||||
 | 
					 * the control to the next handler. In this way, the esc won't work, but there will be no exceptions.
 | 
				
			||||||
 | 
					 * This handler, that should stand in front of handlers change, just logs the event of pressing the key
 | 
				
			||||||
 | 
					 * and passes the execution.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class VimEnterLoggerHandler(private val nextHandler: EditorActionHandler) : EditorActionHandler() {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    LOG.info("Enter pressed")
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    val LOG = logger<VimEnterLoggerHandler>()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal abstract class VimKeyHandler(nextHandler: EditorActionHandler?) : OctopusHandler(nextHandler) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  abstract val key: String
 | 
					  abstract val key: String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,27 +313,12 @@ internal abstract class VimKeyHandler(nextHandler: EditorActionHandler) : Octopu
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal fun isOctopusEnabled(s: KeyStroke, editor: Editor): Boolean {
 | 
					internal fun isOctopusEnabled(s: KeyStroke, editor: Editor): Boolean {
 | 
				
			||||||
  if (!enableOctopus) return false
 | 
					  // CMD line has a different processing mechanizm: the processing actions are registered
 | 
				
			||||||
  when {
 | 
					  //   for the input field component. These keys are not dispatched via the octopus handler.
 | 
				
			||||||
    s.keyCode == KeyEvent.VK_ENTER -> return editor.mode in listOf(
 | 
					  if (editor.vim.mode is Mode.CMD_LINE) return false
 | 
				
			||||||
      CommandState.Mode.COMMAND,
 | 
					  when (s.keyCode) {
 | 
				
			||||||
      CommandState.Mode.INSERT,
 | 
					    KeyEvent.VK_ENTER -> return true
 | 
				
			||||||
      CommandState.Mode.VISUAL,
 | 
					    KeyEvent.VK_ESCAPE -> return true
 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    s.keyCode == KeyEvent.VK_ESCAPE -> return editor.mode in listOf(
 | 
					 | 
				
			||||||
      CommandState.Mode.COMMAND,
 | 
					 | 
				
			||||||
      CommandState.Mode.INSERT,
 | 
					 | 
				
			||||||
      CommandState.Mode.VISUAL,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return false
 | 
					  return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Experiment: At the moment, IdeaVim intersects all shortcuts and sends the to [KeyHandler]
 | 
					 | 
				
			||||||
 * However, this doesn't seem to be a good solution as other handlers are overridden by vim.
 | 
					 | 
				
			||||||
 * If this option is enabled, vim will connect to IDE via EditorActionHandler extension point
 | 
					 | 
				
			||||||
 *   what seems to be a way better solution as this is a correct way to override editor actions like enter, right, etc.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
internal val enableOctopus: Boolean
 | 
					 | 
				
			||||||
  get() = injector.globalIjOptions().octopushandler
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,11 +8,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.helper
 | 
					package com.maddyhome.idea.vim.helper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.diagnostic.thisLogger
 | 
				
			||||||
import com.intellij.openapi.editor.Caret
 | 
					import com.intellij.openapi.editor.Caret
 | 
				
			||||||
import com.intellij.openapi.editor.CaretVisualAttributes
 | 
					import com.intellij.openapi.editor.CaretVisualAttributes
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import com.intellij.openapi.editor.ex.EditorEx
 | 
					import com.intellij.openapi.editor.ex.EditorEx
 | 
				
			||||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
 | 
					import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.globalOptions
 | 
					import com.maddyhome.idea.vim.api.globalOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
@@ -79,6 +81,7 @@ private fun Editor.guicursorMode(): GuiCursorMode {
 | 
				
			|||||||
private fun isBlockCursorOverride() = EditorSettingsExternalizable.getInstance().isBlockCursor
 | 
					private fun isBlockCursorOverride() = EditorSettingsExternalizable.getInstance().isBlockCursor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun Editor.updatePrimaryCaretVisualAttributes() {
 | 
					private fun Editor.updatePrimaryCaretVisualAttributes() {
 | 
				
			||||||
 | 
					  if (!VimPlugin.isEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
 | 
				
			||||||
  caretModel.primaryCaret.visualAttributes = AttributesCache.getCaretVisualAttributes(this)
 | 
					  caretModel.primaryCaret.visualAttributes = AttributesCache.getCaretVisualAttributes(this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Make sure the caret is visible as soon as it's set. It might be invisible while blinking
 | 
					  // Make sure the caret is visible as soon as it's set. It might be invisible while blinking
 | 
				
			||||||
@@ -86,6 +89,7 @@ private fun Editor.updatePrimaryCaretVisualAttributes() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun Editor.updateSecondaryCaretsVisualAttributes() {
 | 
					private fun Editor.updateSecondaryCaretsVisualAttributes() {
 | 
				
			||||||
 | 
					  if (!VimPlugin.isEnabled()) thisLogger().error("The caret attributes should not be updated if the IdeaVim is disabled")
 | 
				
			||||||
  // IntelliJ simulates visual block with multiple carets with selections. Do our best to hide them
 | 
					  // IntelliJ simulates visual block with multiple carets with selections. Do our best to hide them
 | 
				
			||||||
  val attributes = if (this.vim.inBlockSelection) HIDDEN else AttributesCache.getCaretVisualAttributes(this)
 | 
					  val attributes = if (this.vim.inBlockSelection) HIDDEN else AttributesCache.getCaretVisualAttributes(this)
 | 
				
			||||||
  this.caretModel.allCarets.forEach {
 | 
					  this.caretModel.allCarets.forEach {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -335,7 +335,7 @@ public class EditorHelper {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
 | 
					    final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
 | 
				
			||||||
    @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
					    @NotNull final VimEditor editor1 = new IjVimEditor(editor);
 | 
				
			||||||
    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
 | 
					    final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
 | 
				
			||||||
    final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
 | 
					    final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
 | 
					    // For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@ import com.maddyhome.idea.vim.api.injector
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.normalizeVisualColumn
 | 
					import com.maddyhome.idea.vim.api.normalizeVisualColumn
 | 
				
			||||||
import com.maddyhome.idea.vim.api.options
 | 
					import com.maddyhome.idea.vim.api.options
 | 
				
			||||||
import com.maddyhome.idea.vim.command.CommandFlags
 | 
					import com.maddyhome.idea.vim.command.CommandFlags
 | 
				
			||||||
import com.maddyhome.idea.vim.state.VimStateMachine
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenHeight
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenHeight
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenWidth
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenWidth
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getNonNormalizedVisualLineAtBottomOfScreen
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.getNonNormalizedVisualLineAtBottomOfScreen
 | 
				
			||||||
@@ -29,6 +28,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
 | 
					import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.VimStateMachine
 | 
				
			||||||
import kotlin.math.max
 | 
					import kotlin.math.max
 | 
				
			||||||
import kotlin.math.min
 | 
					import kotlin.math.min
 | 
				
			||||||
import kotlin.math.roundToInt
 | 
					import kotlin.math.roundToInt
 | 
				
			||||||
@@ -56,7 +56,7 @@ internal object ScrollViewHelper {
 | 
				
			|||||||
    // that this needs to be replaced as a more or less dumb line for line rewrite.
 | 
					    // that this needs to be replaced as a more or less dumb line for line rewrite.
 | 
				
			||||||
    val topLine = getVisualLineAtTopOfScreen(editor)
 | 
					    val topLine = getVisualLineAtTopOfScreen(editor)
 | 
				
			||||||
    val bottomLine = getVisualLineAtBottomOfScreen(editor)
 | 
					    val bottomLine = getVisualLineAtBottomOfScreen(editor)
 | 
				
			||||||
    val lastLine = vimEditor.getVisualLineCount() - 1
 | 
					    val lastLine = vimEditor.getVisualLineCount() + editor.settings.additionalLinesCount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
 | 
					    // We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
 | 
				
			||||||
    val scrollOffset = injector.options(vimEditor).scrolloff
 | 
					    val scrollOffset = injector.options(vimEditor).scrolloff
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@ package com.maddyhome.idea.vim.helper
 | 
				
			|||||||
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.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.intellij.openapi.fileEditor.impl.text.TextEditorProvider
 | 
				
			||||||
@@ -19,8 +18,6 @@ import com.maddyhome.idea.vim.VimPlugin
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.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.common.ChangesListener
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.group.IjOptions
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
 | 
					import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					import com.maddyhome.idea.vim.newapi.ij
 | 
				
			||||||
@@ -33,15 +30,6 @@ import com.maddyhome.idea.vim.undo.UndoRedoBase
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
internal class UndoRedoHelper : UndoRedoBase() {
 | 
					internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			||||||
  init {
 | 
					 | 
				
			||||||
    fun onOldUndoChanged() {
 | 
					 | 
				
			||||||
      UndoManagerImpl.ourNeverAskUser = !injector.globalIjOptions().oldundo
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    injector.optionGroup.addGlobalOptionChangeListener(IjOptions.oldundo, ::onOldUndoChanged)
 | 
					 | 
				
			||||||
    onOldUndoChanged()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun undo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val ijContext = context.context as DataContext
 | 
					    val ijContext = context.context as DataContext
 | 
				
			||||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
					    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
				
			||||||
@@ -55,8 +43,13 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
        SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
 | 
					        SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
 | 
				
			||||||
        restoreVisualMode(editor)
 | 
					        restoreVisualMode(editor)
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) })
 | 
					        // TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
 | 
				
			||||||
 | 
					        undoManager.undo(fileEditor)
 | 
				
			||||||
 | 
					        if (hasSelection(editor) && undoManager.isUndoAvailable(fileEditor)) {
 | 
				
			||||||
 | 
					          undoManager.undo(fileEditor) // execute one more time if the previous undo just restored selection
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        // remove selection
 | 
				
			||||||
        editor.carets().forEach {
 | 
					        editor.carets().forEach {
 | 
				
			||||||
          val ijCaret = it.ij
 | 
					          val ijCaret = it.ij
 | 
				
			||||||
          val hasSelection = ijCaret.hasSelection()
 | 
					          val hasSelection = ijCaret.hasSelection()
 | 
				
			||||||
@@ -77,6 +70,10 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
    return false
 | 
					    return false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun hasSelection(editor: VimEditor): Boolean {
 | 
				
			||||||
 | 
					    return editor.primaryCaret().ij.hasSelection()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val ijContext = context.context as DataContext
 | 
					    val ijContext = context.context as DataContext
 | 
				
			||||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
					    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
				
			||||||
@@ -87,7 +84,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
        SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
 | 
					        SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
 | 
				
			||||||
        restoreVisualMode(editor)
 | 
					        restoreVisualMode(editor)
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) })
 | 
					        undoManager.redo(fileEditor)
 | 
				
			||||||
        CommandProcessor.getInstance().runUndoTransparentAction {
 | 
					        CommandProcessor.getInstance().runUndoTransparentAction {
 | 
				
			||||||
          editor.carets().forEach { it.ij.removeSelection() }
 | 
					          editor.carets().forEach { it.ij.removeSelection() }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -97,30 +94,6 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
    return false
 | 
					    return false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun performUntilFileChanges(editor: VimEditor?, check: () -> Boolean, action: Runnable) {
 | 
					 | 
				
			||||||
    if (editor == null) return
 | 
					 | 
				
			||||||
    val vimDocument = editor.document
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val changeListener = object : ChangesListener {
 | 
					 | 
				
			||||||
      var hasChanged = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      override fun documentChanged(change: ChangesListener.Change) {
 | 
					 | 
				
			||||||
        hasChanged = true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val oldPath = editor.getPath()
 | 
					 | 
				
			||||||
    vimDocument.addChangeListener(changeListener)
 | 
					 | 
				
			||||||
    while (check() && !changeListener.hasChanged && !ifFilePathChanged(editor, oldPath)) {
 | 
					 | 
				
			||||||
      action.run()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    vimDocument.removeChangeListener(changeListener)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun ifFilePathChanged(editor: VimEditor, oldPath: String?): Boolean {
 | 
					 | 
				
			||||||
    return editor.getPath() != oldPath
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun restoreVisualMode(editor: VimEditor) {
 | 
					  private fun restoreVisualMode(editor: VimEditor) {
 | 
				
			||||||
    if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
 | 
					    if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
 | 
				
			||||||
      val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
 | 
					      val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ import com.intellij.openapi.util.Key
 | 
				
			|||||||
import com.intellij.openapi.util.removeUserData
 | 
					import com.intellij.openapi.util.removeUserData
 | 
				
			||||||
import com.intellij.openapi.vfs.VirtualFile
 | 
					import com.intellij.openapi.vfs.VirtualFile
 | 
				
			||||||
import com.intellij.util.ExceptionUtil
 | 
					import com.intellij.util.ExceptionUtil
 | 
				
			||||||
import com.jetbrains.rd.util.lifetime.intersect
 | 
					import com.jetbrains.rd.util.lifetime.Lifetime
 | 
				
			||||||
import com.maddyhome.idea.vim.EventFacade
 | 
					import com.maddyhome.idea.vim.EventFacade
 | 
				
			||||||
import com.maddyhome.idea.vim.KeyHandler
 | 
					import com.maddyhome.idea.vim.KeyHandler
 | 
				
			||||||
import com.maddyhome.idea.vim.VimKeyListener
 | 
					import com.maddyhome.idea.vim.VimKeyListener
 | 
				
			||||||
@@ -88,6 +88,8 @@ 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.newapi.IjVimEditor
 | 
					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.state.VimStateMachine
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.inSelectMode
 | 
					import com.maddyhome.idea.vim.state.mode.inSelectMode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.mode
 | 
					import com.maddyhome.idea.vim.state.mode.mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.selectionType
 | 
					import com.maddyhome.idea.vim.state.mode.selectionType
 | 
				
			||||||
@@ -210,7 +212,8 @@ internal object VimListenerManager {
 | 
				
			|||||||
    fun add(editor: Editor, openingEditor: VimEditor, scenario: LocalOptionInitialisationScenario) {
 | 
					    fun add(editor: Editor, openingEditor: VimEditor, scenario: LocalOptionInitialisationScenario) {
 | 
				
			||||||
      val pluginLifetime = VimPlugin.getInstance().createLifetime()
 | 
					      val pluginLifetime = VimPlugin.getInstance().createLifetime()
 | 
				
			||||||
      val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
 | 
					      val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
 | 
				
			||||||
      val disposable = editorLifetime.intersect(pluginLifetime).createNestedDisposable("MyLifetimedDisposable")
 | 
					      val disposable =
 | 
				
			||||||
 | 
					        Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      editor.contentComponent.addKeyListener(VimKeyListener)
 | 
					      editor.contentComponent.addKeyListener(VimKeyListener)
 | 
				
			||||||
      Disposer.register(disposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
 | 
					      Disposer.register(disposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
 | 
				
			||||||
@@ -265,6 +268,16 @@ internal object VimListenerManager {
 | 
				
			|||||||
  class VimFileEditorManagerListener : FileEditorManagerListener {
 | 
					  class VimFileEditorManagerListener : FileEditorManagerListener {
 | 
				
			||||||
    override fun selectionChanged(event: FileEditorManagerEvent) {
 | 
					    override fun selectionChanged(event: FileEditorManagerEvent) {
 | 
				
			||||||
      if (!VimPlugin.isEnabled()) return
 | 
					      if (!VimPlugin.isEnabled()) return
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      val newEditor = event.newEditor
 | 
				
			||||||
 | 
					      if (newEditor is TextEditor) {
 | 
				
			||||||
 | 
					        val editor = newEditor.editor
 | 
				
			||||||
 | 
					        if (editor.isInsertMode) {
 | 
				
			||||||
 | 
					          VimStateMachine.getInstance(editor).mode = Mode.NORMAL()
 | 
				
			||||||
 | 
					          KeyHandler.getInstance().reset(editor.vim)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      MotionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
					      MotionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      FileGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
					      FileGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
      SearchGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
					      SearchGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,10 @@ package com.maddyhome.idea.vim.newapi
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimActionsInitiator
 | 
					import com.maddyhome.idea.vim.api.VimActionsInitiator
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.ActionBeanClass
 | 
					import com.maddyhome.idea.vim.handler.ActionBeanClass
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
 | 
					import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated(message = "Please use CommandOrMotion annotation")
 | 
				
			||||||
 | 
					@ApiStatus.ScheduledForRemoval(inVersion = "2.9.0")
 | 
				
			||||||
internal class IjVimActionsInitiator(val bean: ActionBeanClass) : VimActionsInitiator {
 | 
					internal class IjVimActionsInitiator(val bean: ActionBeanClass) : VimActionsInitiator {
 | 
				
			||||||
  override fun getInstance(): EditorActionHandlerBase = bean.instance
 | 
					  override fun getInstance(): EditorActionHandlerBase = bean.instance
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ import com.maddyhome.idea.vim.api.VimCaret
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.VimCaretBase
 | 
					import com.maddyhome.idea.vim.api.VimCaretBase
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
					import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					 | 
				
			||||||
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
 | 
				
			||||||
@@ -39,12 +38,15 @@ import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
 | 
				
			|||||||
import com.maddyhome.idea.vim.helper.vimLine
 | 
					import com.maddyhome.idea.vim.helper.vimLine
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
 | 
					import com.maddyhome.idea.vim.helper.vimSelectionStart
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.vimSelectionStartClear
 | 
					import com.maddyhome.idea.vim.helper.vimSelectionStartClear
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
 | 
					internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init {
 | 
					  init {
 | 
				
			||||||
    Disposer.register(caret) {
 | 
					    if (caret.isValid) {
 | 
				
			||||||
      (registerStorage as CaretRegisterStorageBase).clearListener()
 | 
					      Disposer.register(caret) {
 | 
				
			||||||
 | 
					        (registerStorage as CaretRegisterStorageBase).clearListener()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,11 @@ import java.lang.System.identityHashCode
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@ApiStatus.Internal
 | 
					@ApiStatus.Internal
 | 
				
			||||||
internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
 | 
					internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    // For cases where Editor does not have a project (for some reason)
 | 
				
			||||||
 | 
					    // It's something IJ Platform related and stored here because of this reason
 | 
				
			||||||
 | 
					    const val DEFAULT_PROJECT_ID = "no project" 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // All the editor actions should be performed with top level editor!!!
 | 
					  // All the editor actions should be performed with top level editor!!!
 | 
				
			||||||
  // Be careful: all the EditorActionHandler implementation should correctly process InjectedEditors
 | 
					  // Be careful: all the EditorActionHandler implementation should correctly process InjectedEditors
 | 
				
			||||||
@@ -369,6 +374,8 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
 | 
				
			|||||||
    return EditorHelper.getVirtualFile(editor)?.getUrl()?.let { VirtualFileManager.extractProtocol(it) }
 | 
					    return EditorHelper.getVirtualFile(editor)?.getUrl()?.let { VirtualFileManager.extractProtocol(it) }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override val projectId = editor.project?.basePath ?: DEFAULT_PROJECT_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visualPositionToOffset(position: VimVisualPosition): Offset {
 | 
					  override fun visualPositionToOffset(position: VimVisualPosition): Offset {
 | 
				
			||||||
    return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight)).offset
 | 
					    return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight)).offset
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,10 @@ internal class IjVimLogger(private val logger: Logger) : VimLogger {
 | 
				
			|||||||
    logger.error(message)
 | 
					    logger.error(message)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun error(message: String, e: Throwable) {
 | 
				
			||||||
 | 
					    logger.error(message, e)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun info(message: String) {
 | 
					  override fun info(message: String) {
 | 
				
			||||||
    logger.info(message)
 | 
					    logger.info(message)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ import com.intellij.openapi.diagnostic.logger
 | 
				
			|||||||
import com.intellij.openapi.editor.Document
 | 
					import com.intellij.openapi.editor.Document
 | 
				
			||||||
import com.intellij.openapi.editor.toolbar.floating.AbstractFloatingToolbarProvider
 | 
					import com.intellij.openapi.editor.toolbar.floating.AbstractFloatingToolbarProvider
 | 
				
			||||||
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
 | 
					import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
 | 
				
			||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
					 | 
				
			||||||
import com.intellij.openapi.project.DumbAwareAction
 | 
					import com.intellij.openapi.project.DumbAwareAction
 | 
				
			||||||
import com.intellij.openapi.util.Disposer
 | 
					import com.intellij.openapi.util.Disposer
 | 
				
			||||||
import com.intellij.openapi.util.io.FileUtil
 | 
					import com.intellij.openapi.util.io.FileUtil
 | 
				
			||||||
@@ -31,10 +30,11 @@ import com.maddyhome.idea.vim.newapi.vim
 | 
				
			|||||||
import com.maddyhome.idea.vim.troubleshooting.Troubleshooter
 | 
					import com.maddyhome.idea.vim.troubleshooting.Troubleshooter
 | 
				
			||||||
import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP
 | 
					import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
 | 
					import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.services.VimRcService
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.services.VimRcService.VIMRC_FILE_NAME
 | 
					import com.maddyhome.idea.vim.vimscript.services.VimRcService.VIMRC_FILE_NAME
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc
 | 
					import com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc
 | 
				
			||||||
import org.jetbrains.annotations.TestOnly
 | 
					import org.jetbrains.annotations.TestOnly
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.readText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This file contains a "reload ~/.ideavimrc file" action functionality.
 | 
					 * This file contains a "reload ~/.ideavimrc file" action functionality.
 | 
				
			||||||
@@ -67,8 +67,7 @@ internal object VimRcFileState : VimrcFileState {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun saveFileState(filePath: String) {
 | 
					  override fun saveFileState(filePath: String) {
 | 
				
			||||||
    val vimRcFile = VimRcService.findIdeaVimRc()
 | 
					    val ideaVimRcText = Path.of(filePath).let {
 | 
				
			||||||
    val ideaVimRcText = vimRcFile?.let {
 | 
					 | 
				
			||||||
      kotlin.runCatching { it.readText() }
 | 
					      kotlin.runCatching { it.readText() }
 | 
				
			||||||
        .onFailure { LOG.error(it) }
 | 
					        .onFailure { LOG.error(it) }
 | 
				
			||||||
        .getOrNull()
 | 
					        .getOrNull()
 | 
				
			||||||
@@ -149,7 +148,6 @@ internal class ReloadVimRc : DumbAwareAction() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun actionPerformed(e: AnActionEvent) {
 | 
					  override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
    val editor = e.getData(PlatformDataKeys.EDITOR) ?: return
 | 
					    val editor = e.getData(PlatformDataKeys.EDITOR) ?: return
 | 
				
			||||||
    FileDocumentManager.getInstance().saveDocumentAsIs(editor.document)
 | 
					 | 
				
			||||||
    injector.keyGroup.removeKeyMapping(MappingOwner.IdeaVim.InitScript)
 | 
					    injector.keyGroup.removeKeyMapping(MappingOwner.IdeaVim.InitScript)
 | 
				
			||||||
    Troubleshooter.instance.removeByType("old-action-notation-in-mappings")
 | 
					    Troubleshooter.instance.removeByType("old-action-notation-in-mappings")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.wm.WindowManager
 | 
				
			|||||||
import com.intellij.openapi.wm.impl.status.EditorBasedWidget
 | 
					import com.intellij.openapi.wm.impl.status.EditorBasedWidget
 | 
				
			||||||
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
 | 
					import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
 | 
				
			||||||
import com.intellij.util.Consumer
 | 
					import com.intellij.util.Consumer
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.globalOptions
 | 
					import com.maddyhome.idea.vim.api.globalOptions
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.EngineStringHelper
 | 
					import com.maddyhome.idea.vim.helper.EngineStringHelper
 | 
				
			||||||
@@ -86,7 +87,10 @@ internal class ShowCmdStatusBarWidgetFactory : StatusBarWidgetFactory/*, LightEd
 | 
				
			|||||||
    // Nothing
 | 
					    // Nothing
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun isAvailable(project: Project): Boolean = injector.globalOptions().showcmd
 | 
					  override fun isAvailable(project: Project): Boolean {
 | 
				
			||||||
 | 
					    VimPlugin.getInstance()
 | 
				
			||||||
 | 
					    return injector.globalOptions().showcmd
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun createWidget(project: Project): StatusBarWidget = Widget(project)
 | 
					  override fun createWidget(project: Project): StatusBarWidget = Widget(project)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -371,7 +371,11 @@ public class ExTextField extends JTextField {
 | 
				
			|||||||
  void toggleInsertReplace() {
 | 
					  void toggleInsertReplace() {
 | 
				
			||||||
    ExDocument doc = (ExDocument)getDocument();
 | 
					    ExDocument doc = (ExDocument)getDocument();
 | 
				
			||||||
    doc.toggleInsertReplace();
 | 
					    doc.toggleInsertReplace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Hide/show the caret so its new shape is immediately visible
 | 
				
			||||||
 | 
					    caret.setVisible(false);
 | 
				
			||||||
    resetCaret();
 | 
					    resetCaret();
 | 
				
			||||||
 | 
					    caret.setVisible(true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void resetCaret() {
 | 
					  private void resetCaret() {
 | 
				
			||||||
@@ -414,20 +418,15 @@ public class ExTextField extends JTextField {
 | 
				
			|||||||
    private boolean hasFocus;
 | 
					    private boolean hasFocus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setAttributes(GuiCursorAttributes attributes) {
 | 
					    public void setAttributes(GuiCursorAttributes attributes) {
 | 
				
			||||||
      final boolean active = isActive();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Hide the currently visible caret
 | 
					      // Note: do not call anything that causes a layout in this method! E.g. setVisible. This method is used as a
 | 
				
			||||||
      if (isVisible()) {
 | 
					      // callback whenever the caret moves, and causing a layout at this point can cause issues such as an infinite
 | 
				
			||||||
        setVisible(false);
 | 
					      // loop in the layout algorithm with multi-width characters such as emoji or non-Latin characters (I don't know
 | 
				
			||||||
      }
 | 
					      // why the layout algorithm gets stuck, but we can easily avoid it)
 | 
				
			||||||
 | 
					      // See VIM-2562
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      mode = attributes.getType();
 | 
					      mode = attributes.getType();
 | 
				
			||||||
      thickness = mode == GuiCursorType.BLOCK ? 100 : attributes.getThickness();
 | 
					      thickness = mode == GuiCursorType.BLOCK ? 100 : attributes.getThickness();
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Make sure the caret is visible, but only if we're active, otherwise we'll kick off the flasher timer unnecessarily
 | 
					 | 
				
			||||||
      if (active) {
 | 
					 | 
				
			||||||
        setVisible(true);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,8 @@ package com.maddyhome.idea.vim.vimscript
 | 
				
			|||||||
import com.intellij.openapi.actionSystem.DataContext
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
import com.intellij.openapi.components.Service
 | 
					import com.intellij.openapi.components.Service
 | 
				
			||||||
import com.intellij.openapi.diagnostic.logger
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
				
			||||||
 | 
					import com.intellij.openapi.vfs.VirtualFileManager
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
@@ -18,6 +20,7 @@ import com.maddyhome.idea.vim.api.VimScriptExecutorBase
 | 
				
			|||||||
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.ex.FinishException
 | 
					import com.maddyhome.idea.vim.ex.FinishException
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
 | 
				
			||||||
import com.maddyhome.idea.vim.history.HistoryConstants
 | 
					import com.maddyhome.idea.vim.history.HistoryConstants
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
 | 
					import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
 | 
				
			||||||
@@ -34,66 +37,94 @@ import java.io.IOException
 | 
				
			|||||||
internal class Executor : VimScriptExecutorBase() {
 | 
					internal class Executor : VimScriptExecutorBase() {
 | 
				
			||||||
  private val logger = logger<Executor>()
 | 
					  private val logger = logger<Executor>()
 | 
				
			||||||
  override var executingVimscript = false
 | 
					  override var executingVimscript = false
 | 
				
			||||||
 | 
					  override var executingIdeaVimRcConfiguration = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Throws(ExException::class)
 | 
					  @Throws(ExException::class)
 | 
				
			||||||
  override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
 | 
					  override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
 | 
				
			||||||
    var finalResult: ExecutionResult = ExecutionResult.Success
 | 
					    try {
 | 
				
			||||||
 | 
					      injector.vimscriptExecutor.executingVimscript = true
 | 
				
			||||||
 | 
					      var finalResult: ExecutionResult = ExecutionResult.Success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val myScript = VimscriptParser.parse(script)
 | 
					      val myScript = VimscriptParser.parse(script)
 | 
				
			||||||
    myScript.units.forEach { it.vimContext = vimContext ?: myScript }
 | 
					      myScript.units.forEach { it.vimContext = vimContext ?: myScript }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (unit in myScript.units) {
 | 
					      for (unit in myScript.units) {
 | 
				
			||||||
      try {
 | 
					        try {
 | 
				
			||||||
        val result = unit.execute(editor, context)
 | 
					          val result = unit.execute(editor, context)
 | 
				
			||||||
        if (result is ExecutionResult.Error) {
 | 
					          if (result is ExecutionResult.Error) {
 | 
				
			||||||
 | 
					            finalResult = ExecutionResult.Error
 | 
				
			||||||
 | 
					            if (indicateErrors) {
 | 
				
			||||||
 | 
					              VimPlugin.indicateError()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } catch (e: ExException) {
 | 
				
			||||||
 | 
					          if (e is FinishException) {
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          finalResult = ExecutionResult.Error
 | 
					          finalResult = ExecutionResult.Error
 | 
				
			||||||
          if (indicateErrors) {
 | 
					          if (indicateErrors) {
 | 
				
			||||||
 | 
					            VimPlugin.showMessage(e.message)
 | 
				
			||||||
 | 
					            VimPlugin.indicateError()
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            logger.warn("Failed while executing $unit. " + e.message)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } catch (e: NotImplementedError) {
 | 
				
			||||||
 | 
					          if (indicateErrors) {
 | 
				
			||||||
 | 
					            VimPlugin.showMessage("Not implemented yet :(")
 | 
				
			||||||
            VimPlugin.indicateError()
 | 
					            VimPlugin.indicateError()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        } catch (e: Exception) {
 | 
				
			||||||
      } catch (e: ExException) {
 | 
					          logger.warn("Caught: ${e.message}")
 | 
				
			||||||
        if (e is FinishException) {
 | 
					          logger.warn(e.stackTrace.toString())
 | 
				
			||||||
          break
 | 
					          if (injector.application.isUnitTest()) {
 | 
				
			||||||
        }
 | 
					            throw e
 | 
				
			||||||
        finalResult = ExecutionResult.Error
 | 
					          }
 | 
				
			||||||
        if (indicateErrors) {
 | 
					 | 
				
			||||||
          VimPlugin.showMessage(e.message)
 | 
					 | 
				
			||||||
          VimPlugin.indicateError()
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          logger.warn("Failed while executing $unit. " + e.message)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } catch (e: NotImplementedError) {
 | 
					 | 
				
			||||||
        if (indicateErrors) {
 | 
					 | 
				
			||||||
          VimPlugin.showMessage("Not implemented yet :(")
 | 
					 | 
				
			||||||
          VimPlugin.indicateError()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } catch (e: Exception) {
 | 
					 | 
				
			||||||
        logger.warn("Caught: ${e.message}")
 | 
					 | 
				
			||||||
        logger.warn(e.stackTrace.toString())
 | 
					 | 
				
			||||||
        if (injector.application.isUnitTest()) {
 | 
					 | 
				
			||||||
          throw e
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!skipHistory) {
 | 
					      if (!skipHistory) {
 | 
				
			||||||
      VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
 | 
					        VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
 | 
				
			||||||
      if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
 | 
					        if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
 | 
				
			||||||
        VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, script)
 | 
					          VimPlugin.getRegister().storeTextSpecial(LAST_COMMAND_REGISTER, script)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      return finalResult
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      injector.vimscriptExecutor.executingVimscript = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Initialize any extensions that were enabled during execution of this vimscript
 | 
				
			||||||
 | 
					      // See the doc of this function for details
 | 
				
			||||||
 | 
					      VimExtensionRegistrar.enableDelayedExtensions()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return finalResult
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun executeFile(file: File, editor: VimEditor, indicateErrors: Boolean) {
 | 
					  override fun executeFile(file: File, editor: VimEditor, fileIsIdeaVimRcConfig: Boolean, indicateErrors: Boolean) {
 | 
				
			||||||
    val context = DataContext.EMPTY_CONTEXT.vim
 | 
					    val context = DataContext.EMPTY_CONTEXT.vim
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
 | 
					      if (fileIsIdeaVimRcConfig) {
 | 
				
			||||||
 | 
					        injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      ensureFileIsSaved(file)
 | 
				
			||||||
      execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
 | 
					      execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
 | 
				
			||||||
    } catch (ignored: IOException) {
 | 
					    } catch (ignored: IOException) {
 | 
				
			||||||
      LOG.error(ignored)
 | 
					      LOG.error(ignored)
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      if (fileIsIdeaVimRcConfig) {
 | 
				
			||||||
 | 
					        injector.vimrcFileState.saveFileState(file.absolutePath)
 | 
				
			||||||
 | 
					        injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun ensureFileIsSaved(file: File) {
 | 
				
			||||||
 | 
					    val documentManager = FileDocumentManager.getInstance()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VirtualFileManager.getInstance().findFileByNioPath(file.toPath())
 | 
				
			||||||
 | 
					      ?.let(documentManager::getCachedDocument)
 | 
				
			||||||
 | 
					      ?.takeIf(documentManager::isDocumentUnsaved)
 | 
				
			||||||
 | 
					      ?.let(documentManager::saveDocumentAsIs)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Throws(ExException::class)
 | 
					  @Throws(ExException::class)
 | 
				
			||||||
  override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val reg = VimPlugin.getRegister().getRegister(':') ?: return false
 | 
					    val reg = VimPlugin.getRegister().getRegister(':') ?: return false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.vimscript.model.functions.handlers
 | 
					package com.maddyhome.idea.vim.vimscript.model.functions.handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.SystemInfoRt
 | 
				
			||||||
 | 
					import com.intellij.util.system.CpuArch
 | 
				
			||||||
import com.intellij.vim.annotations.VimscriptFunction
 | 
					import com.intellij.vim.annotations.VimscriptFunction
 | 
				
			||||||
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
 | 
				
			||||||
@@ -23,7 +25,7 @@ internal class HasFunctionHandler : FunctionHandler() {
 | 
				
			|||||||
  override val minimumNumberOfArguments = 1
 | 
					  override val minimumNumberOfArguments = 1
 | 
				
			||||||
  override val maximumNumberOfArguments = 2
 | 
					  override val maximumNumberOfArguments = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private val supportedFeatures = setOf("ide")
 | 
					  private val supportedFeatures = Features.discover()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun doFunction(
 | 
					  override fun doFunction(
 | 
				
			||||||
    argumentValues: List<Expression>,
 | 
					    argumentValues: List<Expression>,
 | 
				
			||||||
@@ -41,4 +43,38 @@ internal class HasFunctionHandler : FunctionHandler() {
 | 
				
			|||||||
      VimInt.ZERO
 | 
					      VimInt.ZERO
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private object Features {
 | 
				
			||||||
 | 
					    fun discover(): Set<String> {
 | 
				
			||||||
 | 
					      val result = mutableSetOf("ide")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      collectOperatingSystemType(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return result
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun collectOperatingSystemType(result: MutableSet<String>) {
 | 
				
			||||||
 | 
					      if (SystemInfoRt.isWindows) {
 | 
				
			||||||
 | 
					        result.add("win32")
 | 
				
			||||||
 | 
					        if (CpuArch.CURRENT.width == 64) {
 | 
				
			||||||
 | 
					          result.add("win64")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else if (SystemInfoRt.isLinux) {
 | 
				
			||||||
 | 
					        result.add("linux")
 | 
				
			||||||
 | 
					      } else if (SystemInfoRt.isMac) {
 | 
				
			||||||
 | 
					        result.add("mac")
 | 
				
			||||||
 | 
					        result.add("macunix")
 | 
				
			||||||
 | 
					        result.add("osx")
 | 
				
			||||||
 | 
					        result.add("osxdarwin")
 | 
				
			||||||
 | 
					      } else if (SystemInfoRt.isFreeBSD) {
 | 
				
			||||||
 | 
					        result.add("bsd")
 | 
				
			||||||
 | 
					      } else if (SystemInfoRt.isSolaris) {
 | 
				
			||||||
 | 
					        result.add("sun")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (SystemInfoRt.isUnix) {
 | 
				
			||||||
 | 
					        result.add("unix")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,49 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
 | 
					 | 
				
			||||||
 * Copyright (C) 2003-2021 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.vimscript.model.functions.handlers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.intellij.refactoring.rename.inplace.InplaceRefactoring
 | 
					 | 
				
			||||||
import com.intellij.vim.annotations.VimscriptFunction
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.ij
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.VimLContext
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@VimscriptFunction(name = "renaming")
 | 
					 | 
				
			||||||
internal class RenamingFunctionHandler : FunctionHandler() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override val minimumNumberOfArguments = 0
 | 
					 | 
				
			||||||
  override val maximumNumberOfArguments = 0
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  override fun doFunction(
 | 
					 | 
				
			||||||
    argumentValues: List<Expression>,
 | 
					 | 
				
			||||||
    editor: VimEditor,
 | 
					 | 
				
			||||||
    context: ExecutionContext,
 | 
					 | 
				
			||||||
    vimContext: VimLContext,
 | 
					 | 
				
			||||||
  ): VimDataType {
 | 
					 | 
				
			||||||
    return if (InplaceRefactoring.getActiveInplaceRenamer(editor.ij) == null)
 | 
					 | 
				
			||||||
      VimInt.ZERO
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      VimInt.ONE
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -11,4 +11,11 @@
 | 
				
			|||||||
    <listener class="com.maddyhome.idea.vim.listener.RiderActionListener"
 | 
					    <listener class="com.maddyhome.idea.vim.listener.RiderActionListener"
 | 
				
			||||||
              topic="com.intellij.openapi.actionSystem.ex.AnActionListener"/>
 | 
					              topic="com.intellij.openapi.actionSystem.ex.AnActionListener"/>
 | 
				
			||||||
  </projectListeners>
 | 
					  </projectListeners>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <extensions defaultExtensionNs="com.intellij">
 | 
				
			||||||
 | 
					    <editorActionHandler action="EditorEscape"
 | 
				
			||||||
 | 
					                         implementationClass="com.maddyhome.idea.vim.handler.VimEscForRiderHandler"
 | 
				
			||||||
 | 
					                         id="ideavim-rider-esc"
 | 
				
			||||||
 | 
					                         order="first, before idea.only.escape"/>
 | 
				
			||||||
 | 
					  </extensions>
 | 
				
			||||||
</idea-plugin>
 | 
					</idea-plugin>
 | 
				
			||||||
@@ -24,6 +24,5 @@
 | 
				
			|||||||
    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/>
 | 
					    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/>
 | 
				
			||||||
    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.SplitFunctionHandler" name="split"/>
 | 
					    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.SplitFunctionHandler" name="split"/>
 | 
				
			||||||
    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.GetFunctionHandler" name="get"/>
 | 
					    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.GetFunctionHandler" name="get"/>
 | 
				
			||||||
    <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.RenamingFunctionHandler" name="renaming"/>
 | 
					 | 
				
			||||||
  </extensions>
 | 
					  </extensions>
 | 
				
			||||||
</idea-plugin>
 | 
					</idea-plugin>
 | 
				
			||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
  <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
 | 
					  <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
 | 
				
			||||||
  <!-- Check for [Version Update] tag in YouTrack as well -->
 | 
					  <!-- Check for [Version Update] tag in YouTrack as well -->
 | 
				
			||||||
  <!-- Also, please update the value in build.gradle.kts file-->
 | 
					  <!-- Also, please update the value in build.gradle.kts file-->
 | 
				
			||||||
  <idea-version since-build="231.7515.13"/>
 | 
					  <idea-version since-build="232"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
 | 
					  <!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
 | 
				
			||||||
  <depends>com.intellij.modules.platform</depends>
 | 
					  <depends>com.intellij.modules.platform</depends>
 | 
				
			||||||
@@ -70,10 +70,12 @@
 | 
				
			|||||||
         which (at least for 2020.1) has some long running activities that block other startup extensions. None of the
 | 
					         which (at least for 2020.1) has some long running activities that block other startup extensions. None of the
 | 
				
			||||||
         core platform activities have IDs, so we can't use "before ID". We have to use "first" -->
 | 
					         core platform activities have IDs, so we can't use "before ID". We have to use "first" -->
 | 
				
			||||||
    <postStartupActivity implementation="com.maddyhome.idea.vim.PluginStartup" order="first"/>
 | 
					    <postStartupActivity implementation="com.maddyhome.idea.vim.PluginStartup" order="first"/>
 | 
				
			||||||
 | 
					    <postStartupActivity implementation="com.maddyhome.idea.vim.handler.EditorHandlersChainLogger"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <editorFloatingToolbarProvider implementation="com.maddyhome.idea.vim.ui.ReloadFloatingToolbar"/>
 | 
					    <editorFloatingToolbarProvider implementation="com.maddyhome.idea.vim.ui.ReloadFloatingToolbar"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <actionPromoter implementation="com.maddyhome.idea.vim.key.VimActionsPromoter" order="last"/>
 | 
					    <actionPromoter implementation="com.maddyhome.idea.vim.key.VimActionsPromoter" order="last"/>
 | 
				
			||||||
 | 
					    <actionConfigurationCustomizer implementation="com.maddyhome.idea.vim.action.VimActionConfigurationCustomizer"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <spellchecker.bundledDictionaryProvider implementation="com.maddyhome.idea.vim.VimBundledDictionaryProvider"/>
 | 
					    <spellchecker.bundledDictionaryProvider implementation="com.maddyhome.idea.vim.VimBundledDictionaryProvider"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,12 +101,25 @@
 | 
				
			|||||||
<!--    Do not care about red handlers in order. They are necessary for proper ordering, and they'll be resolved when needed -->
 | 
					<!--    Do not care about red handlers in order. They are necessary for proper ordering, and they'll be resolved when needed -->
 | 
				
			||||||
    <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.VimEnterHandler"
 | 
					    <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.VimEnterHandler"
 | 
				
			||||||
                         id="ideavim-enter"
 | 
					                         id="ideavim-enter"
 | 
				
			||||||
                         order="first, before editorEnter, after smart-step-into-enter, after AceHandlerEnter, before jupyterCommandModeEnterKeyHandler, after swift.placeholder.enter"/>
 | 
					                         order="before editorEnter, before rd.client.editor.enter, after smart-step-into-enter, after AceHandlerEnter, after jupyterCommandModeEnterKeyHandler, after swift.placeholder.enter"/>
 | 
				
			||||||
 | 
					    <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.CaretShapeEnterEditorHandler"
 | 
				
			||||||
 | 
					                         id="ideavim-enter-shape"
 | 
				
			||||||
 | 
					                         order="before jupyterCommandModeEnterKeyHandler"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!--    "first" is not defined for this handler as it leads to "unsatisfied ordering exception". Not sure exectly why, but it appears in tests-->
 | 
					<!--    "first" is not defined for this handler as it leads to "unsatisfied ordering exception". Not sure exectly why, but it appears in tests-->
 | 
				
			||||||
    <editorActionHandler action="EditorEscape" implementationClass="com.maddyhome.idea.vim.handler.VimEscHandler"
 | 
					    <editorActionHandler action="EditorEscape" implementationClass="com.maddyhome.idea.vim.handler.VimEscHandler"
 | 
				
			||||||
                         id="ideavim-esc"
 | 
					                         id="ideavim-esc"
 | 
				
			||||||
                         order="after smart-step-into-escape, after AceHandlerEscape, before jupyterCommandModeEscKeyHandler, before templateEscape"/>
 | 
					                         order="after smart-step-into-escape, after AceHandlerEscape, before jupyterCommandModeEscKeyHandler, before templateEscape, before backend.escape"/>
 | 
				
			||||||
 | 
					    <editorActionHandler action="EditorEscape" implementationClass="com.maddyhome.idea.vim.handler.VimEscLoggerHandler"
 | 
				
			||||||
 | 
					                         id="ideavim-esc-logger"
 | 
				
			||||||
 | 
					                         order="first"/>
 | 
				
			||||||
 | 
					    <editorActionHandler action="EditorEnter" implementationClass="com.maddyhome.idea.vim.handler.VimEnterLoggerHandler"
 | 
				
			||||||
 | 
					                         id="ideavim-enter-logger"
 | 
				
			||||||
 | 
					                         order="first"/>
 | 
				
			||||||
 | 
					    <editorActionHandler action="EditorStartNewLine"
 | 
				
			||||||
 | 
					                         implementationClass="com.maddyhome.idea.vim.handler.ShiftEnterDetector"
 | 
				
			||||||
 | 
					                         id="ideavim-shift-enter-detector"
 | 
				
			||||||
 | 
					                         order="first"/>
 | 
				
			||||||
  </extensions>
 | 
					  </extensions>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
 | 
					  <xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
 | 
				
			||||||
@@ -134,5 +149,6 @@
 | 
				
			|||||||
    </group>
 | 
					    </group>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
 | 
					    <action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
 | 
				
			||||||
 | 
					    <action id="VimJumpToSource" class="com.intellij.diff.actions.impl.OpenInEditorAction" />
 | 
				
			||||||
  </actions>
 | 
					  </actions>
 | 
				
			||||||
</idea-plugin>
 | 
					</idea-plugin>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    "actionl[ist]": "com.maddyhome.idea.vim.vimscript.model.commands.ActionListCommand",
 | 
					 | 
				
			||||||
    "b[uffer]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCommand",
 | 
					 | 
				
			||||||
    "ls": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
 | 
					 | 
				
			||||||
    "files": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
 | 
					 | 
				
			||||||
    "buffers": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
 | 
					 | 
				
			||||||
    "!": "com.maddyhome.idea.vim.vimscript.model.commands.CmdFilterCommand",
 | 
					 | 
				
			||||||
    "g[lobal]": "com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand",
 | 
					 | 
				
			||||||
    "v[global]": "com.maddyhome.idea.vim.vimscript.model.commands.GlobalCommand",
 | 
					 | 
				
			||||||
    "h[elp]": "com.maddyhome.idea.vim.vimscript.model.commands.HelpCommand"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,6 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    "line": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LineFunctionHandler",
 | 
					 | 
				
			||||||
    "col": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ColFunctionHandler",
 | 
					 | 
				
			||||||
    "has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
 | 
					 | 
				
			||||||
    "submatch": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -10,11 +10,13 @@ package org.jetbrains.plugins.ideavim
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.maddyhome.idea.vim.RegisterActions.VIM_ACTIONS_EP
 | 
					import com.maddyhome.idea.vim.RegisterActions.VIM_ACTIONS_EP
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
 | 
					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.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.handler.ActionBeanClass
 | 
					import com.maddyhome.idea.vim.handler.ActionBeanClass
 | 
				
			||||||
import com.maddyhome.idea.vim.key.CommandNode
 | 
					import com.maddyhome.idea.vim.key.CommandNode
 | 
				
			||||||
import com.maddyhome.idea.vim.key.CommandPartNode
 | 
					import com.maddyhome.idea.vim.key.CommandPartNode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.impl.OptionTest
 | 
					import org.jetbrains.plugins.ideavim.impl.OptionTest
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.impl.VimOption
 | 
					import org.jetbrains.plugins.ideavim.impl.VimOption
 | 
				
			||||||
import org.junit.jupiter.api.Test
 | 
					import org.junit.jupiter.api.Test
 | 
				
			||||||
@@ -84,6 +86,7 @@ class RegisterActionsTest : VimTestCase() {
 | 
				
			|||||||
    VimOption(TestOptionConstants.whichwrap, doesntAffectTest = true),
 | 
					    VimOption(TestOptionConstants.whichwrap, doesntAffectTest = true),
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
  fun `test unregister extension`() {
 | 
					  fun `test unregister extension`() {
 | 
				
			||||||
 | 
					    if (injector.globalIjOptions().commandOrMotionAnnotation) return
 | 
				
			||||||
    val before = "I ${c}found it in a legendary land"
 | 
					    val before = "I ${c}found it in a legendary land"
 | 
				
			||||||
    val after = "I f${c}ound it in a legendary land"
 | 
					    val after = "I f${c}ound it in a legendary land"
 | 
				
			||||||
    var motionRightAction: ActionBeanClass? = null
 | 
					    var motionRightAction: ActionBeanClass? = null
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,6 @@ class TestIjOptionConstants {
 | 
				
			|||||||
    const val ideamarks = "ideamarks"
 | 
					    const val ideamarks = "ideamarks"
 | 
				
			||||||
    const val idearefactormode = "idearefactormode"
 | 
					    const val idearefactormode = "idearefactormode"
 | 
				
			||||||
    const val ideavimsupport = "ideavimsupport"
 | 
					    const val ideavimsupport = "ideavimsupport"
 | 
				
			||||||
    const val octopushandler = "octopushandler"
 | 
					 | 
				
			||||||
    const val trackactionids = "trackactionids"
 | 
					    const val trackactionids = "trackactionids"
 | 
				
			||||||
    const val unifyjumps = "unifyjumps"
 | 
					    const val unifyjumps = "unifyjumps"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -740,7 +740,6 @@ abstract class VimTestCase {
 | 
				
			|||||||
      when (keyChar) {
 | 
					      when (keyChar) {
 | 
				
			||||||
        is CharType.CharDetected -> {
 | 
					        is CharType.CharDetected -> {
 | 
				
			||||||
          fixture.type(keyChar.char)
 | 
					          fixture.type(keyChar.char)
 | 
				
			||||||
          PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue()
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        is CharType.EditorAction -> {
 | 
					        is CharType.EditorAction -> {
 | 
				
			||||||
@@ -764,6 +763,7 @@ abstract class VimTestCase {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue()
 | 
				
			||||||
      key = inputModel.nextKeyStroke()
 | 
					      key = inputModel.nextKeyStroke()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,10 +10,10 @@ package org.jetbrains.plugins.ideavim.action
 | 
				
			|||||||
import com.intellij.codeInsight.folding.CodeFoldingManager
 | 
					import com.intellij.codeInsight.folding.CodeFoldingManager
 | 
				
			||||||
import com.intellij.codeInsight.folding.impl.FoldingUtil
 | 
					import com.intellij.codeInsight.folding.impl.FoldingUtil
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.ReturnTo
 | 
					import com.maddyhome.idea.vim.state.mode.ReturnTo
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
 | 
					 | 
				
			||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
					import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
					import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
@@ -881,6 +881,18 @@ foobaz
 | 
				
			|||||||
  // VIM-511 |.|
 | 
					  // VIM-511 |.|
 | 
				
			||||||
  @TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
 | 
					  @TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
 | 
					  @VimBehaviorDiffers(originalVimAfter = """
 | 
				
			||||||
 | 
					    class C {
 | 
				
			||||||
 | 
					      C(int i) {
 | 
				
			||||||
 | 
					          i = 3;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      C(int i) {
 | 
				
			||||||
 | 
					          i = 3;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  """, description = """The bracket should be on the new line.
 | 
				
			||||||
 | 
					    |This behaviour was explicitely broken as we migrate to the new handlers and I can't support it"""
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
  fun testAutoCompleteCurlyBraceWithEnterWithinFunctionBody() {
 | 
					  fun testAutoCompleteCurlyBraceWithEnterWithinFunctionBody() {
 | 
				
			||||||
    configureByJavaText(
 | 
					    configureByJavaText(
 | 
				
			||||||
      """
 | 
					      """
 | 
				
			||||||
@@ -896,8 +908,7 @@ foobaz
 | 
				
			|||||||
        i = 3;
 | 
					        i = 3;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    C(int i) {
 | 
					    C(int i) {
 | 
				
			||||||
        i = 3;
 | 
					    i = 3;}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
""",
 | 
					""",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,8 @@ package org.jetbrains.plugins.ideavim.action
 | 
				
			|||||||
import com.google.common.collect.Lists
 | 
					import com.google.common.collect.Lists
 | 
				
			||||||
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.state.mode.Mode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.enableOctopus
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
					import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
					import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
@@ -155,9 +154,7 @@ class MarkTest : VimTestCase() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Currently broken, needs investigation
 | 
					    // Currently broken, needs investigation
 | 
				
			||||||
    // Because of some reason system mark is recreated. As we're on a different column at this moment, this breaks test
 | 
					    // Because of some reason system mark is recreated. As we're on a different column at this moment, this breaks test
 | 
				
			||||||
    if (!enableOctopus) {
 | 
					 | 
				
			||||||
//      assertEquals(2, mark.col)
 | 
					//      assertEquals(2, mark.col)
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // |m|
 | 
					  // |m|
 | 
				
			||||||
@@ -177,9 +174,7 @@ class MarkTest : VimTestCase() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Currently broken, needs investigation
 | 
					    // Currently broken, needs investigation
 | 
				
			||||||
    // Because of some reason system mark is recreated. As we're on a different column at this moment, this breaks test
 | 
					    // Because of some reason system mark is recreated. As we're on a different column at this moment, this breaks test
 | 
				
			||||||
    if (!enableOctopus) {
 | 
					 | 
				
			||||||
//      assertEquals(6, mark.col)
 | 
					//      assertEquals(6, mark.col)
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // |m| |`|
 | 
					  // |m| |`|
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package org.jetbrains.plugins.ideavim.action.change
 | 
					package org.jetbrains.plugins.ideavim.action.change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.idea.TestFor
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
import org.junit.jupiter.api.Test
 | 
					import org.junit.jupiter.api.Test
 | 
				
			||||||
@@ -30,10 +31,12 @@ class UndoActionTest : VimTestCase() {
 | 
				
			|||||||
    kotlin.test.assertFalse(editor.caretModel.primaryCaret.hasSelection())
 | 
					    kotlin.test.assertFalse(editor.caretModel.primaryCaret.hasSelection())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Not yet supported
 | 
					  @Test
 | 
				
			||||||
  fun `undo after selection`() {
 | 
					  @TestFor(issues = ["VIM-696"])
 | 
				
			||||||
    val keys = listOf("v3eld", "u")
 | 
					  fun `test undo after selection`() {
 | 
				
			||||||
    val before = """
 | 
					    if (!optionsIjNoEditor().oldundo) {
 | 
				
			||||||
 | 
					      val keys = listOf("dwv3eld", "u")
 | 
				
			||||||
 | 
					      val before = """
 | 
				
			||||||
                Lorem Ipsum
 | 
					                Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ${c}Lorem ipsum dolor sit amet,
 | 
					                ${c}Lorem ipsum dolor sit amet,
 | 
				
			||||||
@@ -41,9 +44,17 @@ class UndoActionTest : VimTestCase() {
 | 
				
			|||||||
                Sed in orci mauris.
 | 
					                Sed in orci mauris.
 | 
				
			||||||
                Cras id tellus in ex imperdiet egestas.
 | 
					                Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
    """.trimIndent()
 | 
					    """.trimIndent()
 | 
				
			||||||
    val after = before
 | 
					      val after = """
 | 
				
			||||||
    doTest(keys, before, after, Mode.NORMAL())
 | 
					                Lorem Ipsum
 | 
				
			||||||
    kotlin.test.assertFalse(hasSelection())
 | 
					
 | 
				
			||||||
 | 
					                ${c}ipsum dolor sit amet,
 | 
				
			||||||
 | 
					                consectetur adipiscing elit
 | 
				
			||||||
 | 
					                Sed in orci mauris.
 | 
				
			||||||
 | 
					                Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
 | 
					    """.trimIndent()
 | 
				
			||||||
 | 
					      doTest(keys, before, after, Mode.NORMAL())
 | 
				
			||||||
 | 
					      kotlin.test.assertFalse(hasSelection())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
@@ -69,30 +80,31 @@ class UndoActionTest : VimTestCase() {
 | 
				
			|||||||
    kotlin.test.assertFalse(hasSelection())
 | 
					    kotlin.test.assertFalse(hasSelection())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					//  @Test
 | 
				
			||||||
  fun `test cursor movements do not require additional undo`() {
 | 
					//  @TestFor(issues = ["VIM-308"])
 | 
				
			||||||
    if (!optionsIjNoEditor().oldundo) {
 | 
					//  fun `test cursor movements do not require additional undo`() {
 | 
				
			||||||
      val keys = listOf("a1<Esc>ea2<Esc>ea3<Esc>", "uu")
 | 
					//    if (!optionsIjNoEditor().oldundo) {
 | 
				
			||||||
      val before = """
 | 
					//      val keys = listOf("a1<Esc>ea2<Esc>ea3<Esc>", "uu")
 | 
				
			||||||
                Lorem Ipsum
 | 
					//      val before = """
 | 
				
			||||||
 | 
					//                Lorem Ipsum
 | 
				
			||||||
                ${c}Lorem ipsum dolor sit amet,
 | 
					//
 | 
				
			||||||
                consectetur adipiscing elit
 | 
					//                ${c}Lorem ipsum dolor sit amet,
 | 
				
			||||||
                Sed in orci mauris.
 | 
					//                consectetur adipiscing elit
 | 
				
			||||||
                Cras id tellus in ex imperdiet egestas.
 | 
					//                Sed in orci mauris.
 | 
				
			||||||
      """.trimIndent()
 | 
					//                Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
      val after = """
 | 
					//      """.trimIndent()
 | 
				
			||||||
                Lorem Ipsum
 | 
					//      val after = """
 | 
				
			||||||
 | 
					//                Lorem Ipsum
 | 
				
			||||||
                I1 found$c it in a legendary land
 | 
					//
 | 
				
			||||||
                consectetur adipiscing elit
 | 
					//                I1 found$c it in a legendary land
 | 
				
			||||||
                Sed in orci mauris.
 | 
					//                consectetur adipiscing elit
 | 
				
			||||||
                Cras id tellus in ex imperdiet egestas.
 | 
					//                Sed in orci mauris.
 | 
				
			||||||
      """.trimIndent()
 | 
					//                Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
      doTest(keys, before, after, Mode.NORMAL())
 | 
					//      """.trimIndent()
 | 
				
			||||||
      kotlin.test.assertFalse(hasSelection())
 | 
					//      doTest(keys, before, after, Mode.NORMAL())
 | 
				
			||||||
    }
 | 
					//      kotlin.test.assertFalse(hasSelection())
 | 
				
			||||||
  }
 | 
					//    }
 | 
				
			||||||
 | 
					//  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun hasSelection(): Boolean {
 | 
					  private fun hasSelection(): Boolean {
 | 
				
			||||||
    val editor = fixture.editor
 | 
					    val editor = fixture.editor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,14 +8,65 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package org.jetbrains.plugins.ideavim.action.change.insert
 | 
					package org.jetbrains.plugins.ideavim.action.change.insert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.ide.plugins.PluginManagerCore
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.Caret
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionHandler
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.actionSystem.EditorActionHandlerBean
 | 
				
			||||||
 | 
					import com.intellij.openapi.extensions.ExtensionPointName
 | 
				
			||||||
 | 
					import com.intellij.testFramework.ExtensionTestUtil
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
					import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
					import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
import org.junit.jupiter.api.Test
 | 
					import org.junit.jupiter.api.BeforeEach
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.RepeatedTest
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.RepetitionInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InsertEnterActionTest : VimTestCase() {
 | 
					class InsertEnterActionTest : VimTestCase() {
 | 
				
			||||||
  @Test
 | 
					  @BeforeEach
 | 
				
			||||||
 | 
					  fun setUp(repetitionInfo: RepetitionInfo) {
 | 
				
			||||||
 | 
					    // Set up a different combination of handlers for enter action
 | 
				
			||||||
 | 
					    // There is a specific that due to IDEA-300030 the existing for "forEach" handler may affect our handlers execution.
 | 
				
			||||||
 | 
					    val mainBean = EditorActionHandlerBean()
 | 
				
			||||||
 | 
					    mainBean.implementationClass = "com.maddyhome.idea.vim.handler.VimEnterHandler"
 | 
				
			||||||
 | 
					    mainBean.action = "EditorEnter"
 | 
				
			||||||
 | 
					    mainBean.setPluginDescriptor(PluginManagerCore.getPlugin(VimPlugin.getPluginId())!!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val singleBean = EditorActionHandlerBean()
 | 
				
			||||||
 | 
					    singleBean.implementationClass = DestroyerHandlerSingle::class.java.name
 | 
				
			||||||
 | 
					    singleBean.action = "EditorEnter"
 | 
				
			||||||
 | 
					    singleBean.setPluginDescriptor(PluginManagerCore.getPlugin(VimPlugin.getPluginId())!!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val forEachBean = EditorActionHandlerBean()
 | 
				
			||||||
 | 
					    forEachBean.implementationClass = DestroyerHandlerForEach::class.java.name
 | 
				
			||||||
 | 
					    forEachBean.action = "EditorEnter"
 | 
				
			||||||
 | 
					    forEachBean.setPluginDescriptor(PluginManagerCore.getPlugin(VimPlugin.getPluginId())!!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (repetitionInfo.currentRepetition == 1) {
 | 
				
			||||||
 | 
					      ExtensionTestUtil.maskExtensions(
 | 
				
			||||||
 | 
					        ExtensionPointName("com.intellij.editorActionHandler"),
 | 
				
			||||||
 | 
					        listOf(mainBean),
 | 
				
			||||||
 | 
					        fixture.testRootDisposable
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    } else if (repetitionInfo.currentRepetition == 2) {
 | 
				
			||||||
 | 
					      ExtensionTestUtil.maskExtensions(
 | 
				
			||||||
 | 
					        ExtensionPointName("com.intellij.editorActionHandler"),
 | 
				
			||||||
 | 
					        listOf(singleBean, mainBean),
 | 
				
			||||||
 | 
					        fixture.testRootDisposable
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    } else if (repetitionInfo.currentRepetition == 3) {
 | 
				
			||||||
 | 
					      ExtensionTestUtil.maskExtensions(
 | 
				
			||||||
 | 
					        ExtensionPointName("com.intellij.editorActionHandler"),
 | 
				
			||||||
 | 
					        listOf(singleBean, mainBean),
 | 
				
			||||||
 | 
					        fixture.testRootDisposable
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @RepeatedTest(3)
 | 
				
			||||||
  fun `test insert enter`() {
 | 
					  fun `test insert enter`() {
 | 
				
			||||||
    val before = """Lorem ipsum dolor sit amet,
 | 
					    val before = """Lorem ipsum dolor sit amet,
 | 
				
			||||||
        |${c}consectetur adipiscing elit
 | 
					        |${c}consectetur adipiscing elit
 | 
				
			||||||
@@ -31,8 +82,25 @@ class InsertEnterActionTest : VimTestCase() {
 | 
				
			|||||||
    doTest(listOf("i", "<Enter>"), before, after, Mode.INSERT)
 | 
					    doTest(listOf("i", "<Enter>"), before, after, Mode.INSERT)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @RepeatedTest(3)
 | 
				
			||||||
 | 
					  fun `test insert enter multicaret`() {
 | 
				
			||||||
 | 
					    val before = """Lorem ipsum dolor sit amet,
 | 
				
			||||||
 | 
					        |${c}consectetur adipiscing elit
 | 
				
			||||||
 | 
					        |Sed in orci mauris.
 | 
				
			||||||
 | 
					        |${c}Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
 | 
					    """.trimMargin()
 | 
				
			||||||
 | 
					    val after = """Lorem ipsum dolor sit amet,
 | 
				
			||||||
 | 
					        |
 | 
				
			||||||
 | 
					        |${c}consectetur adipiscing elit
 | 
				
			||||||
 | 
					        |Sed in orci mauris.
 | 
				
			||||||
 | 
					        |
 | 
				
			||||||
 | 
					        |${c}Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
 | 
					    """.trimMargin()
 | 
				
			||||||
 | 
					    doTest(listOf("i", "<Enter>"), before, after, Mode.INSERT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
 | 
					  @TestWithoutNeovim(SkipNeovimReason.CTRL_CODES)
 | 
				
			||||||
  @Test
 | 
					  @RepeatedTest(3)
 | 
				
			||||||
  fun `test insert enter with C-M`() {
 | 
					  fun `test insert enter with C-M`() {
 | 
				
			||||||
    val before = """Lorem ipsum dolor sit amet,
 | 
					    val before = """Lorem ipsum dolor sit amet,
 | 
				
			||||||
        |${c}consectetur adipiscing elit
 | 
					        |${c}consectetur adipiscing elit
 | 
				
			||||||
@@ -49,7 +117,7 @@ class InsertEnterActionTest : VimTestCase() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
					  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
				
			||||||
  @Test
 | 
					  @RepeatedTest(3)
 | 
				
			||||||
  fun `test insert enter scrolls view up at scrolloff`() {
 | 
					  fun `test insert enter scrolls view up at scrolloff`() {
 | 
				
			||||||
    configureByLines(50, "Lorem ipsum dolor sit amet,")
 | 
					    configureByLines(50, "Lorem ipsum dolor sit amet,")
 | 
				
			||||||
    enterCommand("set scrolloff=10")
 | 
					    enterCommand("set scrolloff=10")
 | 
				
			||||||
@@ -59,3 +127,30 @@ class InsertEnterActionTest : VimTestCase() {
 | 
				
			|||||||
    assertVisibleArea(6, 40)
 | 
					    assertVisibleArea(6, 40)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * An empty handler that works as run "for each caret"
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class DestroyerHandlerForEach(private val nextHandler: EditorActionHandler) : EditorActionHandler(true) {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * An empty handler that works as run "single time"
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					internal class DestroyerHandlerSingle(private val nextHandler: EditorActionHandler) : EditorActionHandler(false) {
 | 
				
			||||||
 | 
					  override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
 | 
				
			||||||
 | 
					    nextHandler.execute(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean {
 | 
				
			||||||
 | 
					    return nextHandler.isEnabled(editor, caret, dataContext)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,9 +11,8 @@ package org.jetbrains.plugins.ideavim.ex
 | 
				
			|||||||
import com.intellij.openapi.actionSystem.DataContext
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin
 | 
					import com.maddyhome.idea.vim.VimPlugin
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.enableOctopus
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
 | 
					import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.commands.EchoCommand
 | 
					import com.maddyhome.idea.vim.vimscript.model.commands.EchoCommand
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.commands.LetCommand
 | 
					import com.maddyhome.idea.vim.vimscript.model.commands.LetCommand
 | 
				
			||||||
@@ -49,13 +48,9 @@ class CommandParserTest : VimTestCase() {
 | 
				
			|||||||
      caretShape = false
 | 
					      caretShape = false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val before = "I ${c}found it in a legendary land"
 | 
					    val before = "I ${c}found it in a legendary land"
 | 
				
			||||||
    val after = if (enableOctopus) {
 | 
					    val after = """I :>>
 | 
				
			||||||
      """I :>>
 | 
					      |${c}found it in a legendary land
 | 
				
			||||||
        |${c}found it in a legendary land
 | 
					    """.trimMargin()
 | 
				
			||||||
      """.trimMargin()
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      "I :>>${c}found it in a legendary land"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    doTest(exCommand(">>"), before, after) {
 | 
					    doTest(exCommand(">>"), before, after) {
 | 
				
			||||||
      VimPlugin.setEnabled(false)
 | 
					      VimPlugin.setEnabled(false)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,20 +7,24 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
package org.jetbrains.plugins.ideavim.ex.implementation.commands
 | 
					package org.jetbrains.plugins.ideavim.ex.implementation.commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.idea.TestFor
 | 
				
			||||||
import com.intellij.openapi.actionSystem.DataContext
 | 
					import com.intellij.openapi.actionSystem.DataContext
 | 
				
			||||||
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
 | 
					import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					import com.maddyhome.idea.vim.ex.ExException
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
 | 
					import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
 | 
				
			||||||
import com.maddyhome.idea.vim.history.HistoryConstants
 | 
					import com.maddyhome.idea.vim.history.HistoryConstants
 | 
				
			||||||
import com.maddyhome.idea.vim.newapi.vim
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
					import org.jetbrains.plugins.ideavim.SkipNeovimReason
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
					import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.waitAndAssert
 | 
					import org.jetbrains.plugins.ideavim.waitAndAssert
 | 
				
			||||||
import org.junit.jupiter.api.Disabled
 | 
					import org.junit.jupiter.api.Disabled
 | 
				
			||||||
import org.junit.jupiter.api.Test
 | 
					import org.junit.jupiter.api.Test
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.assertThrows
 | 
				
			||||||
import javax.swing.JTextArea
 | 
					import javax.swing.JTextArea
 | 
				
			||||||
 | 
					import kotlin.test.assertIs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author vlan
 | 
					 * @author vlan
 | 
				
			||||||
@@ -664,6 +668,29 @@ n  ,f            <Plug>Foo
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @TestWithoutNeovim(SkipNeovimReason.ACTION_COMMAND)
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  fun `action execution has correct ordering`() {
 | 
				
			||||||
 | 
					    configureByJavaText(
 | 
				
			||||||
 | 
					      """
 | 
				
			||||||
 | 
					          -----
 | 
				
			||||||
 | 
					          1<caret>2345
 | 
				
			||||||
 | 
					          abcde
 | 
				
			||||||
 | 
					          -----
 | 
				
			||||||
 | 
					      """.trimIndent(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    typeText(commandToKeys("map k <Action>(EditorDown)x"))
 | 
				
			||||||
 | 
					    typeText(injector.parser.parseKeys("k"))
 | 
				
			||||||
 | 
					    assertState(
 | 
				
			||||||
 | 
					      """
 | 
				
			||||||
 | 
					          -----
 | 
				
			||||||
 | 
					          12345
 | 
				
			||||||
 | 
					          a${c}cde
 | 
				
			||||||
 | 
					          -----
 | 
				
			||||||
 | 
					      """.trimIndent(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @TestWithoutNeovim(reason = SkipNeovimReason.DIFFERENT)
 | 
					  @TestWithoutNeovim(reason = SkipNeovimReason.DIFFERENT)
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
  fun `test execute mapping with a delay`() {
 | 
					  fun `test execute mapping with a delay`() {
 | 
				
			||||||
@@ -849,7 +876,11 @@ n  ,f            <Plug>Foo
 | 
				
			|||||||
      indicateErrors = true,
 | 
					      indicateErrors = true,
 | 
				
			||||||
      null,
 | 
					      null,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    typeText(injector.parser.parseKeys("t"))
 | 
					    val exception = assertThrows<Throwable> {
 | 
				
			||||||
 | 
					      typeText(injector.parser.parseKeys("t"))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assertIs<ExException>(exception.cause) // The original exception comes from the LOG.error, so we check the cause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertPluginError(true)
 | 
					    assertPluginError(true)
 | 
				
			||||||
    assertPluginErrorMessageContains("E121: Undefined variable: s:mapping")
 | 
					    assertPluginErrorMessageContains("E121: Undefined variable: s:mapping")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -891,8 +922,13 @@ n  ,f            <Plug>Foo
 | 
				
			|||||||
          -----
 | 
					          -----
 | 
				
			||||||
    """.trimIndent()
 | 
					    """.trimIndent()
 | 
				
			||||||
    configureByJavaText(text)
 | 
					    configureByJavaText(text)
 | 
				
			||||||
    typeText(commandToKeys("inoremap <expr> <cr> unknownFunction() ? '\\<C-y>' : '\\<C-g>u\\<CR>'"))
 | 
					
 | 
				
			||||||
    typeText(injector.parser.parseKeys("i<CR>"))
 | 
					    val exception = assertThrows<Throwable> {
 | 
				
			||||||
 | 
					      typeText(commandToKeys("inoremap <expr> <cr> unknownFunction() ? '\\<C-y>' : '\\<C-g>u\\<CR>'"))
 | 
				
			||||||
 | 
					      typeText(injector.parser.parseKeys("i<CR>"))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assertIs<ExException>(exception.cause) // The original exception comes from the LOG.error, so we check the cause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertPluginError(true)
 | 
					    assertPluginError(true)
 | 
				
			||||||
    assertPluginErrorMessageContains("E117: Unknown function: unknownFunction")
 | 
					    assertPluginErrorMessageContains("E117: Unknown function: unknownFunction")
 | 
				
			||||||
    assertState(text)
 | 
					    assertState(text)
 | 
				
			||||||
@@ -1035,4 +1071,30 @@ n  ,i            <Action>(Back)
 | 
				
			|||||||
      injector.historyGroup.getEntries(HistoryConstants.COMMAND, 0, 0).last().entry,
 | 
					      injector.historyGroup.getEntries(HistoryConstants.COMMAND, 0, 0).last().entry,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @TestFor(issues = ["VIM-3103"])
 | 
				
			||||||
 | 
					  @TestWithoutNeovim(reason = SkipNeovimReason.ACTION_COMMAND)
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  fun `test map enter to action`() {
 | 
				
			||||||
 | 
					    configureByText(
 | 
				
			||||||
 | 
					      """
 | 
				
			||||||
 | 
					     Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Lorem ipsum dolor sit amet,
 | 
				
			||||||
 | 
					     ${c}consectetur adipiscing elit
 | 
				
			||||||
 | 
					     Sed in orci mauris.
 | 
				
			||||||
 | 
					     Cras id tellus in ex imperdiet egestas. 
 | 
				
			||||||
 | 
					    """.trimIndent()
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    typeText(commandToKeys("map <Enter> <Action>(EditorSelectWord)"))
 | 
				
			||||||
 | 
					    typeText("<Enter>")
 | 
				
			||||||
 | 
					    assertState("""
 | 
				
			||||||
 | 
					     Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Lorem ipsum dolor sit amet,
 | 
				
			||||||
 | 
					     ${s}${c}consectetur${se} adipiscing elit
 | 
				
			||||||
 | 
					     Sed in orci mauris.
 | 
				
			||||||
 | 
					     Cras id tellus in ex imperdiet egestas. 
 | 
				
			||||||
 | 
					    """.trimIndent())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,20 +164,19 @@ class SetCommandTest : VimTestCase() {
 | 
				
			|||||||
    assertCommandOutput("set all",
 | 
					    assertCommandOutput("set all",
 | 
				
			||||||
      """
 | 
					      """
 | 
				
			||||||
        |--- Options ---
 | 
					        |--- Options ---
 | 
				
			||||||
        |noargtextobj          ideawrite=all       scrolljump=1      notextobj-indent
 | 
					        |noargtextobj        noideatracetime       scrolljump=1      notextobj-entire
 | 
				
			||||||
        |  closenotebooks    noignorecase          scrolloff=0         timeout
 | 
					        |  closenotebooks      ideawrite=all       scrolloff=0       notextobj-indent
 | 
				
			||||||
        |nocommentary        noincsearch           selectmode=         timeoutlen=1000
 | 
					        |nocommentary        noignorecase          selectmode=         timeout
 | 
				
			||||||
        |nodigraph           nomatchit             shellcmdflag=-x   notrackactionids
 | 
					        |nodigraph           noincsearch           shellcmdflag=-x     timeoutlen=1000
 | 
				
			||||||
        |noexchange            maxmapdepth=20      shellxescape=@      undolevels=1000
 | 
					        |noexchange          nomatchit             shellxescape=@    notrackactionids
 | 
				
			||||||
        |nogdefault            more                shellxquote={       unifyjumps
 | 
					        |nogdefault            maxmapdepth=20      shellxquote={       undolevels=1000
 | 
				
			||||||
        |nohighlightedyank   nomultiple-cursors    showcmd             virtualedit=
 | 
					        |nohighlightedyank     more                showcmd             unifyjumps
 | 
				
			||||||
        |  history=50        noNERDTree            showmode          novisualbell
 | 
					        |  history=50        nomultiple-cursors    showmode            virtualedit=
 | 
				
			||||||
        |nohlsearch            nrformats=hex       sidescroll=0        visualdelay=100
 | 
					        |nohlsearch          noNERDTree            sidescroll=0      novisualbell
 | 
				
			||||||
        |noideaglobalmode    nonumber              sidescrolloff=0     whichwrap=b,s
 | 
					        |noideaglobalmode      nrformats=hex       sidescrolloff=0     visualdelay=100
 | 
				
			||||||
        |noideajoin          nooctopushandler    nosmartcase           wrapscan
 | 
					        |noideajoin          nonumber            nosmartcase           whichwrap=b,s
 | 
				
			||||||
        |  ideamarks           oldundo             startofline
 | 
					        |  ideamarks         norelativenumber      startofline         wrapscan
 | 
				
			||||||
        |  ideastrictmode    norelativenumber    nosurround
 | 
					        |  ideastrictmode      scroll=0          nosurround
 | 
				
			||||||
        |noideatracetime       scroll=0          notextobj-entire
 | 
					 | 
				
			||||||
        |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
					        |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
				
			||||||
        |  excommandannotation
 | 
					        |  excommandannotation
 | 
				
			||||||
        |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
					        |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
				
			||||||
@@ -195,7 +194,6 @@ class SetCommandTest : VimTestCase() {
 | 
				
			|||||||
        |  shell=/dummy/path/to/bash
 | 
					        |  shell=/dummy/path/to/bash
 | 
				
			||||||
        |novim-paragraph-motion
 | 
					        |novim-paragraph-motion
 | 
				
			||||||
        |  viminfo='100,<50,s10,h
 | 
					        |  viminfo='100,<50,s10,h
 | 
				
			||||||
        |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
        |
 | 
					        |
 | 
				
			||||||
      """.trimMargin())
 | 
					      """.trimMargin())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -262,8 +260,6 @@ class SetCommandTest : VimTestCase() {
 | 
				
			|||||||
      |noNERDTree
 | 
					      |noNERDTree
 | 
				
			||||||
      |  nrformats=hex
 | 
					      |  nrformats=hex
 | 
				
			||||||
      |nonumber
 | 
					      |nonumber
 | 
				
			||||||
      |nooctopushandler
 | 
					 | 
				
			||||||
      |  oldundo
 | 
					 | 
				
			||||||
      |norelativenumber
 | 
					      |norelativenumber
 | 
				
			||||||
      |noReplaceWithRegister
 | 
					      |noReplaceWithRegister
 | 
				
			||||||
      |  scroll=0
 | 
					      |  scroll=0
 | 
				
			||||||
@@ -291,7 +287,6 @@ class SetCommandTest : VimTestCase() {
 | 
				
			|||||||
      |  unifyjumps
 | 
					      |  unifyjumps
 | 
				
			||||||
      |novim-paragraph-motion
 | 
					      |novim-paragraph-motion
 | 
				
			||||||
      |  viminfo='100,<50,s10,h
 | 
					      |  viminfo='100,<50,s10,h
 | 
				
			||||||
      |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
      |  virtualedit=
 | 
					      |  virtualedit=
 | 
				
			||||||
      |novisualbell
 | 
					      |novisualbell
 | 
				
			||||||
      |  visualdelay=100
 | 
					      |  visualdelay=100
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -350,20 +350,19 @@ class SetglobalCommandTest : VimTestCase() {
 | 
				
			|||||||
    setOsSpecificOptionsToSafeValues()
 | 
					    setOsSpecificOptionsToSafeValues()
 | 
				
			||||||
    assertCommandOutput("setglobal all", """
 | 
					    assertCommandOutput("setglobal all", """
 | 
				
			||||||
      |--- Global option values ---
 | 
					      |--- Global option values ---
 | 
				
			||||||
      |noargtextobj          ideawrite=all       scrolljump=1      notextobj-indent
 | 
					      |noargtextobj        noideatracetime       scrolljump=1      notextobj-entire
 | 
				
			||||||
      |  closenotebooks    noignorecase          scrolloff=0         timeout
 | 
					      |  closenotebooks      ideawrite=all       scrolloff=0       notextobj-indent
 | 
				
			||||||
      |nocommentary        noincsearch           selectmode=         timeoutlen=1000
 | 
					      |nocommentary        noignorecase          selectmode=         timeout
 | 
				
			||||||
      |nodigraph           nomatchit             shellcmdflag=-x   notrackactionids
 | 
					      |nodigraph           noincsearch           shellcmdflag=-x     timeoutlen=1000
 | 
				
			||||||
      |noexchange            maxmapdepth=20      shellxescape=@      undolevels=1000
 | 
					      |noexchange          nomatchit             shellxescape=@    notrackactionids
 | 
				
			||||||
      |nogdefault            more                shellxquote={       unifyjumps
 | 
					      |nogdefault            maxmapdepth=20      shellxquote={       undolevels=1000
 | 
				
			||||||
      |nohighlightedyank   nomultiple-cursors    showcmd             virtualedit=
 | 
					      |nohighlightedyank     more                showcmd             unifyjumps
 | 
				
			||||||
      |  history=50        noNERDTree            showmode          novisualbell
 | 
					      |  history=50        nomultiple-cursors    showmode            virtualedit=
 | 
				
			||||||
      |nohlsearch            nrformats=hex       sidescroll=0        visualdelay=100
 | 
					      |nohlsearch          noNERDTree            sidescroll=0      novisualbell
 | 
				
			||||||
      |noideaglobalmode    nonumber              sidescrolloff=0     whichwrap=b,s
 | 
					      |noideaglobalmode      nrformats=hex       sidescrolloff=0     visualdelay=100
 | 
				
			||||||
      |noideajoin          nooctopushandler    nosmartcase           wrapscan
 | 
					      |noideajoin          nonumber            nosmartcase           whichwrap=b,s
 | 
				
			||||||
      |  ideamarks           oldundo             startofline
 | 
					      |  ideamarks         norelativenumber      startofline         wrapscan
 | 
				
			||||||
      |  ideastrictmode    norelativenumber    nosurround
 | 
					      |  ideastrictmode      scroll=0          nosurround
 | 
				
			||||||
      |noideatracetime       scroll=0          notextobj-entire
 | 
					 | 
				
			||||||
      |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
					      |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
				
			||||||
      |  excommandannotation
 | 
					      |  excommandannotation
 | 
				
			||||||
      |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
					      |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
				
			||||||
@@ -381,7 +380,6 @@ class SetglobalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |  shell=/dummy/path/to/bash
 | 
					      |  shell=/dummy/path/to/bash
 | 
				
			||||||
      |novim-paragraph-motion
 | 
					      |novim-paragraph-motion
 | 
				
			||||||
      |  viminfo='100,<50,s10,h
 | 
					      |  viminfo='100,<50,s10,h
 | 
				
			||||||
      |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
      |""".trimMargin()
 | 
					      |""".trimMargin()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -444,8 +442,6 @@ class SetglobalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |noNERDTree
 | 
					      |noNERDTree
 | 
				
			||||||
      |  nrformats=hex
 | 
					      |  nrformats=hex
 | 
				
			||||||
      |nonumber
 | 
					      |nonumber
 | 
				
			||||||
      |nooctopushandler
 | 
					 | 
				
			||||||
      |  oldundo
 | 
					 | 
				
			||||||
      |norelativenumber
 | 
					      |norelativenumber
 | 
				
			||||||
      |noReplaceWithRegister
 | 
					      |noReplaceWithRegister
 | 
				
			||||||
      |  scroll=0
 | 
					      |  scroll=0
 | 
				
			||||||
@@ -473,7 +469,6 @@ class SetglobalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |  unifyjumps
 | 
					      |  unifyjumps
 | 
				
			||||||
      |novim-paragraph-motion
 | 
					      |novim-paragraph-motion
 | 
				
			||||||
      |  viminfo='100,<50,s10,h
 | 
					      |  viminfo='100,<50,s10,h
 | 
				
			||||||
      |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
      |  virtualedit=
 | 
					      |  virtualedit=
 | 
				
			||||||
      |novisualbell
 | 
					      |novisualbell
 | 
				
			||||||
      |  visualdelay=100
 | 
					      |  visualdelay=100
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -382,20 +382,19 @@ class SetlocalCommandTest : VimTestCase() {
 | 
				
			|||||||
    setOsSpecificOptionsToSafeValues()
 | 
					    setOsSpecificOptionsToSafeValues()
 | 
				
			||||||
    assertCommandOutput("setlocal all", """
 | 
					    assertCommandOutput("setlocal all", """
 | 
				
			||||||
      |--- Local option values ---
 | 
					      |--- Local option values ---
 | 
				
			||||||
      |noargtextobj        noideatracetime       scroll=0          notextobj-entire
 | 
					      |noargtextobj          ideastrictmode      scroll=0          nosurround
 | 
				
			||||||
      |  closenotebooks      ideawrite=all       scrolljump=1      notextobj-indent
 | 
					      |  closenotebooks    noideatracetime       scrolljump=1      notextobj-entire
 | 
				
			||||||
      |nocommentary        noignorecase          scrolloff=-1        timeout
 | 
					      |nocommentary          ideawrite=all       scrolloff=-1      notextobj-indent
 | 
				
			||||||
      |nodigraph           noincsearch           selectmode=         timeoutlen=1000
 | 
					      |nodigraph           noignorecase          selectmode=         timeout
 | 
				
			||||||
      |noexchange          nomatchit             shellcmdflag=-x   notrackactionids
 | 
					      |noexchange          noincsearch           shellcmdflag=-x     timeoutlen=1000
 | 
				
			||||||
      |nogdefault            maxmapdepth=20      shellxescape=@      unifyjumps
 | 
					      |nogdefault          nomatchit             shellxescape=@    notrackactionids
 | 
				
			||||||
      |nohighlightedyank     more                shellxquote={       virtualedit=
 | 
					      |nohighlightedyank     maxmapdepth=20      shellxquote={       unifyjumps
 | 
				
			||||||
      |  history=50        nomultiple-cursors    showcmd           novisualbell
 | 
					      |  history=50          more                showcmd             virtualedit=
 | 
				
			||||||
      |nohlsearch          noNERDTree            showmode            visualdelay=100
 | 
					      |nohlsearch          nomultiple-cursors    showmode          novisualbell
 | 
				
			||||||
      |noideaglobalmode      nrformats=hex       sidescroll=0        whichwrap=b,s
 | 
					      |noideaglobalmode    noNERDTree            sidescroll=0        visualdelay=100
 | 
				
			||||||
      |--ideajoin          nonumber              sidescrolloff=-1    wrapscan
 | 
					      |--ideajoin            nrformats=hex       sidescrolloff=-1    whichwrap=b,s
 | 
				
			||||||
      |  ideamarks         nooctopushandler    nosmartcase
 | 
					      |  ideamarks         nonumber            nosmartcase           wrapscan
 | 
				
			||||||
      |  idearefactormode=   oldundo             startofline
 | 
					      |  idearefactormode= norelativenumber      startofline
 | 
				
			||||||
      |  ideastrictmode    norelativenumber    nosurround
 | 
					 | 
				
			||||||
      |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
					      |  clipboard=ideaput,autoselect,exclude:cons\|linux
 | 
				
			||||||
      |  excommandannotation
 | 
					      |  excommandannotation
 | 
				
			||||||
      |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
					      |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
 | 
				
			||||||
@@ -413,7 +412,6 @@ class SetlocalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |  undolevels=-123456
 | 
					      |  undolevels=-123456
 | 
				
			||||||
      |novim-paragraph-motion
 | 
					      |novim-paragraph-motion
 | 
				
			||||||
      |  viminfo='100,<50,s10,h
 | 
					      |  viminfo='100,<50,s10,h
 | 
				
			||||||
      |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
      |""".trimMargin()
 | 
					      |""".trimMargin()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -482,8 +480,6 @@ class SetlocalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |noNERDTree
 | 
					      |noNERDTree
 | 
				
			||||||
      |  nrformats=hex
 | 
					      |  nrformats=hex
 | 
				
			||||||
      |nonumber
 | 
					      |nonumber
 | 
				
			||||||
      |nooctopushandler
 | 
					 | 
				
			||||||
      |  oldundo
 | 
					 | 
				
			||||||
      |norelativenumber
 | 
					      |norelativenumber
 | 
				
			||||||
      |noReplaceWithRegister
 | 
					      |noReplaceWithRegister
 | 
				
			||||||
      |  scroll=0
 | 
					      |  scroll=0
 | 
				
			||||||
@@ -511,7 +507,6 @@ class SetlocalCommandTest : VimTestCase() {
 | 
				
			|||||||
      |  unifyjumps
 | 
					      |  unifyjumps
 | 
				
			||||||
      |novim-paragraph-motion
 | 
					      |novim-paragraph-motion
 | 
				
			||||||
      |  viminfo='100,<50,s10,h
 | 
					      |  viminfo='100,<50,s10,h
 | 
				
			||||||
      |  vimscriptfunctionannotation
 | 
					 | 
				
			||||||
      |  virtualedit=
 | 
					      |  virtualedit=
 | 
				
			||||||
      |novisualbell
 | 
					      |novisualbell
 | 
				
			||||||
      |  visualdelay=100
 | 
					      |  visualdelay=100
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,17 +9,78 @@
 | 
				
			|||||||
package org.jetbrains.plugins.ideavim.ex.implementation.commands
 | 
					package org.jetbrains.plugins.ideavim.ex.implementation.commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.key
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.MappingMode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.MappingInfo
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.key.MappingOwner
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand
 | 
					import com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
import org.junit.jupiter.api.Test
 | 
					import org.junit.jupiter.api.Test
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.io.TempDir
 | 
				
			||||||
 | 
					import java.io.File
 | 
				
			||||||
import kotlin.test.assertEquals
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					import kotlin.test.assertNull
 | 
				
			||||||
import kotlin.test.assertTrue
 | 
					import kotlin.test.assertTrue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SourceCommandTest : VimTestCase() {
 | 
					class SourceCommandTest : VimTestCase() {
 | 
				
			||||||
 | 
					  @TempDir
 | 
				
			||||||
 | 
					  var tempDir: File? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
  fun `command parsing`() {
 | 
					  fun `command parsing`() {
 | 
				
			||||||
    val command = injector.vimscriptParser.parseCommand("source ~/.vimrc")
 | 
					    val command = injector.vimscriptParser.parseCommand("source ~/.vimrc")
 | 
				
			||||||
    assertTrue(command is SourceCommand)
 | 
					    assertTrue(command is SourceCommand)
 | 
				
			||||||
    assertEquals("~/.vimrc", command.argument)
 | 
					    assertEquals("~/.vimrc", command.argument)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  fun `loading ideavimrc configuration via API`() {
 | 
				
			||||||
 | 
					    configureByText("")
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val layerPreCheck = injector.keyGroup.getKeyMappingLayer(MappingMode.NORMAL)
 | 
				
			||||||
 | 
					      val mappingPreCheck = layerPreCheck.getLayer(listOf(key("x")))
 | 
				
			||||||
 | 
					      assertNull(mappingPreCheck) // Make sure we don't yet have a mapping from x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val file = File(tempDir, "text.txt")
 | 
				
			||||||
 | 
					      file.writeText(
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        map x y
 | 
				
			||||||
 | 
					      """.trimIndent()
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      injector.vimscriptExecutor.executeFile(file, fixture.editor.vim, true)
 | 
				
			||||||
 | 
					      val layer = injector.keyGroup.getKeyMappingLayer(MappingMode.NORMAL)
 | 
				
			||||||
 | 
					      val mapping = layer.getLayer(listOf(key("x"))) as MappingInfo
 | 
				
			||||||
 | 
					      assertEquals(MappingOwner.IdeaVim.InitScript, mapping.owner)
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      injector.keyGroup.removeKeyMapping(MappingMode.NXO, listOf(key("x")))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  fun `loading NOT ideavimrc configuration via API`() {
 | 
				
			||||||
 | 
					    configureByText("")
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val layerPreCheck = injector.keyGroup.getKeyMappingLayer(MappingMode.NORMAL)
 | 
				
			||||||
 | 
					      val mappingPreCheck = layerPreCheck.getLayer(listOf(key("x")))
 | 
				
			||||||
 | 
					      assertNull(mappingPreCheck) // Make sure we don't yet have a mapping from x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val file = File(tempDir, "text.txt")
 | 
				
			||||||
 | 
					      file.writeText(
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        map x y
 | 
				
			||||||
 | 
					      """.trimIndent()
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      injector.vimscriptExecutor.executeFile(file, fixture.editor.vim, false)
 | 
				
			||||||
 | 
					      val layer = injector.keyGroup.getKeyMappingLayer(MappingMode.NORMAL)
 | 
				
			||||||
 | 
					      val mapping = layer.getLayer(listOf(key("x"))) as MappingInfo
 | 
				
			||||||
 | 
					      assertEquals(MappingOwner.IdeaVim.Other, mapping.owner)
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      injector.keyGroup.removeKeyMapping(MappingMode.NXO, listOf(key("x")))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -17,9 +17,7 @@ import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			|||||||
import com.maddyhome.idea.vim.api.injector
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
import com.maddyhome.idea.vim.api.moveToMotion
 | 
					import com.maddyhome.idea.vim.api.moveToMotion
 | 
				
			||||||
import com.maddyhome.idea.vim.command.MappingMode
 | 
					import com.maddyhome.idea.vim.command.MappingMode
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.extension.Alias
 | 
					import com.maddyhome.idea.vim.extension.Alias
 | 
				
			||||||
import com.maddyhome.idea.vim.extension.ExtensionBeanClass
 | 
					import com.maddyhome.idea.vim.extension.ExtensionBeanClass
 | 
				
			||||||
import com.maddyhome.idea.vim.extension.ExtensionHandler
 | 
					import com.maddyhome.idea.vim.extension.ExtensionHandler
 | 
				
			||||||
@@ -27,12 +25,13 @@ import com.maddyhome.idea.vim.extension.VimExtension
 | 
				
			|||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
 | 
					import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
 | 
				
			||||||
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.VimExtensionRegistrar
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.handler.Motion
 | 
					import com.maddyhome.idea.vim.handler.Motion
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.isEndAllowed
 | 
					import com.maddyhome.idea.vim.helper.isEndAllowed
 | 
				
			||||||
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.OptionAccessScope
 | 
					import com.maddyhome.idea.vim.options.OptionAccessScope
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
				
			||||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
					import org.jetbrains.plugins.ideavim.VimTestCase
 | 
				
			||||||
import org.junit.jupiter.api.AfterEach
 | 
					import org.junit.jupiter.api.AfterEach
 | 
				
			||||||
import org.junit.jupiter.api.BeforeEach
 | 
					import org.junit.jupiter.api.BeforeEach
 | 
				
			||||||
@@ -268,6 +267,7 @@ class PlugMissingKeysTest : VimTestCase() {
 | 
				
			|||||||
      "Plug 'MyTest'",
 | 
					      "Plug 'MyTest'",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mapping to Z was override by the mapping to myKey
 | 
				
			||||||
    val keyMappings = VimPlugin.getKey().getMapTo(MappingMode.NORMAL, injector.parser.parseKeys("<Plug>TestMissing"))
 | 
					    val keyMappings = VimPlugin.getKey().getMapTo(MappingMode.NORMAL, injector.parser.parseKeys("<Plug>TestMissing"))
 | 
				
			||||||
    kotlin.test.assertEquals(1, keyMappings.size)
 | 
					    kotlin.test.assertEquals(1, keyMappings.size)
 | 
				
			||||||
    kotlin.test.assertEquals(injector.parser.parseKeys("myKey"), keyMappings.first().first)
 | 
					    kotlin.test.assertEquals(injector.parser.parseKeys("myKey"), keyMappings.first().first)
 | 
				
			||||||
@@ -284,6 +284,7 @@ class PlugMissingKeysTest : VimTestCase() {
 | 
				
			|||||||
      "map myKey <Plug>TestMissing",
 | 
					      "map myKey <Plug>TestMissing",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mapping to Z was override by the mapping to myKey
 | 
				
			||||||
    val keyMappings = VimPlugin.getKey().getMapTo(MappingMode.NORMAL, injector.parser.parseKeys("<Plug>TestMissing"))
 | 
					    val keyMappings = VimPlugin.getKey().getMapTo(MappingMode.NORMAL, injector.parser.parseKeys("<Plug>TestMissing"))
 | 
				
			||||||
    kotlin.test.assertEquals(1, keyMappings.size)
 | 
					    kotlin.test.assertEquals(1, keyMappings.size)
 | 
				
			||||||
    kotlin.test.assertEquals(injector.parser.parseKeys("myKey"), keyMappings.first().first)
 | 
					    kotlin.test.assertEquals(injector.parser.parseKeys("myKey"), keyMappings.first().first)
 | 
				
			||||||
@@ -319,9 +320,10 @@ class PlugMissingKeysTest : VimTestCase() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private fun executeLikeVimrc(vararg text: String) {
 | 
					  private fun executeLikeVimrc(vararg text: String) {
 | 
				
			||||||
    injector.vimscriptExecutor.executingVimscript = true
 | 
					    injector.vimscriptExecutor.executingVimscript = true
 | 
				
			||||||
 | 
					    injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
 | 
				
			||||||
    executeVimscript(text.joinToString("\n"), false)
 | 
					    executeVimscript(text.joinToString("\n"), false)
 | 
				
			||||||
 | 
					    injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
 | 
				
			||||||
    injector.vimscriptExecutor.executingVimscript = false
 | 
					    injector.vimscriptExecutor.executingVimscript = false
 | 
				
			||||||
    VimExtensionRegistrar.enableDelayedExtensions()
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -161,7 +161,6 @@ private class OptionsVerificator : BeforeTestExecutionCallback, AfterTestExecuti
 | 
				
			|||||||
      TestIjOptionConstants.ideavimsupport,
 | 
					      TestIjOptionConstants.ideavimsupport,
 | 
				
			||||||
      TestOptionConstants.maxmapdepth,
 | 
					      TestOptionConstants.maxmapdepth,
 | 
				
			||||||
      TestOptionConstants.number,
 | 
					      TestOptionConstants.number,
 | 
				
			||||||
      TestIjOptionConstants.octopushandler,
 | 
					 | 
				
			||||||
      TestOptionConstants.relativenumber,
 | 
					      TestOptionConstants.relativenumber,
 | 
				
			||||||
      TestOptionConstants.scrolljump,
 | 
					      TestOptionConstants.scrolljump,
 | 
				
			||||||
      TestOptionConstants.scrolloff,
 | 
					      TestOptionConstants.scrolloff,
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user