mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-11-04 01:40:12 +01:00 
			
		
		
		
	Compare commits
	
		
			112 Commits
		
	
	
		
			customized
			...
			customized
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						822dad52f3
	
				 | 
					
					
						|||
| 
						
						
							
						
						bf12c98880
	
				 | 
					
					
						|||
| 
						
						
							
						
						c02bd15e4f
	
				 | 
					
					
						|||
| 
						
						
							
						
						5957d5d681
	
				 | 
					
					
						|||
| 
						
						
							
						
						9445afb555
	
				 | 
					
					
						|||
| 
						
						
							
						
						6e115bdf64
	
				 | 
					
					
						|||
| 
						
						
							
						
						6305c412b5
	
				 | 
					
					
						|||
| 
						
						
							
						
						be2eabe3b9
	
				 | 
					
					
						|||
| 
						
						
							
						
						de13e4348a
	
				 | 
					
					
						|||
| 
						
						
							
						
						1c154fdc8a
	
				 | 
					
					
						|||
| 
						
						
							
						
						9b75931736
	
				 | 
					
					
						|||
| 
						
						
							
						
						3fe97aa767
	
				 | 
					
					
						|||
| 
						
						
							
						
						8eb2dbebcf
	
				 | 
					
					
						|||
| 
						
						
							
						
						cb781f9a0d
	
				 | 
					
					
						|||
| 
						
						
							
						
						6693755823
	
				 | 
					
					
						|||
| 
						
						
							
						
						9a9bd335d3
	
				 | 
					
					
						|||
| 
						
						
							
						
						91e22482c6
	
				 | 
					
					
						|||
| 
						
						
							
						
						06dc2ed75c
	
				 | 
					
					
						|||
| 
						
						
							
						
						12da1ac969
	
				 | 
					
					
						|||
| 
						
						
							
						
						5747ac0ebf
	
				 | 
					
					
						|||
| 
						
						
							
						
						8a47bc1840
	
				 | 
					
					
						|||
| 
						
						
							
						
						da4deaf698
	
				 | 
					
					
						|||
| 
						 | 
					4c09ab4766 | ||
| 
						 | 
					ee447bce07 | ||
| 
						 | 
					5fb4c10f88 | ||
| 
						 | 
					ed2fcb08b0 | ||
| dedd90ce13 | |||
| 
						 | 
					73326e623e | ||
| 
						 | 
					a2bc34d6ec | ||
| 
						 | 
					b652c7726a | ||
| 
						 | 
					fb7a2de07b | ||
| 
						 | 
					def9ca479b | ||
| 
						 | 
					0936e0761f | ||
| 
						 | 
					09a335bcfe | ||
| 
						 | 
					37b8d69bac | ||
| 
						 | 
					13308050a8 | ||
| 
						 | 
					a1a553ebc9 | ||
| 
						 | 
					5bb0c4f7cb | ||
| 
						 | 
					da6736f24a | ||
| 
						 | 
					4df1ce2ae8 | ||
| 
						 | 
					00fd4cd491 | ||
| 
						 | 
					d185672e2f | ||
| 
						 | 
					55fef03a4a | ||
| 
						 | 
					69b3e4f782 | ||
| 
						 | 
					6be29b0378 | ||
| 
						 | 
					9965c863a6 | ||
| 
						 | 
					3f11ae512c | ||
| 
						 | 
					1c842eb3d8 | ||
| 
						 | 
					c7fbce675b | ||
| 
						 | 
					d7e68488c8 | ||
| 
						 | 
					69d13a74e6 | ||
| 
						 | 
					5a83df34a7 | ||
| 
						 | 
					0a18c388e0 | ||
| 
						 | 
					1a3409e7df | ||
| 
						 | 
					e93db961a0 | ||
| 
						 | 
					8fd76bd08f | ||
| 
						 | 
					0eea4a5b2c | ||
| 
						 | 
					18a0c533e2 | ||
| 
						 | 
					0bd8d8f4d2 | ||
| 
						 | 
					64a89c8863 | ||
| 
						 | 
					5b17d7740e | ||
| 
						 | 
					e406885ec6 | ||
| 
						 | 
					9bbeab8062 | ||
| 
						 | 
					373bfc4eab | ||
| 
						 | 
					050f2f7b97 | ||
| 
						 | 
					e30bc14843 | ||
| 
						 | 
					76d590be11 | ||
| 
						 | 
					b005328b4a | ||
| 
						 | 
					ad20021cee | ||
| 
						 | 
					126de5c218 | ||
| 
						 | 
					0f7aef3f15 | ||
| 
						 | 
					f352b84922 | ||
| 
						 | 
					789faa7cb2 | ||
| 
						 | 
					a338f5768a | ||
| 
						 | 
					8205c74571 | ||
| 
						 | 
					def40eb409 | ||
| 
						 | 
					010e8a7541 | ||
| 
						 | 
					46c6778b3a | ||
| 
						 | 
					0977bd4400 | ||
| 
						 | 
					db092e9b0a | ||
| 
						 | 
					5cfb98e188 | ||
| 
						 | 
					3a95b62885 | ||
| 
						 | 
					93e6adf5a9 | ||
| 
						 | 
					37204398ff | ||
| 
						 | 
					b2f450d14d | ||
| 
						 | 
					61da888571 | ||
| 
						 | 
					fcda97cfb8 | ||
| 
						 | 
					1dc7ea6363 | ||
| 
						 | 
					bb507db884 | ||
| 
						 | 
					7b0482ed94 | ||
| 
						 | 
					1c79b0d59a | ||
| 
						 | 
					ff4eb31418 | ||
| 
						 | 
					cb1078cf70 | ||
| 
						 | 
					da3e40eaf6 | ||
| 
						 | 
					17f77a9639 | ||
| 
						 | 
					3d03494354 | ||
| 
						 | 
					642caddda7 | ||
| 
						 | 
					1d97c43e30 | ||
| 
						 | 
					7ed3e3b53c | ||
| 
						 | 
					aa39ca2006 | ||
| 
						 | 
					bb122903de | ||
| 
						 | 
					c84a3cf64d | ||
| 
						 | 
					f4c9464b8a | ||
| 
						 | 
					3ba14d05b4 | ||
| 
						 | 
					2189b70b87 | ||
| 
						 | 
					ea2222f9d5 | ||
| 
						 | 
					7d68d41888 | ||
| 
						 | 
					44749b6d8c | ||
| 
						 | 
					1ce4dbc569 | ||
| 
						 | 
					db59513505 | ||
| 
						 | 
					8c9ff9465f | ||
| 
						 | 
					1a2322ddec | 
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
* text=auto eol=lf
 | 
			
		||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -27,9 +27,6 @@
 | 
			
		||||
# Generated by gradle task "generateGrammarSource"
 | 
			
		||||
vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
			
		||||
vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
			
		||||
# Generated JSONs for lazy classloading
 | 
			
		||||
/vim-engine/src/main/resources/ksp-generated
 | 
			
		||||
/src/main/resources/ksp-generated
 | 
			
		||||
 | 
			
		||||
# Created by github automation
 | 
			
		||||
settings.xml
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.teamcity/_Self/Project.kt
									
									
									
									
										vendored
									
									
								
							@@ -27,6 +27,7 @@ object Project : Project({
 | 
			
		||||
  // Active tests
 | 
			
		||||
  buildType(TestingBuildType("Latest EAP", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
			
		||||
  buildType(TestingBuildType("2024.1.1", "<default>"))
 | 
			
		||||
  buildType(TestingBuildType("2024.2", "<default>"))
 | 
			
		||||
  buildType(TestingBuildType("Latest EAP With Xorg", "<default>", version = "LATEST-EAP-SNAPSHOT"))
 | 
			
		||||
 | 
			
		||||
  buildType(PropertyBased)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								AUTHORS.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								AUTHORS.md
									
									
									
									
									
								
							@@ -523,6 +523,22 @@ Contributors:
 | 
			
		||||
  [![icon][github]](https://github.com/LazyScaper)
 | 
			
		||||
   
 | 
			
		||||
  Jake
 | 
			
		||||
* [![icon][mail]](mailto:the1xdeveloper@gmail.com)
 | 
			
		||||
  [![icon][github]](https://github.com/The1xDeveloper)
 | 
			
		||||
   
 | 
			
		||||
  The1xDeveloper
 | 
			
		||||
* [![icon][mail]](mailto:shaunewilliams@gmail.com)
 | 
			
		||||
  [![icon][github]](https://github.com/shaunlebron)
 | 
			
		||||
   
 | 
			
		||||
  shaun
 | 
			
		||||
* [![icon][mail]](mailto:i.i.babko@gmail.com)
 | 
			
		||||
  [![icon][github]](https://github.com/igorbabko)
 | 
			
		||||
   
 | 
			
		||||
  Igor Babko
 | 
			
		||||
* [![icon][mail]](mailto:533601+felixwiemuth@users.noreply.github.com)
 | 
			
		||||
  [![icon][github]](https://github.com/felixwiemuth)
 | 
			
		||||
   
 | 
			
		||||
  Felix Wiemuth
 | 
			
		||||
 | 
			
		||||
Previous contributors:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@ usual beta standards.
 | 
			
		||||
 | 
			
		||||
Since version 2.9.0, the changelog can be found on YouTrack
 | 
			
		||||
 | 
			
		||||
To Be Released: https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20
 | 
			
		||||
Latest Fixes: https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20updated%20
 | 
			
		||||
* [To Be Released](https://youtrack.jetbrains.com/issues/VIM?q=%23%7BReady%20To%20Release%7D%20)
 | 
			
		||||
* [Version Fixes](https://youtrack.jetbrains.com/issues/VIM?q=State:%20Fixed%20sort%20by:%20%7BFix%20versions%7D%20asc)
 | 
			
		||||
 | 
			
		||||
## 2.9.0, 2024-02-20
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -62,12 +62,16 @@ for a few days or send it to a friend for testing.
 | 
			
		||||
If you are looking for:
 | 
			
		||||
 | 
			
		||||
- Vim commands (`w`, `<C-O>`, `p`, etc.):
 | 
			
		||||
    - Any particular command: `package-info.java`.
 | 
			
		||||
    - Any particular command:
 | 
			
		||||
      - [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_commands.json)
 | 
			
		||||
      - [IdeaVim only commands](src/main/resources/ksp-generated/intellij_commands.json)
 | 
			
		||||
    - How commands are executed in common: `EditorActionHandlerBase`.
 | 
			
		||||
    - Key mapping: `KeyHandler.handleKey()`.
 | 
			
		||||
 | 
			
		||||
- Ex commands (`:set`, `:s`, `:nohlsearch`):
 | 
			
		||||
    - Any particular ex command: package `com.maddyhome.idea.vim.ex.handler`.
 | 
			
		||||
    - Any particular command:
 | 
			
		||||
        - [Commands common for Fleet and IdeaVim](vim-engine/src/main/resources/ksp-generated/engine_ex_commands.json)
 | 
			
		||||
        - [IdeaVim only commands](src/main/resources/ksp-generated/intellij_ex_commands.json)
 | 
			
		||||
    - Vim script grammar: `Vimscript.g4`.
 | 
			
		||||
    - Vim script parsing: package `com.maddyhome.idea.vim.vimscript.parser`.
 | 
			
		||||
    - Vim script executor: `Executor`.
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,6 @@ etc
 | 
			
		||||
 | 
			
		||||
See also:
 | 
			
		||||
 | 
			
		||||
* [The list of all supported commands](src/main/java/com/maddyhome/idea/vim/package-info.java)
 | 
			
		||||
* [Top feature requests and bugs](https://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
 | 
			
		||||
* [Vimscript support roadmap](vimscript-info/VIMSCRIPT_ROADMAP.md)
 | 
			
		||||
* [List of supported in-build functions](vimscript-info/FUNCTIONS_INFO.MD)
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,8 @@ class CommandOrMotionProcessor(private val environment: SymbolProcessorEnvironme
 | 
			
		||||
    Files.createDirectories(generatedDirPath)
 | 
			
		||||
 | 
			
		||||
    val filePath = generatedDirPath.resolve(environment.options["commands_file"]!!)
 | 
			
		||||
    val fileContent = json.encodeToString(commands)
 | 
			
		||||
    val sortedCommands = commands.sortedWith(compareBy({ it.keys }, { it.`class` }))
 | 
			
		||||
    val fileContent = json.encodeToString(sortedCommands)
 | 
			
		||||
    filePath.writeText(fileContent)
 | 
			
		||||
 | 
			
		||||
    return emptyList()
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,8 @@ class ExCommandProcessor(private val environment: SymbolProcessorEnvironment): S
 | 
			
		||||
    Files.createDirectories(generatedDirPath)
 | 
			
		||||
 | 
			
		||||
    val filePath = generatedDirPath.resolve(environment.options["ex_commands_file"]!!)
 | 
			
		||||
    val fileContent = json.encodeToString(commandToClass)
 | 
			
		||||
    val sortedCommandToClass = commandToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
 | 
			
		||||
    val fileContent = json.encodeToString(sortedCommandToClass)
 | 
			
		||||
    filePath.writeText(fileContent)
 | 
			
		||||
 | 
			
		||||
    return emptyList()
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,8 @@ class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnviron
 | 
			
		||||
    Files.createDirectories(generatedDirPath)
 | 
			
		||||
 | 
			
		||||
    val filePath = generatedDirPath.resolve(environment.options["vimscript_functions_file"]!!)
 | 
			
		||||
    val fileContent = json.encodeToString(nameToClass)
 | 
			
		||||
    val sortedNameToClass = nameToClass.toList().sortedWith(compareBy({ it.first }, { it.second })).toMap()
 | 
			
		||||
    val fileContent = json.encodeToString(sortedNameToClass)
 | 
			
		||||
    filePath.writeText(fileContent)
 | 
			
		||||
 | 
			
		||||
    return emptyList()
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,7 @@ dependencies {
 | 
			
		||||
 | 
			
		||||
    // AceJump is an optional dependency. We use their SessionManager class to check if it's active
 | 
			
		||||
    plugin("AceJump", "3.8.19")
 | 
			
		||||
    plugin("com.intellij.classic.ui", "242.20224.159")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  moduleSources(project(":vim-engine", "sourcesJarArtifacts"))
 | 
			
		||||
@@ -210,6 +211,8 @@ tasks {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  compileTestKotlin {
 | 
			
		||||
    enabled = false
 | 
			
		||||
    
 | 
			
		||||
    kotlinOptions {
 | 
			
		||||
      jvmTarget = javaVersion
 | 
			
		||||
      apiVersion = "1.9"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
Welcome to the IdeaVim wiki!
 | 
			
		||||
 | 
			
		||||
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins.md)
 | 
			
		||||
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples.md)
 | 
			
		||||
- List of "set" commands: ["set" commands](set-commands.md)
 | 
			
		||||
- Docs about "select" mode in vim: [select mode](Select-mode.md)
 | 
			
		||||
- List of IdeaVim plugins: [plugins](IdeaVim%20Plugins)
 | 
			
		||||
- Examples of `ideajoin` option (also known as "smart join"): ["ideajoin" examples](ideajoin-examples)
 | 
			
		||||
- List of "set" commands: ["set" commands](set-commands)
 | 
			
		||||
- Docs about "select" mode in vim: [select mode](Select-mode)
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ Original plugin: [NERDTree](https://github.com/preservim/nerdtree).
 | 
			
		||||
   
 | 
			
		||||
### Instructions
 | 
			
		||||
   
 | 
			
		||||
[See here](NERDTree-support.md).
 | 
			
		||||
[See here](NERDTree-support).
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ Every effort is made to make these options compatible with Vim behaviour.
 | 
			
		||||
However, some differences are inevitable.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
'clipboard'     'cb'    Defines clipboard behavioue
 | 
			
		||||
'clipboard'     'cb'    Defines clipboard behavior
 | 
			
		||||
        A comma-separated list of words to control clipboard behaviour:
 | 
			
		||||
           unnamed      The clipboard register '*' is used instead of the
 | 
			
		||||
                        unnamed register
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# Support Guide
 | 
			
		||||
 | 
			
		||||
This document is created to help our support team.
 | 
			
		||||
It's not intended to be read by the users as it brings to value to them.
 | 
			
		||||
It's not intended to be read by the users as it brings no value to them.
 | 
			
		||||
 | 
			
		||||
## Support channels
 | 
			
		||||
 | 
			
		||||
@@ -35,4 +35,4 @@ IdeaVim has multiple YouTrack statuses, main are:
 | 
			
		||||
# ~.ideavimrc file
 | 
			
		||||
 | 
			
		||||
`~/.ideavimrc` is the file that is used for IdeaVim configuration. It may affect behaviour of the program,
 | 
			
		||||
so it makes sense to additionally request this file in case the issues can't be reproduced.
 | 
			
		||||
so it makes sense to additionally request this file in case the issues can't be reproduced.
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,11 @@
 | 
			
		||||
# https://data.services.jetbrains.com/products?code=IC
 | 
			
		||||
# Maven releases are here: https://www.jetbrains.com/intellij-repository/releases
 | 
			
		||||
# And snapshots: https://www.jetbrains.com/intellij-repository/snapshots
 | 
			
		||||
ideaVersion=2024.1.1
 | 
			
		||||
ideaVersion=2024.2
 | 
			
		||||
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
 | 
			
		||||
ideaType=IC
 | 
			
		||||
instrumentPluginCode=true
 | 
			
		||||
version=SNAPSHOT
 | 
			
		||||
version=chylex-41
 | 
			
		||||
javaVersion=17
 | 
			
		||||
remoteRobotVersion=0.11.23
 | 
			
		||||
antlrVersion=4.10.1
 | 
			
		||||
@@ -47,7 +47,6 @@ youtrackToken=
 | 
			
		||||
 | 
			
		||||
# Gradle settings
 | 
			
		||||
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
 | 
			
		||||
org.gradle.configuration-cache=true
 | 
			
		||||
org.gradle.caching=true
 | 
			
		||||
 | 
			
		||||
# Disable warning from gradle-intellij-plugin. Kotlin stdlib is included as compileOnly, so the warning is unnecessary
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@ exclude:
 | 
			
		||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/JavaText.kt
 | 
			
		||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/LoremText.kt
 | 
			
		||||
      - src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
 | 
			
		||||
      - src/main/java/com/maddyhome/idea/vim/package-info.java
 | 
			
		||||
      - vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
 | 
			
		||||
      - vim-engine/src/main/java/com/maddyhome/idea/vim/parser/generated
 | 
			
		||||
      - src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,10 @@
 | 
			
		||||
 | 
			
		||||
package com.maddyhome.idea.vim
 | 
			
		||||
 | 
			
		||||
import com.intellij.ide.BrowserUtil
 | 
			
		||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
 | 
			
		||||
import com.intellij.ide.plugins.PluginStateListener
 | 
			
		||||
import com.intellij.ide.plugins.PluginStateManager
 | 
			
		||||
import com.intellij.openapi.application.ApplicationManager
 | 
			
		||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
			
		||||
import com.intellij.openapi.project.Project
 | 
			
		||||
@@ -40,6 +44,18 @@ internal class PluginStartup : ProjectActivity/*, LightEditCompatible*/ {
 | 
			
		||||
 | 
			
		||||
    // This code should be executed once
 | 
			
		||||
    VimPlugin.getInstance().initialize()
 | 
			
		||||
 | 
			
		||||
    // Uninstall survey. Should be registered once for all projects
 | 
			
		||||
    PluginStateManager.addStateListener(object : PluginStateListener {
 | 
			
		||||
      override fun install(p0: IdeaPluginDescriptor) {/*Nothing*/
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      override fun uninstall(descriptor: IdeaPluginDescriptor) {
 | 
			
		||||
        if (descriptor.pluginId == VimPlugin.getPluginId()) {
 | 
			
		||||
          BrowserUtil.open("https://surveys.jetbrains.com/s3/ideavim-uninstall-feedback")
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package com.maddyhome.idea.vim.action
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
			
		||||
import com.intellij.openapi.actionSystem.AnActionEvent
 | 
			
		||||
import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
			
		||||
import com.intellij.openapi.command.WriteCommandAction
 | 
			
		||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
			
		||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
			
		||||
import com.intellij.openapi.project.DumbAwareAction
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
 | 
			
		||||
class VimRunLastMacroInOpenFiles : DumbAwareAction() {
 | 
			
		||||
  override fun update(e: AnActionEvent) {
 | 
			
		||||
    val lastRegister = injector.macro.lastRegister
 | 
			
		||||
    val isEnabled = lastRegister != 0.toChar()
 | 
			
		||||
 | 
			
		||||
    e.presentation.isEnabled = isEnabled
 | 
			
		||||
    e.presentation.text = if (isEnabled) "Run Macro '${lastRegister}' in Open Files" else "Run Last Macro in Open Files"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun getActionUpdateThread(): ActionUpdateThread {
 | 
			
		||||
    return ActionUpdateThread.EDT
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun actionPerformed(e: AnActionEvent) {
 | 
			
		||||
    val project = e.project ?: return
 | 
			
		||||
    val fileEditorManager = FileEditorManagerEx.getInstanceExIfCreated(project) ?: return
 | 
			
		||||
    val editors = fileEditorManager.allEditors.filterIsInstance<TextEditor>()
 | 
			
		||||
    
 | 
			
		||||
    WriteCommandAction.writeCommandAction(project)
 | 
			
		||||
      .withName(e.presentation.text)
 | 
			
		||||
      .withGlobalUndo()
 | 
			
		||||
      .withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION)
 | 
			
		||||
      .run<RuntimeException> {
 | 
			
		||||
        val reg = injector.macro.lastRegister
 | 
			
		||||
        
 | 
			
		||||
        for (editor in editors) {
 | 
			
		||||
          fileEditorManager.openFile(editor.file, true)
 | 
			
		||||
          
 | 
			
		||||
          val vimEditor = editor.editor.vim
 | 
			
		||||
          vimEditor.mode = Mode.NORMAL()
 | 
			
		||||
          KeyHandler.getInstance().reset(vimEditor)
 | 
			
		||||
          
 | 
			
		||||
          injector.macro.playbackRegister(vimEditor, IjEditorExecutionContext(e.dataContext), reg, 1)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -37,7 +37,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
 | 
			
		||||
 | 
			
		||||
// todo make it multicaret
 | 
			
		||||
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
 | 
			
		||||
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, motionType: SelectionType): Boolean {
 | 
			
		||||
  val func = injector.globalOptions().operatorfunc
 | 
			
		||||
  if (func.isEmpty()) {
 | 
			
		||||
    VimPlugin.showMessage(MessageHelper.message("E774"))
 | 
			
		||||
@@ -57,9 +57,9 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
 | 
			
		||||
        if (value is VimFuncref) {
 | 
			
		||||
          handler = value.handler
 | 
			
		||||
        }
 | 
			
		||||
      } catch (ex: ExException) {
 | 
			
		||||
      } catch (_: ExException) {
 | 
			
		||||
        // Get the argument for function('...') or funcref('...') for the error message
 | 
			
		||||
        val functionName = if (expression is FunctionCallExpression && expression.arguments.size > 0) {
 | 
			
		||||
        val functionName = if (expression is FunctionCallExpression && expression.arguments.isNotEmpty()) {
 | 
			
		||||
          expression.arguments[0].evaluate(editor, context, scriptContext).toString()
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
@@ -77,7 +77,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val arg = when (selectionType) {
 | 
			
		||||
  val arg = when (motionType) {
 | 
			
		||||
    SelectionType.LINE_WISE -> "line"
 | 
			
		||||
    SelectionType.CHARACTER_WISE -> "char"
 | 
			
		||||
    SelectionType.BLOCK_WISE -> "block"
 | 
			
		||||
@@ -101,19 +101,13 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
			
		||||
  override val argumentType: Argument.Type = Argument.Type.MOTION
 | 
			
		||||
 | 
			
		||||
  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
			
		||||
    val argument = cmd.argument ?: return false
 | 
			
		||||
    val argument = cmd.argument as? Argument.Motion ?: return false
 | 
			
		||||
    if (!editor.inRepeatMode) {
 | 
			
		||||
      argumentCaptured = argument
 | 
			
		||||
    }
 | 
			
		||||
    val range = getMotionRange(editor, context, argument, operatorArguments)
 | 
			
		||||
 | 
			
		||||
    if (range != null) {
 | 
			
		||||
      val selectionType = if (argument.motion.isLinewiseMotion()) {
 | 
			
		||||
        SelectionType.LINE_WISE
 | 
			
		||||
      } else {
 | 
			
		||||
        SelectionType.CHARACTER_WISE
 | 
			
		||||
      }
 | 
			
		||||
      return doOperatorAction(editor, context, range, selectionType)
 | 
			
		||||
      return doOperatorAction(editor, context, range, argument.getMotionType())
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
@@ -121,7 +115,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
			
		||||
  private fun getMotionRange(
 | 
			
		||||
    editor: VimEditor,
 | 
			
		||||
    context: ExecutionContext,
 | 
			
		||||
    argument: Argument,
 | 
			
		||||
    argument: Argument.Motion,
 | 
			
		||||
    operatorArguments: OperatorArguments,
 | 
			
		||||
  ): TextRange? {
 | 
			
		||||
    // Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
 | 
			
		||||
@@ -136,7 +130,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
 | 
			
		||||
      operatorArguments,
 | 
			
		||||
    )?.normalize()?.let {
 | 
			
		||||
      // If we're linewise, make sure the end offset isn't just the EOL char
 | 
			
		||||
      if (argument.motion.isLinewiseMotion() && it.endOffset < editor.fileSize()) {
 | 
			
		||||
      if (argument.getMotionType() == SelectionType.LINE_WISE && it.endOffset < editor.fileSize()) {
 | 
			
		||||
        TextRange(it.startOffset, it.endOffset + 1)
 | 
			
		||||
      } else {
 | 
			
		||||
        it
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
			
		||||
 | 
			
		||||
  override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
 | 
			
		||||
    val state = injector.vimState
 | 
			
		||||
    val lastCommand = VimRepeater.lastChangeCommand
 | 
			
		||||
    var lastCommand = VimRepeater.lastChangeCommand
 | 
			
		||||
 | 
			
		||||
    if (lastCommand == null && Extension.lastExtensionHandler == null) return false
 | 
			
		||||
 | 
			
		||||
@@ -57,12 +57,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
 | 
			
		||||
      )
 | 
			
		||||
    } else if (!repeatHandler && lastCommand != null) {
 | 
			
		||||
      if (cmd.rawCount > 0) {
 | 
			
		||||
        lastCommand.rawCount = cmd.count
 | 
			
		||||
        val arg = lastCommand.argument
 | 
			
		||||
        if (arg != null) {
 | 
			
		||||
          val mot = arg.motion
 | 
			
		||||
          mot.rawCount = 0
 | 
			
		||||
        }
 | 
			
		||||
        lastCommand = lastCommand.copy(rawCount = cmd.rawCount)
 | 
			
		||||
      }
 | 
			
		||||
      state.executingCommand = lastCommand
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.ConditionalSingleExecuti
 | 
			
		||||
  ): Boolean {
 | 
			
		||||
    injector.editorGroup.notifyIdeaJoin(editor)
 | 
			
		||||
 | 
			
		||||
    return injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)
 | 
			
		||||
    return injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun execute(
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
 | 
			
		||||
    injector.editorGroup.notifyIdeaJoin(editor)
 | 
			
		||||
    var res = true
 | 
			
		||||
    editor.nativeCarets().sortedByDescending { it.offset }.forEach { caret ->
 | 
			
		||||
      if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) {
 | 
			
		||||
      if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true)) {
 | 
			
		||||
        res = false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,6 @@ import com.maddyhome.idea.vim.handler.VimActionHandler
 | 
			
		||||
import com.maddyhome.idea.vim.helper.enumSetOf
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
@CommandOrMotion(keys = ["<C-H>", "<BS>"], modes = [Mode.INSERT])
 | 
			
		||||
internal class VimEditorBackSpace : IdeActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE) {
 | 
			
		||||
  override val type: Command.Type = Command.Type.DELETE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@CommandOrMotion(keys = ["<Del>"], modes = [Mode.INSERT])
 | 
			
		||||
internal class VimEditorDelete : IdeActionHandler(IdeActions.ACTION_EDITOR_DELETE) {
 | 
			
		||||
  override val type: Command.Type = Command.Type.DELETE
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,8 @@ object VimExtensionFacade {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @JvmStatic
 | 
			
		||||
  @Deprecated("Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
			
		||||
  @Deprecated(
 | 
			
		||||
    "Use VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
			
		||||
    ReplaceWith(
 | 
			
		||||
      "VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)",
 | 
			
		||||
      "com.maddyhome.idea.vim.VimPlugin"
 | 
			
		||||
@@ -195,7 +196,7 @@ object VimExtensionFacade {
 | 
			
		||||
 | 
			
		||||
  @JvmStatic
 | 
			
		||||
  fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
 | 
			
		||||
    val reg = caret.registerStorage.getRegister(register) ?: return null
 | 
			
		||||
    val reg = injector.registerGroup.getRegister(register) ?: return null
 | 
			
		||||
    return reg.keys
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -208,7 +209,7 @@ object VimExtensionFacade {
 | 
			
		||||
  /** Set the current contents of the given register */
 | 
			
		||||
  @JvmStatic
 | 
			
		||||
  fun setRegisterForCaret(register: Char, caret: ImmutableVimCaret, keys: List<KeyStroke?>?) {
 | 
			
		||||
    caret.registerStorage.setKeys(register, keys?.filterNotNull() ?: emptyList())
 | 
			
		||||
    injector.registerGroup.setKeys(register, keys?.filterNotNull() ?: emptyList())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Set the current contents of the given register */
 | 
			
		||||
@@ -277,4 +278,4 @@ fun VimExtensionFacade.exportOperatorFunction(name: String, function: OperatorFu
 | 
			
		||||
 | 
			
		||||
fun interface ScriptFunction {
 | 
			
		||||
  fun execute(editor: VimEditor, context: ExecutionContext, args: Map<String, VimDataType>): ExecutionResult
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,6 @@ import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayDeque;
 | 
			
		||||
import java.util.Deque;
 | 
			
		||||
import java.util.EnumSet;
 | 
			
		||||
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
			
		||||
@@ -64,8 +63,8 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
   */
 | 
			
		||||
  private static class BracketPairs {
 | 
			
		||||
    // NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
 | 
			
		||||
    @NotNull private final String openBrackets;
 | 
			
		||||
    @NotNull private final String closeBrackets;
 | 
			
		||||
    private final @NotNull String openBrackets;
 | 
			
		||||
    private final @NotNull String closeBrackets;
 | 
			
		||||
 | 
			
		||||
    static class ParseException extends Exception {
 | 
			
		||||
      public ParseException(@NotNull String message) {
 | 
			
		||||
@@ -87,8 +86,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
     * @param bracketPairs comma-separated list of colon-separated bracket pairs.
 | 
			
		||||
     * @throws ParseException if a syntax error is detected.
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseException {
 | 
			
		||||
    static @NotNull BracketPairs fromBracketPairList(final @NotNull String bracketPairs) throws ParseException {
 | 
			
		||||
      StringBuilder openBrackets = new StringBuilder();
 | 
			
		||||
      StringBuilder closeBrackets = new StringBuilder();
 | 
			
		||||
      ParseState state = ParseState.OPEN;
 | 
			
		||||
@@ -128,7 +126,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
      return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BracketPairs(@NotNull final String openBrackets, @NotNull final String closeBrackets) {
 | 
			
		||||
    BracketPairs(final @NotNull String openBrackets, final @NotNull String closeBrackets) {
 | 
			
		||||
      assert openBrackets.length() == closeBrackets.length();
 | 
			
		||||
      this.openBrackets = openBrackets;
 | 
			
		||||
      this.closeBrackets = closeBrackets;
 | 
			
		||||
@@ -158,10 +156,9 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
 | 
			
		||||
  private static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  private static String bracketPairsVariable() {
 | 
			
		||||
  private static @Nullable String bracketPairsVariable() {
 | 
			
		||||
    final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
 | 
			
		||||
    if (value instanceof VimString vimValue) {
 | 
			
		||||
      return vimValue.getValue();
 | 
			
		||||
@@ -192,13 +189,12 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
        this.isInner = isInner;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Nullable
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                @NotNull ExecutionContext context,
 | 
			
		||||
                                int count,
 | 
			
		||||
                                int rawCount) {
 | 
			
		||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                          @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                          @NotNull ExecutionContext context,
 | 
			
		||||
                                          int count,
 | 
			
		||||
                                          int rawCount) {
 | 
			
		||||
        BracketPairs bracketPairs = DEFAULT_BRACKET_PAIRS;
 | 
			
		||||
        final String bracketPairsVar = bracketPairsVariable();
 | 
			
		||||
        if (bracketPairsVar != null) {
 | 
			
		||||
@@ -236,24 +232,22 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
        return new TextRange(finder.getLeftBound(), finder.getRightBound());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @NotNull
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextObjectVisualType getVisualType() {
 | 
			
		||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
			
		||||
        return TextObjectVisualType.CHARACTER_WISE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
			
		||||
      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
			
		||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
			
		||||
      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
			
		||||
 | 
			
		||||
      final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
 | 
			
		||||
      //noinspection DuplicatedCode
 | 
			
		||||
      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
			
		||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
			
		||||
        int count0 = operatorArguments.getCount0();
 | 
			
		||||
        editor.nativeCarets().forEach((VimCaret caret) -> {
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(editor, caret, context, count, 0);
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(editor, caret, context, Math.max(1, count0), count0);
 | 
			
		||||
          if (range != null) {
 | 
			
		||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
			
		||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
			
		||||
@@ -265,8 +259,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
			
		||||
                                                                                         textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
 | 
			
		||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -276,9 +269,9 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
   * position
 | 
			
		||||
   */
 | 
			
		||||
  private static class ArgBoundsFinder {
 | 
			
		||||
    @NotNull private final CharSequence text;
 | 
			
		||||
    @NotNull private final Document document;
 | 
			
		||||
    @NotNull private final BracketPairs brackets;
 | 
			
		||||
    private final @NotNull CharSequence text;
 | 
			
		||||
    private final @NotNull Document document;
 | 
			
		||||
    private final @NotNull BracketPairs brackets;
 | 
			
		||||
    private int leftBound = Integer.MAX_VALUE;
 | 
			
		||||
    private int rightBound = Integer.MIN_VALUE;
 | 
			
		||||
    private int leftBracket;
 | 
			
		||||
@@ -305,7 +298,7 @@ public class VimArgTextObjExtension implements VimExtension {
 | 
			
		||||
     * @param position starting position.
 | 
			
		||||
     */
 | 
			
		||||
    boolean findBoundsAt(int position) throws IllegalStateException {
 | 
			
		||||
      if (text.length() == 0) {
 | 
			
		||||
      if (text.isEmpty()) {
 | 
			
		||||
        error = "empty document";
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -25,9 +25,6 @@ import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLineEndOffset
 | 
			
		||||
import com.maddyhome.idea.vim.api.globalOptions
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.command.Argument
 | 
			
		||||
import com.maddyhome.idea.vim.command.Command
 | 
			
		||||
import com.maddyhome.idea.vim.command.CommandFlags
 | 
			
		||||
import com.maddyhome.idea.vim.command.MappingMode
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.command.TextObjectVisualType
 | 
			
		||||
@@ -52,7 +49,6 @@ import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
internal class CommentaryExtension : VimExtension {
 | 
			
		||||
 | 
			
		||||
@@ -184,10 +180,8 @@ internal class CommentaryExtension : VimExtension {
 | 
			
		||||
    override val isRepeatable = true
 | 
			
		||||
 | 
			
		||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
			
		||||
      val command = Command(operatorArguments.count1, CommentaryTextObjectMotionHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags::class.java))
 | 
			
		||||
 | 
			
		||||
      val keyState = KeyHandler.getInstance().keyHandlerState
 | 
			
		||||
      keyState.commandBuilder.completeCommandPart(Argument(command))
 | 
			
		||||
      keyState.commandBuilder.addAction(CommentaryTextObjectMotionHandler)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,10 +21,7 @@ import com.intellij.openapi.editor.markup.TextAttributes
 | 
			
		||||
import com.intellij.openapi.util.Disposer
 | 
			
		||||
import com.intellij.util.Alarm
 | 
			
		||||
import com.intellij.util.Alarm.ThreadToUse
 | 
			
		||||
import com.jetbrains.rd.util.first
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.common.ModeChangeListener
 | 
			
		||||
@@ -117,9 +114,9 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
 | 
			
		||||
    initialised = false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun yankPerformed(caretToRange: Map<ImmutableVimCaret, TextRange>) {
 | 
			
		||||
  override fun yankPerformed(editor: VimEditor, range: TextRange) {
 | 
			
		||||
    ensureInitialised()
 | 
			
		||||
    highlightHandler.highlightYankRange(caretToRange)
 | 
			
		||||
    highlightHandler.highlightYankRange(editor.ij, range)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun modeChanged(editor: VimEditor, oldMode: Mode) {
 | 
			
		||||
@@ -140,25 +137,22 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
 | 
			
		||||
    private var lastEditor: Editor? = null
 | 
			
		||||
    private val highlighters = mutableSetOf<RangeHighlighter>()
 | 
			
		||||
 | 
			
		||||
    fun highlightYankRange(caretToRange: Map<ImmutableVimCaret, TextRange>) {
 | 
			
		||||
    fun highlightYankRange(editor: Editor, range: TextRange) {
 | 
			
		||||
      // from vim-highlightedyank docs: When a new text is yanked or user starts editing, the old highlighting would be deleted
 | 
			
		||||
      clearYankHighlighters()
 | 
			
		||||
 | 
			
		||||
      val editor = caretToRange.first().key.editor.ij
 | 
			
		||||
      lastEditor = editor
 | 
			
		||||
 | 
			
		||||
      val attributes = getHighlightTextAttributes(editor)
 | 
			
		||||
      for (range in caretToRange.values) {
 | 
			
		||||
        for (i in 0 until range.size()) {
 | 
			
		||||
          val highlighter = editor.markupModel.addRangeHighlighter(
 | 
			
		||||
            range.startOffsets[i],
 | 
			
		||||
            range.endOffsets[i],
 | 
			
		||||
            HighlighterLayer.SELECTION,
 | 
			
		||||
            attributes,
 | 
			
		||||
            HighlighterTargetArea.EXACT_RANGE,
 | 
			
		||||
          )
 | 
			
		||||
          highlighters.add(highlighter)
 | 
			
		||||
        }
 | 
			
		||||
      for (i in 0 until range.size()) {
 | 
			
		||||
        val highlighter = editor.markupModel.addRangeHighlighter(
 | 
			
		||||
          range.startOffsets[i],
 | 
			
		||||
          range.endOffsets[i],
 | 
			
		||||
          HighlighterLayer.SELECTION,
 | 
			
		||||
          attributes,
 | 
			
		||||
          HighlighterTargetArea.EXACT_RANGE,
 | 
			
		||||
        )
 | 
			
		||||
        highlighters.add(highlighter)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // from vim-highlightedyank docs: A negative number makes the highlight persistent.
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ import com.maddyhome.idea.vim.helper.enumSetOf
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.regex.Pattern
 | 
			
		||||
 | 
			
		||||
@@ -93,34 +94,29 @@ internal class Matchit : VimExtension {
 | 
			
		||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
			
		||||
      val keyHandler = KeyHandler.getInstance()
 | 
			
		||||
      val keyState = keyHandler.keyHandlerState
 | 
			
		||||
      val count = keyState.commandBuilder.count
 | 
			
		||||
 | 
			
		||||
      // Reset the command count so it doesn't transfer onto subsequent commands.
 | 
			
		||||
      keyState.commandBuilder.resetCount()
 | 
			
		||||
 | 
			
		||||
      // Normally we want to jump to the start of the matching pair. But when moving forward in operator
 | 
			
		||||
      // pending mode, we want to include the entire match. isInOpPending makes that distinction.
 | 
			
		||||
      val isInOpPending = keyHandler.isOperatorPending(editor.mode, keyState)
 | 
			
		||||
 | 
			
		||||
      if (isInOpPending) {
 | 
			
		||||
      if (editor.mode is Mode.OP_PENDING) {
 | 
			
		||||
        val matchitAction = MatchitAction()
 | 
			
		||||
        matchitAction.reverse = reverse
 | 
			
		||||
        matchitAction.isInOpPending = true
 | 
			
		||||
 | 
			
		||||
        keyState.commandBuilder.completeCommandPart(
 | 
			
		||||
          Argument(
 | 
			
		||||
            Command(
 | 
			
		||||
              count,
 | 
			
		||||
              matchitAction,
 | 
			
		||||
              Command.Type.MOTION,
 | 
			
		||||
              EnumSet.noneOf(CommandFlags::class.java),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        )
 | 
			
		||||
        keyState.commandBuilder.addAction(matchitAction)
 | 
			
		||||
      } else {
 | 
			
		||||
        editor.sortedCarets().forEach { caret ->
 | 
			
		||||
          injector.jumpService.saveJumpLocation(editor)
 | 
			
		||||
          caret.moveToOffset(getMatchitOffset(editor.ij, caret.ij, count, isInOpPending, reverse))
 | 
			
		||||
          caret.moveToOffset(
 | 
			
		||||
            getMatchitOffset(
 | 
			
		||||
              editor.ij,
 | 
			
		||||
              caret.ij,
 | 
			
		||||
              operatorArguments.count0,
 | 
			
		||||
              isInOpPending = false,
 | 
			
		||||
              reverse
 | 
			
		||||
            ))
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -234,7 +230,7 @@ private object FileTypePatterns {
 | 
			
		||||
    } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
 | 
			
		||||
      this.cMakePatterns
 | 
			
		||||
    } else {
 | 
			
		||||
      return null
 | 
			
		||||
      this.htmlPatterns
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -354,7 +350,7 @@ private object FileTypePatterns {
 | 
			
		||||
 | 
			
		||||
private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')
 | 
			
		||||
 | 
			
		||||
private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPending: Boolean, reverse: Boolean): Int {
 | 
			
		||||
private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPending: Boolean, reverse: Boolean): Int {
 | 
			
		||||
  val virtualFile = EditorHelper.getVirtualFile(editor)
 | 
			
		||||
  var caretOffset = caret.offset
 | 
			
		||||
 | 
			
		||||
@@ -367,9 +363,9 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPen
 | 
			
		||||
  val currentChar = editor.document.charsSequence[caretOffset]
 | 
			
		||||
  var motionOffset: Int? = null
 | 
			
		||||
 | 
			
		||||
  if (count > 0) {
 | 
			
		||||
  if (count0 > 0) {
 | 
			
		||||
    // Matchit doesn't affect the percent motion, so we fall back to the default behavior.
 | 
			
		||||
    motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count)
 | 
			
		||||
    motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count0)
 | 
			
		||||
  } else {
 | 
			
		||||
    // Check the simplest case first.
 | 
			
		||||
    if (DEFAULT_PAIRS.contains(currentChar)) {
 | 
			
		||||
@@ -400,8 +396,7 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPen
 | 
			
		||||
 | 
			
		||||
private fun getMotionOffset(motion: Motion): Int? {
 | 
			
		||||
  return when (motion) {
 | 
			
		||||
    is Motion.AbsoluteOffset -> motion.offset
 | 
			
		||||
    is Motion.AdjustedOffset -> motion.offset
 | 
			
		||||
    is Motion.AdjustedOffset, is Motion.AbsoluteOffset -> motion.offset
 | 
			
		||||
    is Motion.Error, is Motion.NoMotion -> null
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -555,12 +555,13 @@ private fun registerCommand(default: String, action: NerdAction) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private val actionsRoot: RootNode<NerdAction> = RootNode()
 | 
			
		||||
private val actionsRoot: RootNode<NerdAction> = RootNode("NERDTree")
 | 
			
		||||
private var currentNode: CommandPartNode<NerdAction> = actionsRoot
 | 
			
		||||
 | 
			
		||||
private fun collectShortcuts(node: Node<NerdAction>): Set<KeyStroke> {
 | 
			
		||||
  return if (node is CommandPartNode<NerdAction>) {
 | 
			
		||||
    val res = node.keys.toMutableSet()
 | 
			
		||||
    res += node.values.map { collectShortcuts(it) }.flatten()
 | 
			
		||||
    val res = node.children.keys.toMutableSet()
 | 
			
		||||
    res += node.children.values.map { collectShortcuts(it) }.flatten()
 | 
			
		||||
    res
 | 
			
		||||
  } else {
 | 
			
		||||
    emptySet()
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ package com.maddyhome.idea.vim.extension.replacewithregister
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.actionSystem.DataContext
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
			
		||||
@@ -144,7 +143,7 @@ internal class ReplaceWithRegister : VimExtension {
 | 
			
		||||
private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
 | 
			
		||||
  val registerGroup = injector.registerGroup
 | 
			
		||||
  val lastRegisterChar = if (editor.caretModel.caretCount == 1) registerGroup.currentRegister else registerGroup.getCurrentRegisterForMulticaret()
 | 
			
		||||
  val savedRegister = caret.registerStorage.getRegister(lastRegisterChar) ?: return
 | 
			
		||||
  val savedRegister = registerGroup.getRegister(lastRegisterChar) ?: return
 | 
			
		||||
 | 
			
		||||
  var usedType = savedRegister.type
 | 
			
		||||
  var usedText = savedRegister.text
 | 
			
		||||
@@ -166,18 +165,12 @@ private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimC
 | 
			
		||||
    putToLine = -1,
 | 
			
		||||
  )
 | 
			
		||||
  val vimEditor = editor.vim
 | 
			
		||||
  val keyHandler = KeyHandler.getInstance()
 | 
			
		||||
  ClipboardOptionHelper.IdeaputDisabler().use {
 | 
			
		||||
    VimPlugin.getPut().putText(
 | 
			
		||||
      vimEditor,
 | 
			
		||||
      context.vim,
 | 
			
		||||
      putData,
 | 
			
		||||
      operatorArguments = OperatorArguments(
 | 
			
		||||
        keyHandler.isOperatorPending(vimEditor.mode, keyHandler.keyHandlerState),
 | 
			
		||||
        0,
 | 
			
		||||
        editor.vim.mode,
 | 
			
		||||
      ),
 | 
			
		||||
      saveToRegister = false
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,6 +14,7 @@ import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimChangeGroup
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.endsWithNewLine
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
 | 
			
		||||
@@ -36,7 +37,10 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
 | 
			
		||||
import com.maddyhome.idea.vim.extension.exportOperatorFunction
 | 
			
		||||
import com.maddyhome.idea.vim.group.findBlockRange
 | 
			
		||||
import com.maddyhome.idea.vim.helper.exitVisualMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
 | 
			
		||||
import com.maddyhome.idea.vim.key.OperatorFunction
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
 | 
			
		||||
@@ -80,7 +84,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
			
		||||
      putKeyMappingIfMissing(MappingMode.XO, injector.parser.parseKeys("S"), owner, injector.parser.parseKeys("<Plug>VSurround"), true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator())
 | 
			
		||||
    VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator(supportsMultipleCursors = false, count = 1)) // TODO
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private class YSurroundHandler : ExtensionHandler {
 | 
			
		||||
@@ -108,7 +112,7 @@ internal class VimSurroundExtension : VimExtension {
 | 
			
		||||
        val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
 | 
			
		||||
        if (lastNonWhiteSpaceOffset != null) {
 | 
			
		||||
          val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
 | 
			
		||||
          performSurround(pair, range, it)
 | 
			
		||||
          performSurround(pair, range, it, count = operatorArguments.count1)
 | 
			
		||||
        }
 | 
			
		||||
//        it.moveToOffset(lineStartOffset)
 | 
			
		||||
      }
 | 
			
		||||
@@ -131,15 +135,13 @@ internal class VimSurroundExtension : VimExtension {
 | 
			
		||||
 | 
			
		||||
  private class VSurroundHandler : ExtensionHandler {
 | 
			
		||||
    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
			
		||||
      val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart
 | 
			
		||||
      // NB: Operator ignores SelectionType anyway
 | 
			
		||||
      if (!Operator().apply(editor, context, editor.mode.selectionType)) {
 | 
			
		||||
      if (!Operator(supportsMultipleCursors = true, count = operatorArguments.count1).apply(editor, context, editor.mode.selectionType)) {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      runWriteAction {
 | 
			
		||||
        // Leave visual mode
 | 
			
		||||
        editor.exitVisualMode()
 | 
			
		||||
        editor.ij.caretModel.moveToOffset(selectionStart)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -160,6 +162,10 @@ internal class VimSurroundExtension : VimExtension {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
      fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
 | 
			
		||||
        editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
 | 
			
		||||
        // Save old register values for carets
 | 
			
		||||
        val surroundings = editor.sortedCarets()
 | 
			
		||||
          .map {
 | 
			
		||||
@@ -267,20 +273,41 @@ internal class VimSurroundExtension : VimExtension {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private class Operator : OperatorFunction {
 | 
			
		||||
    override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
 | 
			
		||||
      val ijEditor = editor.ij
 | 
			
		||||
  private class Operator(private val supportsMultipleCursors: Boolean, private val count: Int) : OperatorFunction {
 | 
			
		||||
    override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
 | 
			
		||||
      val ijEditor = vimEditor.ij
 | 
			
		||||
      val c = getChar(ijEditor)
 | 
			
		||||
      if (c.code == 0) return true
 | 
			
		||||
 | 
			
		||||
      val pair = getOrInputPair(c, ijEditor, context.ij) ?: return false
 | 
			
		||||
      // XXX: Will it work with line-wise or block-wise selections?
 | 
			
		||||
      val range = getSurroundRange(editor.currentCaret()) ?: return false
 | 
			
		||||
      performSurround(pair, range, editor.currentCaret(), selectionType == SelectionType.LINE_WISE)
 | 
			
		||||
      // Jump back to start
 | 
			
		||||
      executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
 | 
			
		||||
 | 
			
		||||
      runWriteAction {
 | 
			
		||||
        val change = VimPlugin.getChange()
 | 
			
		||||
        if (supportsMultipleCursors) {
 | 
			
		||||
          ijEditor.runWithEveryCaretAndRestore {
 | 
			
		||||
            applyOnce(ijEditor, change, pair, count)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          applyOnce(ijEditor, change, pair, count)
 | 
			
		||||
          // Jump back to start
 | 
			
		||||
          executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return true
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
 | 
			
		||||
      // XXX: Will it work with line-wise or block-wise selections?
 | 
			
		||||
      val primaryCaret = editor.caretModel.primaryCaret
 | 
			
		||||
      val range = getSurroundRange(primaryCaret.vim)
 | 
			
		||||
      if (range != null) {
 | 
			
		||||
        val start = RepeatedCharSequence.of(pair.first, count)
 | 
			
		||||
        val end = RepeatedCharSequence.of(pair.second, count)
 | 
			
		||||
        change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, start)
 | 
			
		||||
        change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + start.length, end)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getSurroundRange(caret: VimCaret): TextRange? {
 | 
			
		||||
      val editor = caret.editor
 | 
			
		||||
@@ -375,15 +402,15 @@ private fun getChar(editor: Editor): Char {
 | 
			
		||||
  return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
    val editor = caret.editor
 | 
			
		||||
    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 hasNewLine = editor.endsWithNewLine()
 | 
			
		||||
    val rightSurround = if (tagsOnNewLines) {
 | 
			
		||||
    val rightSurround = (if (tagsOnNewLines) {
 | 
			
		||||
      if (isEOF && !hasNewLine) {
 | 
			
		||||
        "\n" + pair.second
 | 
			
		||||
      } else {
 | 
			
		||||
@@ -391,7 +418,7 @@ private fun performSurround(pair: Pair<String, String>, range: TextRange, caret:
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      pair.second
 | 
			
		||||
    }
 | 
			
		||||
    }).let { RepeatedCharSequence.of(it, count) }
 | 
			
		||||
 | 
			
		||||
    change.insertText(editor, caret, range.startOffset, leftSurround)
 | 
			
		||||
    change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,14 +29,12 @@ import com.maddyhome.idea.vim.state.mode.Mode;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.EnumSet;
 | 
			
		||||
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Port of vim-entire:
 | 
			
		||||
 * https://github.com/kana/vim-textobj-entire
 | 
			
		||||
 * <a href="https://github.com/kana/vim-textobj-entire">vim-textobj-entire</a>
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * vim-textobj-entire provides two text objects:
 | 
			
		||||
@@ -51,7 +49,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingI
 | 
			
		||||
 * </ul>
 | 
			
		||||
 *
 | 
			
		||||
 * See also the reference manual for more details at:
 | 
			
		||||
 * https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt
 | 
			
		||||
 * <a href="https://github.com/kana/vim-textobj-entire/blob/master/doc/textobj-entire.txt">text-obj-entire.txt</a>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Alexandre Grison (@agrison)
 | 
			
		||||
 */
 | 
			
		||||
@@ -94,13 +92,12 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
			
		||||
        this.ignoreLeadingAndTrailing = ignoreLeadingAndTrailing;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Nullable
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                @NotNull ExecutionContext context,
 | 
			
		||||
                                int count,
 | 
			
		||||
                                int rawCount) {
 | 
			
		||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                          @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                          @NotNull ExecutionContext context,
 | 
			
		||||
                                          int count,
 | 
			
		||||
                                          int rawCount) {
 | 
			
		||||
        int start = 0, end = ((IjVimEditor)editor).getEditor().getDocument().getTextLength();
 | 
			
		||||
 | 
			
		||||
        // for the `ie` text object we don't want leading an trailing spaces
 | 
			
		||||
@@ -125,24 +122,22 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
			
		||||
        return new TextRange(start, end);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @NotNull
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextObjectVisualType getVisualType() {
 | 
			
		||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
			
		||||
        return TextObjectVisualType.CHARACTER_WISE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
			
		||||
      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
			
		||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
			
		||||
      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
			
		||||
 | 
			
		||||
      final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
 | 
			
		||||
      //noinspection DuplicatedCode
 | 
			
		||||
      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
			
		||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
			
		||||
        int count0 = operatorArguments.getCount0();
 | 
			
		||||
        ((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, count, 0);
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
 | 
			
		||||
          if (range != null) {
 | 
			
		||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
			
		||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
			
		||||
@@ -155,9 +150,7 @@ public class VimTextObjEntireExtension implements VimExtension {
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
			
		||||
                                                                                         textObjectHandler, Command.Type.MOTION,
 | 
			
		||||
                                                                                         EnumSet.noneOf(CommandFlags.class))));
 | 
			
		||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,14 +30,12 @@ import com.maddyhome.idea.vim.state.mode.Mode;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.EnumSet;
 | 
			
		||||
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
 | 
			
		||||
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Port of vim-indent-object:
 | 
			
		||||
 * https://github.com/michaeljsmith/vim-indent-object
 | 
			
		||||
 * <a href="https://github.com/michaeljsmith/vim-indent-object">vim-indent-object</a>
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * vim-indent-object provides these text objects based on the cursor line's indentation:
 | 
			
		||||
@@ -49,7 +47,7 @@ import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
 | 
			
		||||
 * </ul>
 | 
			
		||||
 *
 | 
			
		||||
 * See also the reference manual for more details at:
 | 
			
		||||
 * https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt
 | 
			
		||||
 * <a href="https://github.com/michaeljsmith/vim-indent-object/blob/master/doc/indent-object.txt">indent-object.txt</a>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shrikant Kandula (@sharat87)
 | 
			
		||||
 */
 | 
			
		||||
@@ -98,13 +96,12 @@ public class VimIndentObject implements VimExtension {
 | 
			
		||||
        this.includeBelow = includeBelow;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Nullable
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                @NotNull ExecutionContext context,
 | 
			
		||||
                                int count,
 | 
			
		||||
                                int rawCount) {
 | 
			
		||||
      public @Nullable TextRange getRange(@NotNull VimEditor editor,
 | 
			
		||||
                                          @NotNull ImmutableVimCaret caret,
 | 
			
		||||
                                          @NotNull ExecutionContext context,
 | 
			
		||||
                                          int count,
 | 
			
		||||
                                          int rawCount) {
 | 
			
		||||
        final CharSequence charSequence = ((IjVimEditor)editor).getEditor().getDocument().getCharsSequence();
 | 
			
		||||
        final int caretOffset = ((IjVimCaret)caret).getCaret().getOffset();
 | 
			
		||||
 | 
			
		||||
@@ -249,9 +246,8 @@ public class VimIndentObject implements VimExtension {
 | 
			
		||||
        return new TextRange(upperBoundaryOffset, lowerBoundaryOffset);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @NotNull
 | 
			
		||||
      @Override
 | 
			
		||||
      public TextObjectVisualType getVisualType() {
 | 
			
		||||
      public @NotNull TextObjectVisualType getVisualType() {
 | 
			
		||||
        return TextObjectVisualType.LINE_WISE;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -264,15 +260,14 @@ public class VimIndentObject implements VimExtension {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
 | 
			
		||||
      IjVimEditor vimEditor = (IjVimEditor)editor;
 | 
			
		||||
      @NotNull KeyHandler keyHandler = KeyHandler.getInstance();
 | 
			
		||||
      @NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
 | 
			
		||||
      int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());
 | 
			
		||||
 | 
			
		||||
      final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
 | 
			
		||||
 | 
			
		||||
      if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
 | 
			
		||||
      if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
 | 
			
		||||
        int count0 = operatorArguments.getCount0();
 | 
			
		||||
        ((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, count, 0);
 | 
			
		||||
          final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, Math.max(1, count0), count0);
 | 
			
		||||
          if (range != null) {
 | 
			
		||||
            try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
 | 
			
		||||
              if (editor.getMode() instanceof Mode.VISUAL) {
 | 
			
		||||
@@ -285,9 +280,7 @@ public class VimIndentObject implements VimExtension {
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
 | 
			
		||||
                                                                                         textObjectHandler, Command.Type.MOTION,
 | 
			
		||||
                                                                                         EnumSet.noneOf(CommandFlags.class))));
 | 
			
		||||
        keyHandlerState.getCommandBuilder().addAction(textObjectHandler);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,6 @@ import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
import kotlin.math.min
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides all the insert/replace related functionality
 | 
			
		||||
@@ -104,6 +103,11 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun processBackspace(editor: VimEditor, context: ExecutionContext) {
 | 
			
		||||
    injector.actionExecutor.executeAction(editor, name = IdeActions.ACTION_EDITOR_BACKSPACE, context = context)
 | 
			
		||||
    injector.scroll.scrollCaretIntoView(editor)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun restoreCursor(editor: VimEditor, caret: VimCaret, startLine: Int) {
 | 
			
		||||
    if (caret != editor.primaryCaret()) {
 | 
			
		||||
      (editor as IjVimEditor).editor.caretModel.addCaret(
 | 
			
		||||
@@ -125,6 +129,7 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
			
		||||
    context: ExecutionContext,
 | 
			
		||||
    range: TextRange,
 | 
			
		||||
  ) {
 | 
			
		||||
    val startPos = editor.offsetToBufferPosition(caret.offset)
 | 
			
		||||
    val startOffset = editor.getLineStartForOffset(range.startOffset)
 | 
			
		||||
    val endOffset = editor.getLineEndForOffset(range.endOffset)
 | 
			
		||||
    val ijEditor = (editor as IjVimEditor).editor
 | 
			
		||||
@@ -149,11 +154,7 @@ class ChangeGroup : VimChangeGroupBase() {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    val afterAction = {
 | 
			
		||||
      val firstLine = editor.offsetToBufferPosition(
 | 
			
		||||
        min(startOffset.toDouble(), endOffset.toDouble()).toInt()
 | 
			
		||||
      ).line
 | 
			
		||||
      val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
 | 
			
		||||
      caret.moveToOffset(newOffset)
 | 
			
		||||
      caret.moveToOffset(injector.motion.moveCaretToLineStartSkipLeading(editor, startPos.line))
 | 
			
		||||
      restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
 | 
			
		||||
    }
 | 
			
		||||
    if (project != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,11 +11,14 @@ package com.maddyhome.idea.vim.group;
 | 
			
		||||
import com.intellij.openapi.diagnostic.Logger;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimDigraphGroupBase;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimOutputPanel;
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
			
		||||
import com.maddyhome.idea.vim.helper.EditorHelper;
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
 | 
			
		||||
 | 
			
		||||
public class DigraphGroup extends VimDigraphGroupBase {
 | 
			
		||||
 | 
			
		||||
  public void showDigraphs(@NotNull VimEditor editor) {
 | 
			
		||||
@@ -71,7 +74,9 @@ public class DigraphGroup extends VimDigraphGroupBase {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ExOutputModel.getInstance(((IjVimEditor) editor).getEditor()).output(res.toString());
 | 
			
		||||
    VimOutputPanel output = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
 | 
			
		||||
    output.addText(res.toString(), true );
 | 
			
		||||
    output.show();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static final Logger logger = Logger.getInstance(DigraphGroup.class.getName());
 | 
			
		||||
 
 | 
			
		||||
@@ -374,9 +374,9 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
 | 
			
		||||
          if (activeCommandLine != null) {
 | 
			
		||||
            activeCommandLine.close(true, false);
 | 
			
		||||
          }
 | 
			
		||||
          ExOutputModel exOutputModel = ExOutputModel.tryGetInstance(editor);
 | 
			
		||||
          if (exOutputModel != null) {
 | 
			
		||||
            exOutputModel.close();
 | 
			
		||||
          VimOutputPanel outputPanel = injector.getOutputPanel().getCurrentOutputPanel();
 | 
			
		||||
          if (outputPanel != null) {
 | 
			
		||||
            outputPanel.close();
 | 
			
		||||
          }
 | 
			
		||||
          VimModalInput modalInput = injector.getModalInput().getCurrentModalInput();
 | 
			
		||||
          if (modalInput != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ import com.intellij.openapi.components.State;
 | 
			
		||||
import com.intellij.openapi.components.Storage;
 | 
			
		||||
import com.intellij.openapi.diagnostic.Logger;
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
			
		||||
import com.maddyhome.idea.vim.history.HistoryBlock;
 | 
			
		||||
import com.maddyhome.idea.vim.history.HistoryEntry;
 | 
			
		||||
import com.maddyhome.idea.vim.history.VimHistoryBase;
 | 
			
		||||
import com.maddyhome.idea.vim.history.*;
 | 
			
		||||
import org.jdom.Element;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
@@ -35,21 +33,20 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
			
		||||
    logger.debug("saveData");
 | 
			
		||||
    Element hist = new Element("history");
 | 
			
		||||
 | 
			
		||||
    saveData(hist, SEARCH);
 | 
			
		||||
    saveData(hist, COMMAND);
 | 
			
		||||
    saveData(hist, EXPRESSION);
 | 
			
		||||
    saveData(hist, INPUT);
 | 
			
		||||
    for (Type type : getHistories().keySet()) {
 | 
			
		||||
      saveData(hist, type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    element.addContent(hist);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void saveData(@NotNull Element element, String key) {
 | 
			
		||||
    final HistoryBlock block = getHistories().get(key);
 | 
			
		||||
  private void saveData(@NotNull Element element, VimHistory.Type type) {
 | 
			
		||||
    final HistoryBlock block = getHistories().get(type);
 | 
			
		||||
    if (block == null) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final Element root = new Element("history-" + key);
 | 
			
		||||
    final Element root = new Element("history-" + typeToKey(type));
 | 
			
		||||
 | 
			
		||||
    for (HistoryEntry entry : block.getEntries()) {
 | 
			
		||||
      final Element entryElement = new Element("entry");
 | 
			
		||||
@@ -67,10 +64,10 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    readData(hist, SEARCH);
 | 
			
		||||
    readData(hist, COMMAND);
 | 
			
		||||
    readData(hist, EXPRESSION);
 | 
			
		||||
    readData(hist, INPUT);
 | 
			
		||||
    for (Element child : hist.getChildren()) {
 | 
			
		||||
      String key = child.getName().replace("history-", "");
 | 
			
		||||
      readData(hist, key);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void readData(@NotNull Element element, String key) {
 | 
			
		||||
@@ -80,7 +77,7 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block = new HistoryBlock();
 | 
			
		||||
    getHistories().put(key, block);
 | 
			
		||||
    getHistories().put(getTypeForString(key), block);
 | 
			
		||||
 | 
			
		||||
    final Element root = element.getChild("history-" + key);
 | 
			
		||||
    if (root != null) {
 | 
			
		||||
@@ -94,6 +91,25 @@ public class HistoryGroup extends VimHistoryBase implements PersistentStateCompo
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private String typeToKey(VimHistory.Type type) {
 | 
			
		||||
    if (type instanceof VimHistory.Type.Search) {
 | 
			
		||||
      return SEARCH;
 | 
			
		||||
    }
 | 
			
		||||
    if (type instanceof VimHistory.Type.Command) {
 | 
			
		||||
      return COMMAND;
 | 
			
		||||
    }
 | 
			
		||||
    if (type instanceof VimHistory.Type.Expression) {
 | 
			
		||||
      return EXPRESSION;
 | 
			
		||||
    }
 | 
			
		||||
    if (type instanceof VimHistory.Type.Input) {
 | 
			
		||||
      return INPUT;
 | 
			
		||||
    }
 | 
			
		||||
    if (type instanceof VimHistory.Type.Custom) {
 | 
			
		||||
      return ((Type.Custom) type).getId();
 | 
			
		||||
    }
 | 
			
		||||
    return "unreachable";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  @Override
 | 
			
		||||
  public Element getState() {
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@ object IjOptions {
 | 
			
		||||
  // Temporary feature flags during development, not really intended for external use
 | 
			
		||||
  val closenotebooks: ToggleOption = addOption(ToggleOption("closenotebooks", GLOBAL, "closenotebooks", true, isHidden = true))
 | 
			
		||||
  val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isHidden = true))
 | 
			
		||||
  val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", false, isHidden = true))
 | 
			
		||||
  val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", true, isHidden = true))
 | 
			
		||||
  val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true, isHidden = true))
 | 
			
		||||
  val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isHidden = true))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,7 @@ import com.maddyhome.idea.vim.EventFacade;
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
			
		||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
			
		||||
import com.maddyhome.idea.vim.action.change.LazyVimCommand;
 | 
			
		||||
import com.maddyhome.idea.vim.api.NativeAction;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimInjectorKt;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
 | 
			
		||||
import com.maddyhome.idea.vim.api.*;
 | 
			
		||||
import com.maddyhome.idea.vim.command.MappingMode;
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel;
 | 
			
		||||
import com.maddyhome.idea.vim.key.*;
 | 
			
		||||
@@ -80,25 +77,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
			
		||||
                                                          ((IjVimEditor)editor).getEditor().getComponent());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull Editor editor) {
 | 
			
		||||
    List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
 | 
			
		||||
    final StringBuilder builder = new StringBuilder();
 | 
			
		||||
    for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
 | 
			
		||||
      MappingInfo mappingInfo = row.getSecond();
 | 
			
		||||
      builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(mappingInfo.isRecursive() ? " " : "*");
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(mappingInfo.getPresentableString());
 | 
			
		||||
      builder.append("\n");
 | 
			
		||||
    }
 | 
			
		||||
    ExOutputModel.getInstance(editor).output(builder.toString());
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void updateShortcutKeysRegistration() {
 | 
			
		||||
    for (VimEditor editor : injector.getEditorGroup().getEditors()) {
 | 
			
		||||
@@ -358,6 +336,22 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public boolean showKeyMappings(@NotNull Set<? extends MappingMode> modes, @NotNull VimEditor editor) {
 | 
			
		||||
    return showKeyMappings(modes, ((IjVimEditor) editor).getEditor());
 | 
			
		||||
    List<Pair<EnumSet<MappingMode>, MappingInfo>> rows = getKeyMappingRows(modes);
 | 
			
		||||
    final StringBuilder builder = new StringBuilder();
 | 
			
		||||
    for (Pair<EnumSet<MappingMode>, MappingInfo> row : rows) {
 | 
			
		||||
      MappingInfo mappingInfo = row.getSecond();
 | 
			
		||||
      builder.append(StringsKt.padEnd(getModesStringCode(row.getFirst()), 2, ' '));
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(StringsKt.padEnd(VimInjectorKt.getInjector().getParser().toKeyNotation(mappingInfo.getFromKeys()), 11, ' '));
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(mappingInfo.isRecursive() ? " " : "*");
 | 
			
		||||
      builder.append(" ");
 | 
			
		||||
      builder.append(mappingInfo.getPresentableString());
 | 
			
		||||
      builder.append("\n");
 | 
			
		||||
    }
 | 
			
		||||
    VimOutputPanel outputPanel = injector.getOutputPanel().getOrCreate(editor, injector.getExecutionContextManager().getEditorExecutionContext(editor));
 | 
			
		||||
    outputPanel.addText(builder.toString(), true);
 | 
			
		||||
    outputPanel.show();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
package com.maddyhome.idea.vim.group
 | 
			
		||||
 | 
			
		||||
import com.intellij.codeInsight.daemon.ReferenceImporter
 | 
			
		||||
import com.intellij.openapi.actionSystem.CommonDataKeys
 | 
			
		||||
import com.intellij.openapi.actionSystem.DataContext
 | 
			
		||||
import com.intellij.openapi.application.ApplicationManager
 | 
			
		||||
import com.intellij.openapi.application.ReadAction
 | 
			
		||||
import com.intellij.openapi.command.WriteCommandAction
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.intellij.openapi.fileEditor.FileDocumentManager
 | 
			
		||||
import com.intellij.openapi.progress.ProgressIndicator
 | 
			
		||||
import com.intellij.openapi.progress.ProgressManager
 | 
			
		||||
import com.intellij.openapi.progress.Task
 | 
			
		||||
import com.intellij.psi.PsiDocumentManager
 | 
			
		||||
import com.intellij.psi.PsiElement
 | 
			
		||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
 | 
			
		||||
import java.util.function.BooleanSupplier
 | 
			
		||||
 | 
			
		||||
internal object MacroAutoImport {
 | 
			
		||||
  fun run(editor: Editor, dataContext: DataContext) {
 | 
			
		||||
    val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
 | 
			
		||||
    val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return
 | 
			
		||||
 | 
			
		||||
    if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val importers = ReferenceImporter.EP_NAME.extensionList
 | 
			
		||||
    if (importers.isEmpty()) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Auto import", true) {
 | 
			
		||||
      override fun run(indicator: ProgressIndicator) {
 | 
			
		||||
        val fixes = ReadAction.nonBlocking<List<BooleanSupplier>> {
 | 
			
		||||
          val fixes = mutableListOf<BooleanSupplier>()
 | 
			
		||||
 | 
			
		||||
          file.accept(object : PsiRecursiveElementWalkingVisitor() {
 | 
			
		||||
            override fun visitElement(element: PsiElement) {
 | 
			
		||||
              for (reference in element.references) {
 | 
			
		||||
                if (reference.resolve() != null) {
 | 
			
		||||
                  continue
 | 
			
		||||
                }
 | 
			
		||||
                for (importer in importers) {
 | 
			
		||||
                  importer.computeAutoImportAtOffset(editor, file, element.textRange.startOffset, true)
 | 
			
		||||
                    ?.let(fixes::add)
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              super.visitElement(element)
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          return@nonBlocking fixes
 | 
			
		||||
        }.executeSynchronously()
 | 
			
		||||
 | 
			
		||||
        ApplicationManager.getApplication().invokeAndWait {
 | 
			
		||||
          WriteCommandAction.writeCommandAction(project)
 | 
			
		||||
            .withName("Auto Import")
 | 
			
		||||
            .withGroupId("IdeaVimAutoImportAfterMacro")
 | 
			
		||||
            .shouldRecordActionForActiveDocument(true)
 | 
			
		||||
            .run<RuntimeException> {
 | 
			
		||||
              fixes.forEach { it.asBoolean }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.helper.MessageHelper.message
 | 
			
		||||
import com.maddyhome.idea.vim.macro.VimMacroBase
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Used to handle playback of macros
 | 
			
		||||
@@ -93,6 +94,9 @@ internal class MacroGroup : VimMacroBase() {
 | 
			
		||||
        } finally {
 | 
			
		||||
          keyStack.removeFirst()
 | 
			
		||||
        }
 | 
			
		||||
        if (!isInternalMacro) {
 | 
			
		||||
          MacroAutoImport.run(editor.ij, context.ij)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (isInternalMacro) {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ import com.maddyhome.idea.vim.command.Argument
 | 
			
		||||
import com.maddyhome.idea.vim.command.MotionType
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.common.TextRange
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
			
		||||
import com.maddyhome.idea.vim.handler.ExternalActionHandler
 | 
			
		||||
import com.maddyhome.idea.vim.handler.Motion
 | 
			
		||||
import com.maddyhome.idea.vim.handler.Motion.AbsoluteOffset
 | 
			
		||||
import com.maddyhome.idea.vim.handler.MotionActionHandler
 | 
			
		||||
@@ -193,21 +193,16 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
			
		||||
      argument: Argument,
 | 
			
		||||
      operatorArguments: OperatorArguments,
 | 
			
		||||
    ): TextRange? {
 | 
			
		||||
      if (argument !is Argument.Motion) {
 | 
			
		||||
        throw RuntimeException("Unexpected argument passed to getMotionRange2: $argument")
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      var start: Int
 | 
			
		||||
      var end: Int
 | 
			
		||||
      if (argument.type === Argument.Type.OFFSETS) {
 | 
			
		||||
        val offsets = argument.offsets[caret.vim] ?: return null
 | 
			
		||||
        val (first, second) = offsets.getNativeStartAndEnd()
 | 
			
		||||
        start = first
 | 
			
		||||
        end = second
 | 
			
		||||
      } else {
 | 
			
		||||
        val cmd = argument.motion
 | 
			
		||||
        // Normalize the counts between the command and the motion argument
 | 
			
		||||
        val cnt = cmd.count * operatorArguments.count1
 | 
			
		||||
        val raw = if (operatorArguments.count0 == 0 && cmd.rawCount == 0) 0 else cnt
 | 
			
		||||
        if (cmd.action is MotionActionHandler) {
 | 
			
		||||
          val action = cmd.action as MotionActionHandler
 | 
			
		||||
 | 
			
		||||
      val action = argument.motion
 | 
			
		||||
      when (action) {
 | 
			
		||||
        is MotionActionHandler -> {
 | 
			
		||||
          // This is where we are now
 | 
			
		||||
          start = caret.offset
 | 
			
		||||
 | 
			
		||||
@@ -216,8 +211,8 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
			
		||||
            editor.vim,
 | 
			
		||||
            caret.vim,
 | 
			
		||||
            IjEditorExecutionContext(context!!),
 | 
			
		||||
            cmd.argument,
 | 
			
		||||
            operatorArguments.withCount0(raw),
 | 
			
		||||
            argument.argument,
 | 
			
		||||
            operatorArguments
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
          // Invalid motion
 | 
			
		||||
@@ -233,22 +228,32 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
			
		||||
              end++
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } else if (cmd.action is TextObjectActionHandler) {
 | 
			
		||||
          val action = cmd.action as TextObjectActionHandler
 | 
			
		||||
          val range =
 | 
			
		||||
            action.getRange(editor.vim, caret.vim, IjEditorExecutionContext(context!!), cnt, raw) ?: return null
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        is TextObjectActionHandler -> {
 | 
			
		||||
          val range = action.getRange(
 | 
			
		||||
            editor.vim,
 | 
			
		||||
            caret.vim,
 | 
			
		||||
            IjEditorExecutionContext(context!!),
 | 
			
		||||
            operatorArguments.count1,
 | 
			
		||||
            operatorArguments.count0
 | 
			
		||||
          ) ?: return null
 | 
			
		||||
          start = range.startOffset
 | 
			
		||||
          end = range.endOffset
 | 
			
		||||
          if (cmd.isLinewiseMotion()) end--
 | 
			
		||||
        } else {
 | 
			
		||||
          throw RuntimeException(
 | 
			
		||||
            "Commands doesn't take " + cmd.action.javaClass.simpleName + " as an operator",
 | 
			
		||||
          )
 | 
			
		||||
          if (argument.isLinewiseMotion()) end--
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        is ExternalActionHandler -> {
 | 
			
		||||
          val range = action.getRange(caret.vim) ?: return null
 | 
			
		||||
          start = range.startOffset
 | 
			
		||||
          end = range.endOffset
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        else -> throw RuntimeException("Commands doesn't take " + action.javaClass.simpleName + " as an operator")
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
 | 
			
		||||
      val id = argument.motion.action.id
 | 
			
		||||
      val id = argument.motion.id
 | 
			
		||||
      if (id == VimChangeGroupBase.VIM_MOTION_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_BIG_WORD_RIGHT || id == VimChangeGroupBase.VIM_MOTION_CAMEL_RIGHT) {
 | 
			
		||||
        val text = editor.document.charsSequence.subSequence(start, end).toString()
 | 
			
		||||
        val lastNewLine = text.lastIndexOf('\n')
 | 
			
		||||
@@ -258,6 +263,7 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return TextRange(start, end)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -317,7 +323,7 @@ internal class MotionGroup : VimMotionGroupBase() {
 | 
			
		||||
              is Mode.CMD_LINE -> {
 | 
			
		||||
                val commandLine = injector.commandLine.getActiveCommandLine() ?: return
 | 
			
		||||
                commandLine.close(refocusOwningEditor = false, resetCaret = false)
 | 
			
		||||
                ExOutputModel.tryGetInstance(editor)?.close()
 | 
			
		||||
                injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
			
		||||
              }
 | 
			
		||||
              else -> {}
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -218,13 +218,17 @@ internal class VimEnterHandler(nextHandler: EditorActionHandler?) : VimKeyHandle
 | 
			
		||||
internal class VimEscHandler(nextHandler: EditorActionHandler) : VimKeyHandler(nextHandler) {
 | 
			
		||||
  override val key: String = "<Esc>"
 | 
			
		||||
 | 
			
		||||
  private val ideaVimSupportDialog
 | 
			
		||||
    get() = injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
 | 
			
		||||
  
 | 
			
		||||
  override fun isHandlerEnabled(editor: Editor, dataContext: DataContext?): Boolean {
 | 
			
		||||
    val ideaVimSupportDialog =
 | 
			
		||||
      injector.globalIjOptions().ideavimsupport.contains(IjOptionConstants.ideavimsupport_dialog)
 | 
			
		||||
 | 
			
		||||
    return editor.isPrimaryEditor() ||
 | 
			
		||||
      EditorHelper.isFileEditor(editor) && !editor.vim.mode.inNormalMode ||
 | 
			
		||||
      ideaVimSupportDialog && !editor.vim.mode.inNormalMode
 | 
			
		||||
      EditorHelper.isFileEditor(editor) && vimStateNeedsToHandleEscape(editor) ||
 | 
			
		||||
      ideaVimSupportDialog && vimStateNeedsToHandleEscape(editor)
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  private fun vimStateNeedsToHandleEscape(editor: Editor): Boolean {
 | 
			
		||||
    return !editor.vim.mode.inNormalMode || KeyHandler.getInstance().keyHandlerState.mappingState.hasKeys
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -326,7 +326,7 @@ public class EditorHelper {
 | 
			
		||||
 | 
			
		||||
    final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
 | 
			
		||||
    @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);
 | 
			
		||||
 | 
			
		||||
    // For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ package com.maddyhome.idea.vim.helper
 | 
			
		||||
 | 
			
		||||
import com.intellij.codeWithMe.ClientId
 | 
			
		||||
import com.intellij.openapi.editor.Caret
 | 
			
		||||
import com.intellij.openapi.editor.CaretState
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.intellij.openapi.editor.ex.util.EditorUtil
 | 
			
		||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
			
		||||
@@ -20,6 +21,8 @@ import com.maddyhome.idea.vim.api.StringListOptionValue
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.group.IjOptionConstants
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.inBlockSelection
 | 
			
		||||
import java.awt.Component
 | 
			
		||||
import javax.swing.JComponent
 | 
			
		||||
import javax.swing.JTable
 | 
			
		||||
@@ -96,3 +99,41 @@ internal val Caret.vimLine: Int
 | 
			
		||||
 */
 | 
			
		||||
internal val Editor.vimLine: Int
 | 
			
		||||
  get() = this.caretModel.currentCaret.vimLine
 | 
			
		||||
 | 
			
		||||
internal inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) {
 | 
			
		||||
  val caretModel = this.caretModel
 | 
			
		||||
  val carets = if (this.vim.inBlockSelection) null else caretModel.allCarets
 | 
			
		||||
  if (carets == null || carets.size == 1) {
 | 
			
		||||
    action()
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    var initialDocumentSize = this.document.textLength
 | 
			
		||||
    var documentSizeDifference = 0
 | 
			
		||||
 | 
			
		||||
    val caretOffsets = carets.map { it.selectionStart to it.selectionEnd }
 | 
			
		||||
    val restoredCarets = mutableListOf<CaretState>()
 | 
			
		||||
 | 
			
		||||
    caretModel.removeSecondaryCarets()
 | 
			
		||||
    
 | 
			
		||||
    for ((selectionStart, selectionEnd) in caretOffsets) {
 | 
			
		||||
      if (selectionStart == selectionEnd) {
 | 
			
		||||
        caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference)
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        caretModel.primaryCaret.setSelection(
 | 
			
		||||
          selectionStart + documentSizeDifference,
 | 
			
		||||
          selectionEnd + documentSizeDifference
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      action()
 | 
			
		||||
      restoredCarets.add(caretModel.caretsAndSelections.single())
 | 
			
		||||
 | 
			
		||||
      val documentLength = this.document.textLength
 | 
			
		||||
      documentSizeDifference += documentLength - initialDocumentSize
 | 
			
		||||
      initialDocumentSize = documentLength
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    caretModel.caretsAndSelections = restoredCarets
 | 
			
		||||
  } 
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys
 | 
			
		||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
 | 
			
		||||
import com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks
 | 
			
		||||
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
 | 
			
		||||
import com.intellij.openapi.actionSystem.impl.Utils
 | 
			
		||||
import com.intellij.openapi.application.ex.ApplicationManagerEx
 | 
			
		||||
import com.intellij.openapi.command.CommandProcessor
 | 
			
		||||
import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
			
		||||
@@ -60,6 +61,9 @@ internal class IjActionExecutor : VimActionExecutor {
 | 
			
		||||
    get() = IdeActions.ACTION_EXPAND_REGION
 | 
			
		||||
  override val ACTION_EXPAND_REGION_RECURSIVELY: String
 | 
			
		||||
    get() = IdeActions.ACTION_EXPAND_REGION_RECURSIVELY
 | 
			
		||||
  override val ACTION_EXPAND_COLLAPSE_TOGGLE: String
 | 
			
		||||
    // [VERSION UPDATE] 2024.3+ Replace raw "ExpandCollapseToggleAction" with IdeActions.ACTION_EXPAND_COLLAPSE_TOGGLE_REGION from the platform.
 | 
			
		||||
    get() = "ExpandCollapseToggleAction"
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Execute an action
 | 
			
		||||
@@ -92,6 +96,7 @@ internal class IjActionExecutor : VimActionExecutor {
 | 
			
		||||
      ActionManager.getInstance(),
 | 
			
		||||
      0,
 | 
			
		||||
    )
 | 
			
		||||
    Utils.initUpdateSession(event)
 | 
			
		||||
    // beforeActionPerformedUpdate should be called to update the action. It fixes some rider-specific problems.
 | 
			
		||||
    //   because rider use async update method. See VIM-1819.
 | 
			
		||||
    // This method executes inside of lastUpdateAndCheckDumb
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
			
		||||
@@ -94,6 +93,6 @@ internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal fun Editor.exitInsertMode(context: DataContext, operatorArguments: OperatorArguments) {
 | 
			
		||||
  VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context), operatorArguments)
 | 
			
		||||
internal fun Editor.exitInsertMode(context: DataContext) {
 | 
			
		||||
  VimPlugin.getChange().processEscape(IjVimEditor(this), IjEditorExecutionContext(context))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ internal object ScrollViewHelper {
 | 
			
		||||
    // that this needs to be replaced as a more or less dumb line for line rewrite.
 | 
			
		||||
    val topLine = getVisualLineAtTopOfScreen(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
 | 
			
		||||
    val scrollOffset = injector.options(vimEditor).scrolloff
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,8 @@ import com.maddyhome.idea.vim.common.InsertSequence
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
 | 
			
		||||
import com.maddyhome.idea.vim.undo.UndoRedoBase
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -66,15 +68,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
			
		||||
      // TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
 | 
			
		||||
      editor.runWithChangeTracking {
 | 
			
		||||
        undoManager.undo(fileEditor)
 | 
			
		||||
 | 
			
		||||
        // We execute undo one more time if the previous one just restored selection
 | 
			
		||||
        if (!hasChanges && hasSelection(editor) && undoManager.isUndoAvailable(fileEditor)) {
 | 
			
		||||
          undoManager.undo(fileEditor)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      CommandProcessor.getInstance().runUndoTransparentAction {
 | 
			
		||||
        removeSelections(editor)
 | 
			
		||||
        restoreVisualMode(editor)
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      notifyAboutNewUndo(editor.ij.project)
 | 
			
		||||
@@ -108,7 +102,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
			
		||||
  private fun hasSelection(editor: VimEditor): Boolean {
 | 
			
		||||
    return editor.primaryCaret().ij.hasSelection()
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
			
		||||
    val ijContext = context.context as DataContext
 | 
			
		||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
			
		||||
@@ -229,4 +223,21 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
			
		||||
    val hasChanges: Boolean
 | 
			
		||||
      get() = changeListener.hasChanged || initialPath != editor.getPath()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun restoreVisualMode(editor: VimEditor) {
 | 
			
		||||
    if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
 | 
			
		||||
      val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
 | 
			
		||||
 | 
			
		||||
      // Visual block selection is restored into multiple carets, so multi-carets that form a block are always
 | 
			
		||||
      // identified as visual block mode, leading to false positives.
 | 
			
		||||
      // Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
 | 
			
		||||
      // visual block mode.
 | 
			
		||||
      val wantedMode = if (detectedMode == SelectionType.BLOCK_WISE)
 | 
			
		||||
        SelectionType.CHARACTER_WISE
 | 
			
		||||
      else
 | 
			
		||||
        detectedMode
 | 
			
		||||
 | 
			
		||||
      VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,13 +18,13 @@ import com.intellij.openapi.editor.VisualPosition
 | 
			
		||||
import com.intellij.openapi.editor.markup.RangeHighlighter
 | 
			
		||||
import com.intellij.openapi.util.Key
 | 
			
		||||
import com.intellij.openapi.util.UserDataHolder
 | 
			
		||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
 | 
			
		||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
 | 
			
		||||
import com.maddyhome.idea.vim.api.SelectionInfo
 | 
			
		||||
import com.maddyhome.idea.vim.common.InsertSequence
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
			
		||||
import com.maddyhome.idea.vim.group.visual.VisualChange
 | 
			
		||||
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
 | 
			
		||||
import com.maddyhome.idea.vim.common.InsertSequence
 | 
			
		||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.VimStateMachine
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
@@ -96,7 +96,6 @@ internal var Caret.vimInsertStart: RangeMarker by userDataOr {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Data could be lost during visual block motion
 | 
			
		||||
internal var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
 | 
			
		||||
internal var Caret.markStorage: LocalMarkStorage? by userDataCaretToEditor()
 | 
			
		||||
internal var Caret.lastSelectionInfo: SelectionInfo? by userDataCaretToEditor()
 | 
			
		||||
 | 
			
		||||
@@ -126,6 +125,7 @@ internal var Editor.vimExOutput: ExOutputModel? by userData()
 | 
			
		||||
internal var Editor.vimTestInputModel: TestInputModel? by userData()
 | 
			
		||||
 | 
			
		||||
internal var Editor.vimChangeActionSwitchMode: Mode? by userData()
 | 
			
		||||
internal var Editor.replaceMask: VimEditorReplaceMask? by userData()
 | 
			
		||||
 | 
			
		||||
internal var Caret.currentInsert: InsertSequence? by userData()
 | 
			
		||||
internal val Caret.insertHistory: MutableList<InsertSequence> by userDataOr { mutableListOf() }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,32 +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.helper
 | 
			
		||||
 | 
			
		||||
import com.intellij.ide.plugins.StandalonePluginUpdateChecker
 | 
			
		||||
import com.intellij.openapi.components.Service
 | 
			
		||||
import com.intellij.openapi.components.service
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.group.NotificationService
 | 
			
		||||
import com.maddyhome.idea.vim.icons.VimIcons
 | 
			
		||||
 | 
			
		||||
@Service(Service.Level.APP)
 | 
			
		||||
internal class VimStandalonePluginUpdateChecker : StandalonePluginUpdateChecker(
 | 
			
		||||
  VimPlugin.getPluginId(),
 | 
			
		||||
  updateTimestampProperty = PROPERTY_NAME,
 | 
			
		||||
  NotificationService.IDEAVIM_STICKY_GROUP,
 | 
			
		||||
  VimIcons.IDEAVIM,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
  override fun skipUpdateCheck(): Boolean = VimPlugin.isNotEnabled() || "dev" in VimPlugin.getVersion()
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    private const val PROPERTY_NAME = "ideavim.statistics.timestamp"
 | 
			
		||||
    fun getInstance(): VimStandalonePluginUpdateChecker = service()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,15 +10,12 @@ package com.maddyhome.idea.vim.listener
 | 
			
		||||
 | 
			
		||||
import com.intellij.execution.impl.ConsoleViewImpl
 | 
			
		||||
import com.intellij.openapi.application.ApplicationManager
 | 
			
		||||
import com.intellij.openapi.editor.EditorKind
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.common.EditorListener
 | 
			
		||||
import com.maddyhome.idea.vim.helper.EditorHelper
 | 
			
		||||
import com.maddyhome.idea.vim.helper.inInsertMode
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
@@ -63,17 +60,11 @@ class IJEditorFocusListener : EditorListener {
 | 
			
		||||
      val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
 | 
			
		||||
      VimPlugin.getChange().insertBeforeCursor(editor, context)
 | 
			
		||||
    }
 | 
			
		||||
    if (!ijEditor.isViewer &&
 | 
			
		||||
      !EditorHelper.isFileEditor(ijEditor) &&
 | 
			
		||||
      ijEditor.document.isWritable &&
 | 
			
		||||
      !ijEditor.inInsertMode && ijEditor.editorKind != EditorKind.DIFF
 | 
			
		||||
    ) {
 | 
			
		||||
      switchToInsertMode.run()
 | 
			
		||||
    } else if (!ijEditor.document.isWritable) {
 | 
			
		||||
    if (!ijEditor.document.isWritable) {
 | 
			
		||||
      val context: ExecutionContext = injector.executionContextManager.getEditorExecutionContext(editor)
 | 
			
		||||
      val mode = injector.vimState.mode
 | 
			
		||||
      when (mode) {
 | 
			
		||||
        is Mode.INSERT -> editor.exitInsertMode(context, OperatorArguments(false, 0, mode))
 | 
			
		||||
        is Mode.INSERT -> editor.exitInsertMode(context)
 | 
			
		||||
        else -> {}
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -86,4 +77,5 @@ class IJEditorFocusListener : EditorListener {
 | 
			
		||||
    }
 | 
			
		||||
    KeyHandler.getInstance().reset(editor)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,9 @@ import com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction
 | 
			
		||||
import com.intellij.codeInsight.template.Template
 | 
			
		||||
import com.intellij.codeInsight.template.TemplateEditingAdapter
 | 
			
		||||
import com.intellij.codeInsight.template.TemplateManagerListener
 | 
			
		||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
 | 
			
		||||
import com.intellij.codeInsight.template.impl.TemplateState
 | 
			
		||||
import com.intellij.codeInsight.template.impl.actions.NextVariableAction
 | 
			
		||||
import com.intellij.find.FindModelListener
 | 
			
		||||
import com.intellij.openapi.actionSystem.ActionManager
 | 
			
		||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
			
		||||
@@ -28,6 +30,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
 | 
			
		||||
import com.intellij.openapi.actionSystem.ex.AnActionListener
 | 
			
		||||
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.intellij.openapi.editor.impl.ScrollingModelImpl
 | 
			
		||||
import com.intellij.openapi.keymap.KeymapManager
 | 
			
		||||
import com.intellij.openapi.project.DumbAwareToggleAction
 | 
			
		||||
import com.intellij.openapi.util.TextRange
 | 
			
		||||
@@ -58,6 +61,7 @@ internal object IdeaSpecifics {
 | 
			
		||||
    private val surrounderAction =
 | 
			
		||||
      "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
 | 
			
		||||
    private var editor: Editor? = null
 | 
			
		||||
    private var caretOffset = -1
 | 
			
		||||
    private var completionPrevDocumentLength: Int? = null
 | 
			
		||||
    private var completionPrevDocumentOffset: Int? = null
 | 
			
		||||
 | 
			
		||||
@@ -67,6 +71,7 @@ internal object IdeaSpecifics {
 | 
			
		||||
      val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
 | 
			
		||||
      if (hostEditor != null) {
 | 
			
		||||
        editor = hostEditor
 | 
			
		||||
        caretOffset = hostEditor.caretModel.offset
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
 | 
			
		||||
@@ -115,42 +120,61 @@ internal object IdeaSpecifics {
 | 
			
		||||
      if (VimPlugin.isNotEnabled()) return
 | 
			
		||||
 | 
			
		||||
      val editor = editor
 | 
			
		||||
      if (editor != null && action is ChooseItemAction && injector.registerGroup.isRecording) {
 | 
			
		||||
        val prevDocumentLength = completionPrevDocumentLength
 | 
			
		||||
        val prevDocumentOffset = completionPrevDocumentOffset
 | 
			
		||||
      if (editor != null) {
 | 
			
		||||
        if (action is ChooseItemAction && injector.registerGroup.isRecording) {
 | 
			
		||||
          val prevDocumentLength = completionPrevDocumentLength
 | 
			
		||||
          val prevDocumentOffset = completionPrevDocumentOffset
 | 
			
		||||
 | 
			
		||||
        if (prevDocumentLength != null && prevDocumentOffset != null) {
 | 
			
		||||
          val register = VimPlugin.getRegister()
 | 
			
		||||
          val addedTextLength = editor.document.textLength - prevDocumentLength
 | 
			
		||||
          val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
 | 
			
		||||
          val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
 | 
			
		||||
          if (prevDocumentLength != null && prevDocumentOffset != null) {
 | 
			
		||||
            val register = VimPlugin.getRegister()
 | 
			
		||||
            val addedTextLength = editor.document.textLength - prevDocumentLength
 | 
			
		||||
            val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
 | 
			
		||||
            val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
 | 
			
		||||
 | 
			
		||||
          register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
 | 
			
		||||
          repeat(caretShift.coerceAtLeast(0)) {
 | 
			
		||||
            register.recordKeyStroke(leftArrow)
 | 
			
		||||
            register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
 | 
			
		||||
            repeat(caretShift.coerceAtLeast(0)) {
 | 
			
		||||
              register.recordKeyStroke(leftArrow)
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          this.completionPrevDocumentLength = null
 | 
			
		||||
          this.completionPrevDocumentOffset = null
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        //region Enter insert mode after surround with if
 | 
			
		||||
        if (surrounderAction == action.javaClass.name && surrounderItems.any {
 | 
			
		||||
            action.templatePresentation.text.endsWith(
 | 
			
		||||
              it,
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
        ) {
 | 
			
		||||
          editor?.let {
 | 
			
		||||
            it.vim.mode = Mode.NORMAL()
 | 
			
		||||
            VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
 | 
			
		||||
            KeyHandler.getInstance().reset(it.vim)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.completionPrevDocumentLength = null
 | 
			
		||||
        this.completionPrevDocumentOffset = null
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      //region Enter insert mode after surround with if
 | 
			
		||||
      if (surrounderAction == action.javaClass.name && surrounderItems.any {
 | 
			
		||||
          action.templatePresentation.text.endsWith(
 | 
			
		||||
            it,
 | 
			
		||||
          )
 | 
			
		||||
        else if (action is NextVariableAction && TemplateManagerImpl.getTemplateState(editor) == null) {
 | 
			
		||||
          editor.vim.exitInsertMode(event.dataContext.vim)
 | 
			
		||||
          KeyHandler.getInstance().reset(editor.vim)
 | 
			
		||||
        }
 | 
			
		||||
      ) {
 | 
			
		||||
        editor?.let {
 | 
			
		||||
          it.vim.mode = Mode.NORMAL()
 | 
			
		||||
          VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
 | 
			
		||||
          KeyHandler.getInstance().reset(it.vim)
 | 
			
		||||
        //endregion
 | 
			
		||||
 | 
			
		||||
        if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
 | 
			
		||||
          val scrollModel = editor.scrollingModel as ScrollingModelImpl
 | 
			
		||||
          if (scrollModel.isScrollingNow) {
 | 
			
		||||
            val v = scrollModel.verticalScrollOffset
 | 
			
		||||
            val h = scrollModel.horizontalScrollOffset
 | 
			
		||||
            scrollModel.finishAnimation()
 | 
			
		||||
            scrollModel.scroll(h, v)
 | 
			
		||||
            scrollModel.finishAnimation()
 | 
			
		||||
          }
 | 
			
		||||
          injector.scroll.scrollCaretIntoView(editor.vim)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      //endregion
 | 
			
		||||
 | 
			
		||||
      this.editor = null
 | 
			
		||||
      this.caretOffset = -1
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ import com.intellij.openapi.editor.ex.DocumentEx
 | 
			
		||||
import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
 | 
			
		||||
import com.intellij.openapi.editor.ex.FocusChangeListener
 | 
			
		||||
import com.intellij.openapi.editor.impl.EditorComponentImpl
 | 
			
		||||
import com.intellij.openapi.editor.impl.EditorImpl
 | 
			
		||||
import com.intellij.openapi.fileEditor.FileEditorManager
 | 
			
		||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
 | 
			
		||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
 | 
			
		||||
@@ -45,11 +46,14 @@ import com.intellij.openapi.fileEditor.ex.FileEditorWithProvider
 | 
			
		||||
import com.intellij.openapi.fileEditor.impl.EditorComposite
 | 
			
		||||
import com.intellij.openapi.fileEditor.impl.EditorWindow
 | 
			
		||||
import com.intellij.openapi.project.ProjectManager
 | 
			
		||||
import com.intellij.openapi.rd.createLifetime
 | 
			
		||||
import com.intellij.openapi.rd.createNestedDisposable
 | 
			
		||||
import com.intellij.openapi.util.Disposer
 | 
			
		||||
import com.intellij.openapi.util.Key
 | 
			
		||||
import com.intellij.openapi.util.removeUserData
 | 
			
		||||
import com.intellij.openapi.vfs.VirtualFile
 | 
			
		||||
import com.intellij.util.ExceptionUtil
 | 
			
		||||
import com.jetbrains.rd.util.lifetime.Lifetime
 | 
			
		||||
import com.maddyhome.idea.vim.EventFacade
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.VimKeyListener
 | 
			
		||||
@@ -62,7 +66,6 @@ import com.maddyhome.idea.vim.api.coerceOffset
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
 | 
			
		||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
			
		||||
import com.maddyhome.idea.vim.group.EditorGroup
 | 
			
		||||
import com.maddyhome.idea.vim.group.FileGroup
 | 
			
		||||
import com.maddyhome.idea.vim.group.IjOptions
 | 
			
		||||
@@ -79,7 +82,6 @@ import com.maddyhome.idea.vim.handler.keyCheckRequests
 | 
			
		||||
import com.maddyhome.idea.vim.helper.CaretVisualAttributesListener
 | 
			
		||||
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
 | 
			
		||||
import com.maddyhome.idea.vim.helper.StrictMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.VimStandalonePluginUpdateChecker
 | 
			
		||||
import com.maddyhome.idea.vim.helper.exitSelectMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.exitVisualMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.forceBarCursor
 | 
			
		||||
@@ -95,6 +97,7 @@ import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.InsertTimeRecorder
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.ij
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.inSelectMode
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.selectionType
 | 
			
		||||
import com.maddyhome.idea.vim.ui.ShowCmdOptionChangeListener
 | 
			
		||||
@@ -103,7 +106,6 @@ import com.maddyhome.idea.vim.ui.widgets.macro.MacroWidgetListener
 | 
			
		||||
import com.maddyhome.idea.vim.ui.widgets.macro.macroWidgetOptionListener
 | 
			
		||||
import com.maddyhome.idea.vim.ui.widgets.mode.listeners.ModeWidgetListener
 | 
			
		||||
import com.maddyhome.idea.vim.ui.widgets.mode.modeWidgetOptionListener
 | 
			
		||||
import com.maddyhome.idea.vim.vimDisposable
 | 
			
		||||
import java.awt.event.MouseAdapter
 | 
			
		||||
import java.awt.event.MouseEvent
 | 
			
		||||
import javax.swing.SwingUtilities
 | 
			
		||||
@@ -285,12 +287,10 @@ internal object VimListenerManager {
 | 
			
		||||
      // TODO: If the user changes the 'ideavimsupport' option, existing editors won't be initialised
 | 
			
		||||
      if (vimDisabled(editor)) return
 | 
			
		||||
 | 
			
		||||
      // As I understand, there is no need to pass a disposable that also disposes on editor close
 | 
			
		||||
      //   because all editor resources will be garbage collected anyway on editor close
 | 
			
		||||
      // Note that this uses the plugin's main disposable, rather than VimPlugin.onOffDisposable, because we don't need
 | 
			
		||||
      // to - we explicitly call VimListenerManager.removeAll from VimPlugin.turnOffPlugin, and this disposes each
 | 
			
		||||
      // editor's disposable individually.
 | 
			
		||||
      val disposable = editor.project?.vimDisposable ?: return
 | 
			
		||||
      val pluginLifetime = VimPlugin.getInstance().createLifetime()
 | 
			
		||||
      val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
 | 
			
		||||
      val disposable =
 | 
			
		||||
        Lifetime.intersect(pluginLifetime, editorLifetime).createNestedDisposable("MyLifetimedDisposable")
 | 
			
		||||
 | 
			
		||||
      // Protect against double initialisation
 | 
			
		||||
      if (editor.getUserData(editorListenersDisposableKey) != null) {
 | 
			
		||||
@@ -386,7 +386,18 @@ internal object VimListenerManager {
 | 
			
		||||
    override fun selectionChanged(event: FileEditorManagerEvent) {
 | 
			
		||||
      // We can't rely on being passed a non-null editor, so check for Code With Me scenarios explicitly
 | 
			
		||||
      if (VimPlugin.isNotEnabled() || !ClientId.isCurrentlyUnderLocalId) return
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
      val newEditor = event.newEditor
 | 
			
		||||
      if (newEditor is TextEditor) {
 | 
			
		||||
        val editor = newEditor.editor
 | 
			
		||||
        if (editor.isInsertMode) {
 | 
			
		||||
          editor.vim.mode = Mode.NORMAL()
 | 
			
		||||
          KeyHandler.getInstance().reset(editor.vim)
 | 
			
		||||
        }
 | 
			
		||||
        // Breaks relativenumber for some reason
 | 
			
		||||
//        injector.scroll.scrollCaretIntoView(editor.vim)
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      MotionGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
			
		||||
      FileGroup.fileEditorManagerSelectionChangedCallback(event)
 | 
			
		||||
      VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
 | 
			
		||||
@@ -458,8 +469,6 @@ internal object VimListenerManager {
 | 
			
		||||
 | 
			
		||||
        event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      VimStandalonePluginUpdateChecker.getInstance().pluginUsed()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun editorReleased(event: EditorFactoryEvent) {
 | 
			
		||||
@@ -739,7 +748,7 @@ internal object VimListenerManager {
 | 
			
		||||
        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
			
		||||
        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
			
		||||
 | 
			
		||||
        ExOutputModel.tryGetInstance(editor)?.close()
 | 
			
		||||
        injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
			
		||||
 | 
			
		||||
        val caretModel = editor.caretModel
 | 
			
		||||
        if (editor.vim.mode.selectionType != null) {
 | 
			
		||||
@@ -768,7 +777,7 @@ internal object VimListenerManager {
 | 
			
		||||
        injector.commandLine.getActiveCommandLine()?.close(refocusOwningEditor = true, resetCaret = false)
 | 
			
		||||
        injector.modalInput.getCurrentModalInput()?.deactivate(refocusOwningEditor = true, resetCaret = false)
 | 
			
		||||
 | 
			
		||||
        ExOutputModel.getInstance(event.editor).close()
 | 
			
		||||
        injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,27 @@ import com.maddyhome.idea.vim.common.LiveRange
 | 
			
		||||
internal class IjLiveRange(val marker: RangeMarker) : LiveRange {
 | 
			
		||||
  override val startOffset: Int
 | 
			
		||||
    get() = marker.startOffset
 | 
			
		||||
 | 
			
		||||
  override val endOffset: Int
 | 
			
		||||
    get() = marker.endOffset
 | 
			
		||||
 | 
			
		||||
  override fun equals(other: Any?): Boolean {
 | 
			
		||||
    if (this === other) return true
 | 
			
		||||
    if (javaClass != other?.javaClass) return false
 | 
			
		||||
 | 
			
		||||
    other as IjLiveRange
 | 
			
		||||
 | 
			
		||||
    if (startOffset != other.startOffset) return false
 | 
			
		||||
    if (endOffset != other.endOffset) return false
 | 
			
		||||
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun hashCode(): Int {
 | 
			
		||||
    var result = startOffset
 | 
			
		||||
    result = 31 * result + endOffset
 | 
			
		||||
    return result
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val RangeMarker.vim: LiveRange
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,6 @@ import com.intellij.openapi.editor.Caret
 | 
			
		||||
import com.intellij.openapi.editor.LogicalPosition
 | 
			
		||||
import com.intellij.openapi.editor.VisualPosition
 | 
			
		||||
import com.maddyhome.idea.vim.api.BufferPosition
 | 
			
		||||
import com.maddyhome.idea.vim.api.CaretRegisterStorage
 | 
			
		||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
 | 
			
		||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
			
		||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
 | 
			
		||||
import com.maddyhome.idea.vim.api.SelectionInfo
 | 
			
		||||
@@ -29,7 +27,6 @@ import com.maddyhome.idea.vim.helper.insertHistory
 | 
			
		||||
import com.maddyhome.idea.vim.helper.lastSelectionInfo
 | 
			
		||||
import com.maddyhome.idea.vim.helper.markStorage
 | 
			
		||||
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
 | 
			
		||||
import com.maddyhome.idea.vim.helper.registerStorage
 | 
			
		||||
import com.maddyhome.idea.vim.helper.resetVimLastColumn
 | 
			
		||||
import com.maddyhome.idea.vim.helper.vimInsertStart
 | 
			
		||||
import com.maddyhome.idea.vim.helper.vimLastColumn
 | 
			
		||||
@@ -41,18 +38,6 @@ import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
			
		||||
 | 
			
		||||
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
 | 
			
		||||
 | 
			
		||||
  override val registerStorage: CaretRegisterStorage
 | 
			
		||||
    get() {
 | 
			
		||||
      var storage = this.caret.registerStorage
 | 
			
		||||
      if (storage == null) {
 | 
			
		||||
        initInjector() // To initialize injector used in CaretRegisterStorageBase
 | 
			
		||||
        storage = CaretRegisterStorageBase(this)
 | 
			
		||||
        this.caret.registerStorage = storage
 | 
			
		||||
      } else if (storage.caret != this) {
 | 
			
		||||
        storage.caret = this
 | 
			
		||||
      }
 | 
			
		||||
      return storage
 | 
			
		||||
    }
 | 
			
		||||
  override val markStorage: LocalMarkStorage
 | 
			
		||||
    get() {
 | 
			
		||||
      var storage = this.caret.markStorage
 | 
			
		||||
 
 | 
			
		||||
@@ -38,12 +38,12 @@ import com.maddyhome.idea.vim.api.VimSelectionModel
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimVisualPosition
 | 
			
		||||
import com.maddyhome.idea.vim.api.VirtualFile
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.common.IndentConfig
 | 
			
		||||
import com.maddyhome.idea.vim.common.IndentConfig.Companion.create
 | 
			
		||||
import com.maddyhome.idea.vim.common.LiveRange
 | 
			
		||||
import com.maddyhome.idea.vim.common.ModeChangeListener
 | 
			
		||||
import com.maddyhome.idea.vim.common.TextRange
 | 
			
		||||
import com.maddyhome.idea.vim.common.VimEditorReplaceMask
 | 
			
		||||
import com.maddyhome.idea.vim.common.forgetAllReplaceMasks
 | 
			
		||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemBlockSelectionSilently
 | 
			
		||||
import com.maddyhome.idea.vim.helper.EditorHelper
 | 
			
		||||
import com.maddyhome.idea.vim.helper.StrictMode
 | 
			
		||||
@@ -53,6 +53,7 @@ import com.maddyhome.idea.vim.helper.fileSize
 | 
			
		||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
 | 
			
		||||
import com.maddyhome.idea.vim.helper.inExMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.isTemplateActive
 | 
			
		||||
import com.maddyhome.idea.vim.helper.replaceMask
 | 
			
		||||
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
 | 
			
		||||
import com.maddyhome.idea.vim.helper.vimLastSelectionType
 | 
			
		||||
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
 | 
			
		||||
@@ -75,6 +76,11 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
			
		||||
  // TBH, I don't like the names. Need to think a bit more about this
 | 
			
		||||
  val editor = editor.getTopLevelEditor()
 | 
			
		||||
  val originalEditor = editor
 | 
			
		||||
  override var replaceMask: VimEditorReplaceMask?
 | 
			
		||||
    get() = editor.replaceMask
 | 
			
		||||
    set(value) {
 | 
			
		||||
      editor.replaceMask = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  override fun updateMode(mode: Mode) {
 | 
			
		||||
    (injector.vimState as VimStateMachineImpl).mode = mode
 | 
			
		||||
@@ -91,7 +97,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
			
		||||
      editor.vimChangeActionSwitchMode = value
 | 
			
		||||
    }
 | 
			
		||||
  override val indentConfig: VimIndentConfig
 | 
			
		||||
    get() = create(editor)
 | 
			
		||||
    get() = IndentConfig.create(editor)
 | 
			
		||||
 | 
			
		||||
  override fun fileSize(): Long = editor.fileSize.toLong()
 | 
			
		||||
 | 
			
		||||
@@ -165,21 +171,38 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
			
		||||
    return editor.caretModel.allCarets.map { IjVimCaret(it) }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override var isFirstCaret = true
 | 
			
		||||
  override var isReversingCarets = false
 | 
			
		||||
  
 | 
			
		||||
  @Suppress("ideavimRunForEachCaret")
 | 
			
		||||
  override fun forEachCaret(action: (VimCaret) -> Unit) {
 | 
			
		||||
    if (editor.vim.inBlockSelection) {
 | 
			
		||||
      action(IjVimCaret(editor.caretModel.primaryCaret))
 | 
			
		||||
    } else {
 | 
			
		||||
      editor.caretModel.runForEachCaret({
 | 
			
		||||
        if (it.isValid) {
 | 
			
		||||
          action(IjVimCaret(it))
 | 
			
		||||
        }
 | 
			
		||||
      }, false)
 | 
			
		||||
      try {
 | 
			
		||||
        editor.caretModel.runForEachCaret({
 | 
			
		||||
          if (it.isValid) {
 | 
			
		||||
            action(IjVimCaret(it))
 | 
			
		||||
            isFirstCaret = false
 | 
			
		||||
          }
 | 
			
		||||
        }, false)
 | 
			
		||||
      } finally {
 | 
			
		||||
        isFirstCaret = true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
 | 
			
		||||
    editor.caretModel.runForEachCaret({ action(IjVimCaret(it)) }, reverse)
 | 
			
		||||
    isReversingCarets = reverse
 | 
			
		||||
    try {
 | 
			
		||||
      editor.caretModel.runForEachCaret({
 | 
			
		||||
        action(IjVimCaret(it))
 | 
			
		||||
        isFirstCaret = false
 | 
			
		||||
      }, reverse)
 | 
			
		||||
    } finally {
 | 
			
		||||
      isFirstCaret = true
 | 
			
		||||
      isReversingCarets = false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun isInForEachCaretScope(): Boolean {
 | 
			
		||||
@@ -381,8 +404,8 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
			
		||||
    return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun exitInsertMode(context: ExecutionContext, operatorArguments: OperatorArguments) {
 | 
			
		||||
    editor.exitInsertMode(context.ij, operatorArguments)
 | 
			
		||||
  override fun exitInsertMode(context: ExecutionContext) {
 | 
			
		||||
    editor.exitInsertMode(context.ij)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun exitSelectModeNative(adjustCaret: Boolean) {
 | 
			
		||||
@@ -454,6 +477,7 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
 | 
			
		||||
    get() = (editor as? EditorEx)?.isInsertMode ?: false
 | 
			
		||||
    set(value) {
 | 
			
		||||
      (editor as? EditorEx)?.isInsertMode = value
 | 
			
		||||
      forgetAllReplaceMasks()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  override val document: VimDocument
 | 
			
		||||
@@ -530,4 +554,4 @@ internal class InsertTimeRecorder: ModeChangeListener {
 | 
			
		||||
      editor.forEachCaret { undo.endInsertSequence(it, it.offset, nanoTime) }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,718 +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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * IdeaVim command index.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Insert mode
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |i_CTRL-@|             {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertExitAction}
 | 
			
		||||
 * |i_CTRL-A|             {@link com.maddyhome.idea.vim.action.change.insert.InsertPreviousInsertAction}
 | 
			
		||||
 * |i_CTRL-C|             {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
			
		||||
 * |i_CTRL-D|             {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftLinesAction}
 | 
			
		||||
 * |i_CTRL-E|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterBelowCursorAction}
 | 
			
		||||
 * |i_CTRL-G_j|           TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-G_k|           TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-G_u|           TO BE IMPLEMENTED
 | 
			
		||||
 * |i_<BS>|               {@link com.maddyhome.idea.vim.action.editor.VimEditorBackSpace}
 | 
			
		||||
 * |i_digraph|            IdeaVim enter digraph
 | 
			
		||||
 * |i_CTRL-H|             IntelliJ editor backspace
 | 
			
		||||
 * |i_<Tab>|              {@link com.maddyhome.idea.vim.action.editor.VimEditorTab}
 | 
			
		||||
 * |i_CTRL-I|             IntelliJ editor tab
 | 
			
		||||
 * |i_<NL>|               {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
			
		||||
 * |i_CTRL-J|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-K|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction}
 | 
			
		||||
 * |i_CTRL-L|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_<CR>|               {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
			
		||||
 * |i_CTRL-M|             {@link com.maddyhome.idea.vim.action.change.insert.InsertEnterAction}
 | 
			
		||||
 * |i_CTRL-N|             {@link com.maddyhome.idea.vim.action.window.LookupDownAction}
 | 
			
		||||
 * |i_CTRL-O|             {@link com.maddyhome.idea.vim.action.change.insert.InsertSingleCommandAction}
 | 
			
		||||
 * |i_CTRL-P|             {@link com.maddyhome.idea.vim.action.window.LookupUpAction}
 | 
			
		||||
 * |i_CTRL-Q|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-R|             {@link com.maddyhome.idea.vim.action.change.insert.InsertRegisterAction}
 | 
			
		||||
 * |i_CTRL-R_CTRL-R|      TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-R_CTRL-O|      TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-R_CTRL-P|      TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-T|             {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightLinesAction}
 | 
			
		||||
 * |i_CTRL-U|             {@link com.maddyhome.idea.vim.action.change.insert.InsertDeleteInsertedTextAction}
 | 
			
		||||
 * |i_CTRL-V|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
 | 
			
		||||
 * |i_CTRL-V_digit|       {@link com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction}
 | 
			
		||||
 * |i_CTRL-W|             {@link com.maddyhome.idea.vim.action.change.insert.InsertDeletePreviousWordAction}
 | 
			
		||||
 * |i_CTRL-X|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-Y|             {@link com.maddyhome.idea.vim.action.change.insert.InsertCharacterAboveCursorAction}
 | 
			
		||||
 * |i_CTRL-Z|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_<Esc>|              {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
			
		||||
 * |i_CTRL-[|             {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
 | 
			
		||||
 * |i_CTRL-\_CTRL-N|      {@link com.maddyhome.idea.vim.action.ResetModeAction}
 | 
			
		||||
 * |i_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-]}             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-^|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_CTRL-_|             TO BE IMPLEMENTED
 | 
			
		||||
 * |i_0_CTRL-D|           TO BE IMPLEMENTED
 | 
			
		||||
 * |i_^_CTRL-D|           TO BE IMPLEMENTED
 | 
			
		||||
 * |i_<Del>|              {@link com.maddyhome.idea.vim.action.editor.VimEditorDelete}
 | 
			
		||||
 * |i_<Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftInsertModeAction}
 | 
			
		||||
 * |i_<S-Left>|           {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
 | 
			
		||||
 * |i_<C-Left>|           {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftInsertAction}
 | 
			
		||||
 * |i_<Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightInsertAction}
 | 
			
		||||
 * |i_<S-Right>|          {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
 | 
			
		||||
 * |i_<C-Right>|          {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightInsertAction}
 | 
			
		||||
 * |i_<Up>|               {@link com.maddyhome.idea.vim.action.editor.VimEditorUp}
 | 
			
		||||
 * |i_<S-Up>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
 | 
			
		||||
 * |i_<Down>|             {@link com.maddyhome.idea.vim.action.editor.VimEditorDown}
 | 
			
		||||
 * |i_<S-Down>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
 | 
			
		||||
 * |i_<Home>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnInsertModeAction}
 | 
			
		||||
 * |i_<C-Home>|           {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstInsertAction}
 | 
			
		||||
 * |i_<End>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnInsertAction}
 | 
			
		||||
 * |i_<C-End>|            {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndInsertAction}
 | 
			
		||||
 * |i_<Insert>|           {@link com.maddyhome.idea.vim.action.change.insert.InsertInsertAction}
 | 
			
		||||
 * |i_<PageUp>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpInsertModeAction}
 | 
			
		||||
 * |i_<PageDown>|         {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownInsertModeAction}
 | 
			
		||||
 * |i_<F1>|               IntelliJ help
 | 
			
		||||
 * |i_<Insert>|           IntelliJ editor toggle insert/replace
 | 
			
		||||
 * |i_CTRL-X_index|       TO BE IMPLEMENTED
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Normal mode
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |CTRL-A|               {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberIncAction}
 | 
			
		||||
 * |CTRL-B|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
 | 
			
		||||
 * |CTRL-C|               TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-D|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageDownAction}
 | 
			
		||||
 * |CTRL-E|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineDownAction}
 | 
			
		||||
 * |CTRL-F|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
 | 
			
		||||
 * |CTRL-G|               {@link com.maddyhome.idea.vim.action.file.FileGetFileInfoAction}
 | 
			
		||||
 * |<BS>|                 {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
 | 
			
		||||
 * |CTRL-H|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionBackspaceAction}
 | 
			
		||||
 * |<Tab>|                TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-I|               {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpNextAction}
 | 
			
		||||
 * |<NL>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownNotLineWiseAction}
 | 
			
		||||
 * |CTRL-J|               TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-L|               not applicable
 | 
			
		||||
 * |<CR>|                 {@link com.maddyhome.idea.vim.action.motion.updown.EnterNormalAction}
 | 
			
		||||
 * |CTRL-M|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
 | 
			
		||||
 * |CTRL-N|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction}
 | 
			
		||||
 * |CTRL-O|               {@link com.maddyhome.idea.vim.action.motion.mark.MotionJumpPreviousAction}
 | 
			
		||||
 * |CTRL-P|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpCtrlPAction}
 | 
			
		||||
 * |CTRL-R|               {@link com.maddyhome.idea.vim.action.change.RedoAction}
 | 
			
		||||
 * |CTRL-T|               TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-U|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfPageUpAction}
 | 
			
		||||
 * |CTRL-V|               {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleBlockModeAction}
 | 
			
		||||
 * |CTRL-W|               see window commands
 | 
			
		||||
 * |CTRL-X|               {@link com.maddyhome.idea.vim.action.change.change.number.ChangeNumberDecAction}
 | 
			
		||||
 * |CTRL-Y|               {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLineUpAction}
 | 
			
		||||
 * |CTRL-Z|               TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-]|               {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
			
		||||
 * |CTRL-6|               {@link com.maddyhome.idea.vim.action.file.FilePreviousAction}
 | 
			
		||||
 * |CTRL-\CTRL-N|         {@link com.maddyhome.idea.vim.action.ResetModeAction}
 | 
			
		||||
 * |<Space>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionSpaceAction}
 | 
			
		||||
 * |!|                    {@link com.maddyhome.idea.vim.action.change.change.FilterMotionAction}
 | 
			
		||||
 * |!!|                   translated to !_
 | 
			
		||||
 * |quote|                handled by command key parser
 | 
			
		||||
 * |#|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordBackwardAction}
 | 
			
		||||
 * |$|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastColumnAction}
 | 
			
		||||
 * |%|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionPercentOrMatchAction}
 | 
			
		||||
 * |&|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeLastSearchReplaceAction}
 | 
			
		||||
 * |'|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineAction}
 | 
			
		||||
 * |''|                   ?
 | 
			
		||||
 * ...
 | 
			
		||||
 * |(|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousStartAction}
 | 
			
		||||
 * |)|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextStartAction}
 | 
			
		||||
 * |star|                 {@link com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction}
 | 
			
		||||
 * |+|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownFirstNonSpaceAction}
 | 
			
		||||
 * |,|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharReverseAction}
 | 
			
		||||
 * |-|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpFirstNonSpaceAction}
 | 
			
		||||
 * |.|                    {@link com.maddyhome.idea.vim.action.change.RepeatChangeAction}
 | 
			
		||||
 * |/|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryFwdAction}
 | 
			
		||||
 * |:|                    {@link com.maddyhome.idea.vim.action.ex.ExEntryAction}
 | 
			
		||||
 * |;|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastMatchCharAction}
 | 
			
		||||
 * |<|                    {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftMotionAction}
 | 
			
		||||
 * |<<|                   translated to <_
 | 
			
		||||
 * |=|                    {@link com.maddyhome.idea.vim.action.change.shift.AutoIndentMotionAction}
 | 
			
		||||
 * |==|                   translated to =_
 | 
			
		||||
 * |>|                    {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightMotionAction}
 | 
			
		||||
 * |>>|                   translated to >_
 | 
			
		||||
 * |?|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchEntryRevAction}
 | 
			
		||||
 * |@|                    {@link com.maddyhome.idea.vim.action.macro.PlaybackRegisterAction}
 | 
			
		||||
 * |A|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterLineEndAction}
 | 
			
		||||
 * |B|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordLeftAction}
 | 
			
		||||
 * |C|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction}
 | 
			
		||||
 * |D|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteEndOfLineAction}
 | 
			
		||||
 * |E|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndRightAction}
 | 
			
		||||
 * |F|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftMatchCharAction}
 | 
			
		||||
 * |G|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastAction}
 | 
			
		||||
 * |H|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionFirstScreenLineAction}
 | 
			
		||||
 * |H|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingFirstScreenLineAction}
 | 
			
		||||
 * |I|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeFirstNonBlankAction}
 | 
			
		||||
 * |J|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction}
 | 
			
		||||
 * |K|                    {@link com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc}
 | 
			
		||||
 * |L|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionLastScreenLineAction}
 | 
			
		||||
 * |L|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionOpPendingLastScreenLineAction}
 | 
			
		||||
 * |M|                    {@link com.maddyhome.idea.vim.action.motion.screen.MotionMiddleScreenLineAction}
 | 
			
		||||
 * |N|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainPreviousAction}
 | 
			
		||||
 * |O|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineAboveAction}
 | 
			
		||||
 * |P|                    {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorAction}
 | 
			
		||||
 * |Q|                    TO BE IMPLEMENTED
 | 
			
		||||
 * |R|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeReplaceAction}
 | 
			
		||||
 * |S|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeLineAction}
 | 
			
		||||
 * |T|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftTillMatchCharAction}
 | 
			
		||||
 * |U|                    ?
 | 
			
		||||
 * |V|                    {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleLineModeAction}
 | 
			
		||||
 * |W|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordRightAction}
 | 
			
		||||
 * |X|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterLeftAction}
 | 
			
		||||
 * |Y|                    {@link com.maddyhome.idea.vim.action.copy.YankLineAction}
 | 
			
		||||
 * |ZZ|                   {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
 | 
			
		||||
 * |ZQ|                   {@link com.maddyhome.idea.vim.action.file.FileSaveCloseAction}
 | 
			
		||||
 * |[|                    see bracket commands
 | 
			
		||||
 * |]|                    see bracket commands
 | 
			
		||||
 * |^|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstNonSpaceAction}
 | 
			
		||||
 * |_|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction}
 | 
			
		||||
 * |`|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkAction}
 | 
			
		||||
 * |``|                   ?
 | 
			
		||||
 * ...
 | 
			
		||||
 * |0|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstColumnAction}
 | 
			
		||||
 * |a|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertAfterCursorAction}
 | 
			
		||||
 * |b|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
 | 
			
		||||
 * |c|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeMotionAction}
 | 
			
		||||
 * |cc|                   translated to c_
 | 
			
		||||
 * |d|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteMotionAction}
 | 
			
		||||
 * |dd|                   translated to d_
 | 
			
		||||
 * |do|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |dp|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |e|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndRightAction}
 | 
			
		||||
 * |f|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction}
 | 
			
		||||
 * |g|                    see commands starting with 'g'
 | 
			
		||||
 * |h|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLeftAction}
 | 
			
		||||
 * |i|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
 | 
			
		||||
 * |j|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionDownAction}
 | 
			
		||||
 * |k|                    {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpAction}
 | 
			
		||||
 * |l|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightAction}
 | 
			
		||||
 * |m|                    {@link com.maddyhome.idea.vim.action.motion.mark.MotionMarkAction}
 | 
			
		||||
 * |n|                    {@link com.maddyhome.idea.vim.action.motion.search.SearchAgainNextAction}
 | 
			
		||||
 * |o|                    {@link com.maddyhome.idea.vim.action.change.insert.InsertNewLineBelowAction}
 | 
			
		||||
 * |p|                    {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorAction}
 | 
			
		||||
 * |q|                    {@link com.maddyhome.idea.vim.action.macro.ToggleRecordingAction}
 | 
			
		||||
 * |r|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction}
 | 
			
		||||
 * |s|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction}
 | 
			
		||||
 * |t|                    {@link com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction}
 | 
			
		||||
 * |u|                    {@link com.maddyhome.idea.vim.action.change.UndoAction}
 | 
			
		||||
 * |v|                    {@link com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction}
 | 
			
		||||
 * |w|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
 | 
			
		||||
 * |x|                    {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterRightAction}
 | 
			
		||||
 * |y|                    {@link com.maddyhome.idea.vim.action.copy.YankMotionAction}
 | 
			
		||||
 * |yy|                   translated to y_
 | 
			
		||||
 * |z|                    see commands starting with 'z'
 | 
			
		||||
 * |{|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphPreviousAction}
 | 
			
		||||
 * |bar|                  {@link com.maddyhome.idea.vim.action.motion.leftright.MotionColumnAction}
 | 
			
		||||
 * |}|                    {@link com.maddyhome.idea.vim.action.motion.text.MotionParagraphNextAction}
 | 
			
		||||
 * |~|                    {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction}
 | 
			
		||||
 * |<C-End>|              {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineLastEndAction}
 | 
			
		||||
 * |<C-Home>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
 | 
			
		||||
 * |<C-Left>|             {@link com.maddyhome.idea.vim.action.motion.text.MotionWordLeftAction}
 | 
			
		||||
 * |<C-Right>|            {@link com.maddyhome.idea.vim.action.motion.text.MotionWordRightAction}
 | 
			
		||||
 * |<C-Down>|             {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlDownAction}
 | 
			
		||||
 * |<C-Up>|               {@link com.maddyhome.idea.vim.action.motion.scroll.CtrlUpAction}
 | 
			
		||||
 * |<Del>|                {@link com.maddyhome.idea.vim.action.change.delete.DeleteCharacterAction}
 | 
			
		||||
 * |<Down>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
 | 
			
		||||
 * |<End>|                {@link com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction}
 | 
			
		||||
 * |<F1>|                 IntelliJ help
 | 
			
		||||
 * |<Home>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction}
 | 
			
		||||
 * |<Insert>|             {@link com.maddyhome.idea.vim.action.change.insert.InsertBeforeCursorAction}
 | 
			
		||||
 * |<Left>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowLeftAction}
 | 
			
		||||
 * |<PageDown>|           {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageDownAction}
 | 
			
		||||
 * |<PageUp>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollPageUpAction}
 | 
			
		||||
 * |<Right>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionArrowRightAction}
 | 
			
		||||
 * |<S-Down>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
 | 
			
		||||
 * |<S-Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
 | 
			
		||||
 * |<S-Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
 | 
			
		||||
 * |<S-Up>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
 | 
			
		||||
 * |<S-Home>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction}
 | 
			
		||||
 * |<S-End>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction}
 | 
			
		||||
 * |<Up>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2.1. Text objects
 | 
			
		||||
 *
 | 
			
		||||
 * Text object commands are listed in the visual mode section.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2.2. Window commands
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |CTRL-W_+|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_-|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_<|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_=|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_>|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_H|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_J|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_K|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_L|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_P|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_R|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_S|             {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
 | 
			
		||||
 * |CTRL-W_T|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_W|             {@link com.maddyhome.idea.vim.action.window.WindowPrevAction}
 | 
			
		||||
 * |CTRL-W_]|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_^|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W__|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_b|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_c|             {@link com.maddyhome.idea.vim.action.window.CloseWindowAction}
 | 
			
		||||
 * |CTRL-W_d|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_f|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W-F|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W-g]|            TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W-g}|            TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W-gf|            TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W-gF|            TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_h|             {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
			
		||||
 * |CTRL-W_i|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_j|             {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
			
		||||
 * |CTRL-W_k|             {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
			
		||||
 * |CTRL-W_l|             {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
			
		||||
 * |CTRL-W_n|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_o|             {@link com.maddyhome.idea.vim.action.window.WindowOnlyAction}
 | 
			
		||||
 * |CTRL-W_p|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_q|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_r|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_s|             {@link com.maddyhome.idea.vim.action.window.HorizontalSplitAction}
 | 
			
		||||
 * |CTRL-W_t|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_v|             {@link com.maddyhome.idea.vim.action.window.VerticalSplitAction}
 | 
			
		||||
 * |CTRL-W_w|             {@link com.maddyhome.idea.vim.action.window.WindowNextAction}
 | 
			
		||||
 * |CTRL-W_x|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_z|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_bar|           TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_}|             TO BE IMPLEMENTED
 | 
			
		||||
 * |CTRL-W_<Down>|        {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
			
		||||
 * |CTRL-W_<Up>|          {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
			
		||||
 * |CTRL-W_<Left>|        {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
			
		||||
 * |CTRL-W_<Right>|       {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
			
		||||
 * |CTRL-W_CTRL-H|        {@link com.maddyhome.idea.vim.action.window.WindowLeftAction}
 | 
			
		||||
 * |CTRL-W_CTRL-J|        {@link com.maddyhome.idea.vim.action.window.WindowDownAction}
 | 
			
		||||
 * |CTRL-W_CTRL-K|        {@link com.maddyhome.idea.vim.action.window.WindowUpAction}
 | 
			
		||||
 * |CTRL-W_CTRL-L|        {@link com.maddyhome.idea.vim.action.window.WindowRightAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2.3. Square bracket commands
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 * |[_CTRL-D|             TO BE IMPLEMENTED
 | 
			
		||||
 * |[_CTRL-I|             TO BE IMPLEMENTED
 | 
			
		||||
 * |[#|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |['|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[(|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenOpenAction}
 | 
			
		||||
 * |[star|                TO BE IMPLEMENTED
 | 
			
		||||
 * |[`|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[/|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[D|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[I|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[M|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousEndAction}
 | 
			
		||||
 * |[P|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
 | 
			
		||||
 * |[P|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
 | 
			
		||||
 * |[[|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardStartAction}
 | 
			
		||||
 * |[]|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionBackwardEndAction}
 | 
			
		||||
 * |[c|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[d|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[f|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[i|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
 | 
			
		||||
 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
			
		||||
 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
			
		||||
 * |[s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
 | 
			
		||||
 * |[z|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |[{|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
 | 
			
		||||
 * |]_CTRL-D|             TO BE IMPLEMENTED
 | 
			
		||||
 * |]_CTRL-I|             TO BE IMPLEMENTED
 | 
			
		||||
 * |]#|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]'|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |])|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedParenCloseAction}
 | 
			
		||||
 * |]star|                TO BE IMPLEMENTED
 | 
			
		||||
 * |]`|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]/|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]D|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]I|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]M|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction}
 | 
			
		||||
 * |]P|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorNoIndentAction}
 | 
			
		||||
 * |]P|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorNoIndentAction}
 | 
			
		||||
 * |][|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardEndAction}
 | 
			
		||||
 * |]]|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSectionForwardStartAction}
 | 
			
		||||
 * |]c|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]d|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]f|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]i|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
 | 
			
		||||
 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
			
		||||
 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
			
		||||
 * |]s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
 | 
			
		||||
 * |]z|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |]}|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2.4. Commands starting with 'g'
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |g_CTRL-A|             not applicable
 | 
			
		||||
 * |g_CTRL-G|             {@link com.maddyhome.idea.vim.action.file.FileGetLocationInfoAction}
 | 
			
		||||
 * |g_CTRL-H|             {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableBlockModeAction}
 | 
			
		||||
 * |g_CTRL-]|             TO BE IMPLEMENTED
 | 
			
		||||
 * |g#|                   {@link com.maddyhome.idea.vim.action.motion.search.SearchWordBackwardAction}
 | 
			
		||||
 * |g$|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
 | 
			
		||||
 * |g&|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeLastGlobalSearchReplaceAction}
 | 
			
		||||
 * |v_g'|                 {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineNoSaveJumpAction}
 | 
			
		||||
 * |g'|                   {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkLineNoSaveJumpAction}
 | 
			
		||||
 * |g`|                   {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoMarkNoSaveJumpAction}
 | 
			
		||||
 * |gstar|                {@link com.maddyhome.idea.vim.action.motion.search.SearchWordForwardAction}
 | 
			
		||||
 * |g+|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g,|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g-|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g0|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
 | 
			
		||||
 * |g8|                   {@link com.maddyhome.idea.vim.action.file.FileGetHexAction}
 | 
			
		||||
 * |g;|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g<|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g?|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g?g?|                 TO BE IMPLEMENTED
 | 
			
		||||
 * |gD|                   {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
			
		||||
 * |gE|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionBigWordEndLeftAction}
 | 
			
		||||
 * |gF|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gH|                   {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableLineModeAction}
 | 
			
		||||
 * |gI|                   {@link com.maddyhome.idea.vim.action.change.insert.InsertLineStartAction}
 | 
			
		||||
 * |gJ|                   {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction}
 | 
			
		||||
 * |gN|                   {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch}
 | 
			
		||||
 * |gN|                   {@link com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject}
 | 
			
		||||
 * |gP|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorMoveCursorAction}
 | 
			
		||||
 * |gP|                   {@link com.maddyhome.idea.vim.action.copy.PutTextBeforeCursorActionMoveCursor}
 | 
			
		||||
 * |gQ|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gR|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gT|                   {@link com.maddyhome.idea.vim.action.window.tabs.PreviousTabAction}
 | 
			
		||||
 * |gU|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction}
 | 
			
		||||
 * |gV|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g]|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g^|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenNonSpaceAction}
 | 
			
		||||
 * |g_|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastNonSpaceAction}
 | 
			
		||||
 * |ga|                   {@link com.maddyhome.idea.vim.action.file.FileGetAsciiAction}
 | 
			
		||||
 * |gd|                   {@link com.maddyhome.idea.vim.action.motion.search.GotoDeclarationAction}
 | 
			
		||||
 * |ge|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionWordEndLeftAction}
 | 
			
		||||
 * |gf|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gg|                   {@link com.maddyhome.idea.vim.action.motion.updown.MotionGotoLineFirstAction}
 | 
			
		||||
 * |gh|                   {@link com.maddyhome.idea.vim.action.motion.select.SelectEnableCharacterModeAction}
 | 
			
		||||
 * |gi|                   {@link com.maddyhome.idea.vim.action.change.insert.InsertAtPreviousInsertAction}
 | 
			
		||||
 * |gj|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gk|                   {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
 | 
			
		||||
 * |gn|                   {@link com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch}
 | 
			
		||||
 * |gn|                   {@link com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject}
 | 
			
		||||
 * |gm|                   {@link com.maddyhome.idea.vim.action.motion.leftright.MotionMiddleColumnAction}
 | 
			
		||||
 * |go|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionNthCharacterAction}
 | 
			
		||||
 * |gp|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorMoveCursorAction}
 | 
			
		||||
 * |gp|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorActionMoveCursor}
 | 
			
		||||
 * |gq|                   {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeMotionAction}
 | 
			
		||||
 * |gr|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gs|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |gt|                   {@link com.maddyhome.idea.vim.action.window.tabs.NextTabAction}
 | 
			
		||||
 * |gu|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction}
 | 
			
		||||
 * |gv|                   {@link com.maddyhome.idea.vim.action.motion.visual.VisualSelectPreviousAction}
 | 
			
		||||
 * |gw|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |g@|                   {@link com.maddyhome.idea.vim.action.change.OperatorAction}
 | 
			
		||||
 * |g~|                   {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction}
 | 
			
		||||
 * |g<Down>|              TO BE IMPLEMENTED
 | 
			
		||||
 * |g<End>|               {@link com.maddyhome.idea.vim.action.motion.leftright.MotionLastScreenColumnAction}
 | 
			
		||||
 * |g<Home>|              {@link com.maddyhome.idea.vim.action.motion.leftright.MotionFirstScreenColumnAction}
 | 
			
		||||
 * |g<Up>|                {@link com.maddyhome.idea.vim.action.motion.updown.MotionUpNotLineWiseAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 2.5. Commands starting with 'z'
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 * |z<CR>|                {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineStartAction}
 | 
			
		||||
 * |z+|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLinePageStartAction}
 | 
			
		||||
 * |z-|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineStartAction}
 | 
			
		||||
 * |z.|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineStartAction}
 | 
			
		||||
 * |z=|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zA|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zC|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegionRecursively}
 | 
			
		||||
 * |zD|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zE|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zF|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zG|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zH|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction}
 | 
			
		||||
 * |zL|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction}
 | 
			
		||||
 * |zM|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseAllRegions}
 | 
			
		||||
 * |zN|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zO|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandRegionRecursively}
 | 
			
		||||
 * |zR|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandAllRegions}
 | 
			
		||||
 * |zW|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zX|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |z^|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLinePageStartAction}
 | 
			
		||||
 * |za|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zb|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenLineAction}
 | 
			
		||||
 * |zc|                   {@link com.maddyhome.idea.vim.action.fold.VimCollapseRegion}
 | 
			
		||||
 * |zd|                   not applicable
 | 
			
		||||
 * |ze|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollLastScreenColumnAction}
 | 
			
		||||
 * |zf|                   not applicable
 | 
			
		||||
 * |zg|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zh|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
 | 
			
		||||
 * |zi|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zj|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zk|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zl|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
 | 
			
		||||
 * |zm|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zn|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zo|                   {@link com.maddyhome.idea.vim.action.fold.VimExpandRegion}
 | 
			
		||||
 * |zr|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zs|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenColumnAction}
 | 
			
		||||
 * |zt|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollFirstScreenLineAction}
 | 
			
		||||
 * |zv|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zw|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zx|                   TO BE IMPLEMENTED
 | 
			
		||||
 * |zz|                   {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollMiddleScreenLineAction}
 | 
			
		||||
 * |z<Left>|              {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction}
 | 
			
		||||
 * |z<Right>|             {@link com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnLeftAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Visual mode
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |v_CTRL-\_CTRL-N|      {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
			
		||||
 * |v_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
			
		||||
 * |v_CTRL-A|             {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberIncAction}
 | 
			
		||||
 * |v_CTRL-C|             {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
			
		||||
 * |v_CTRL-G|             {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
 | 
			
		||||
 * |v_<BS>|               NVO mapping
 | 
			
		||||
 * |v_CTRL-H|             NVO mapping
 | 
			
		||||
 * |v_CTRL-O|             TO BE IMPLEMENTED
 | 
			
		||||
 * |v_CTRL-V|             NVO mapping
 | 
			
		||||
 * |v_<Esc>|              {@link com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction}
 | 
			
		||||
 * |v_CTRL-X|             {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberDecAction}
 | 
			
		||||
 * |v_CTRL-]|             TO BE IMPLEMENTED
 | 
			
		||||
 * |v_!|                  {@link com.maddyhome.idea.vim.action.change.change.FilterVisualLinesAction}
 | 
			
		||||
 * |v_:|                  NVO mapping
 | 
			
		||||
 * |v_<|                  {@link com.maddyhome.idea.vim.action.change.shift.ShiftLeftVisualAction}
 | 
			
		||||
 * |v_=|                  {@link com.maddyhome.idea.vim.action.change.change.AutoIndentLinesVisualAction}
 | 
			
		||||
 * |v_>|                  {@link com.maddyhome.idea.vim.action.change.shift.ShiftRightVisualAction}
 | 
			
		||||
 * |v_b_A|                {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockAppendAction}
 | 
			
		||||
 * |v_C|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesEndAction}
 | 
			
		||||
 * |v_D|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesEndAction}
 | 
			
		||||
 * |v_b_I|                {@link com.maddyhome.idea.vim.action.change.insert.VisualBlockInsertAction}
 | 
			
		||||
 * |v_J|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction}
 | 
			
		||||
 * |v_K|                  TO BE IMPLEMENTED
 | 
			
		||||
 * |v_O|                  {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsBlockAction}
 | 
			
		||||
 * |v_P|                  {@link com.maddyhome.idea.vim.action.copy.PutVisualTextBeforeCursorAction}
 | 
			
		||||
 * |v_R|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
 | 
			
		||||
 * |v_S|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualLinesAction}
 | 
			
		||||
 * |v_U|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction}
 | 
			
		||||
 * |v_V|                  NV mapping
 | 
			
		||||
 * |v_X|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualLinesAction}
 | 
			
		||||
 * |v_Y|                  {@link com.maddyhome.idea.vim.action.copy.YankVisualLinesAction}
 | 
			
		||||
 * |v_aquote|             {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockDoubleQuoteAction}
 | 
			
		||||
 * |v_a'|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockSingleQuoteAction}
 | 
			
		||||
 * |v_a(|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
			
		||||
 * |v_a)|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
			
		||||
 * |v_a<|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
 | 
			
		||||
 * |v_a>|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockAngleAction}
 | 
			
		||||
 * |v_aB|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
			
		||||
 * |v_aW|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction}
 | 
			
		||||
 * |v_a[|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
 | 
			
		||||
 * |v_a]|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBracketAction}
 | 
			
		||||
 * |v_a`|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBackQuoteAction}
 | 
			
		||||
 * |v_ab|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockParenAction}
 | 
			
		||||
 * |v_ap|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterParagraphAction}
 | 
			
		||||
 * |v_as|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterSentenceAction}
 | 
			
		||||
 * |v_at|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockTagAction}
 | 
			
		||||
 * |v_aw|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction}
 | 
			
		||||
 * |v_a{|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
			
		||||
 * |v_a}|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionOuterBlockBraceAction}
 | 
			
		||||
 * |v_c|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
 | 
			
		||||
 * |v_d|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
 | 
			
		||||
 * |v_gCTRL-A|            {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheIncAction}
 | 
			
		||||
 * |v_gCTRL-X|            {@link com.maddyhome.idea.vim.action.change.change.number.ChangeVisualNumberAvalancheDecAction}
 | 
			
		||||
 * |v_gJ|                 {@link com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction}
 | 
			
		||||
 * |v_gq|                 {@link com.maddyhome.idea.vim.action.change.change.ReformatCodeVisualAction}
 | 
			
		||||
 * |v_gv|                 {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapSelectionsAction}
 | 
			
		||||
 * |v_g`|                 {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkNoSaveJumpAction}
 | 
			
		||||
 * |v_g@|                 {@link com.maddyhome.idea.vim.action.change.VisualOperatorAction}
 | 
			
		||||
 * |v_iquote|             {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockDoubleQuoteAction}
 | 
			
		||||
 * |v_i'|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockSingleQuoteAction}
 | 
			
		||||
 * |v_i(|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
			
		||||
 * |v_i)|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
			
		||||
 * |v_i<|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
 | 
			
		||||
 * |v_i>|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockAngleAction}
 | 
			
		||||
 * |v_iB|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
			
		||||
 * |v_iW|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBigWordAction}
 | 
			
		||||
 * |v_i[|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
 | 
			
		||||
 * |v_i]|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBracketAction}
 | 
			
		||||
 * |v_i`|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBackQuoteAction}
 | 
			
		||||
 * |v_ib|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockParenAction}
 | 
			
		||||
 * |v_ip|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerParagraphAction}
 | 
			
		||||
 * |v_is|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerSentenceAction}
 | 
			
		||||
 * |v_it|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockTagAction}
 | 
			
		||||
 * |v_iw|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerWordAction}
 | 
			
		||||
 * |v_i{|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
			
		||||
 * |v_i}|                 {@link com.maddyhome.idea.vim.action.motion.object.MotionInnerBlockBraceAction}
 | 
			
		||||
 * |v_o|                  {@link com.maddyhome.idea.vim.action.motion.visual.VisualSwapEndsAction}
 | 
			
		||||
 * |v_p|                  {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorAction}
 | 
			
		||||
 * |v_r|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualCharacterAction}
 | 
			
		||||
 * |v_s|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeVisualAction}
 | 
			
		||||
 * |v_u|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction}
 | 
			
		||||
 * |v_v|                  NV mapping
 | 
			
		||||
 * |v_x|                  {@link com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction}
 | 
			
		||||
 * |v_y|                  {@link com.maddyhome.idea.vim.action.copy.YankVisualAction}
 | 
			
		||||
 * |v_~|                  {@link com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction}
 | 
			
		||||
 * |v_`|                  {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkAction}
 | 
			
		||||
 * |v_'|                  {@link com.maddyhome.idea.vim.action.motion.mark.MotionGotoFileMarkLineAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 4. Select mode
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 * |<BS>|                 {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
 | 
			
		||||
 * |<CR>|                 {@link com.maddyhome.idea.vim.action.motion.select.SelectEnterAction}
 | 
			
		||||
 * |<DEL>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectDeleteAction}
 | 
			
		||||
 * |<ESC>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectEscapeAction}
 | 
			
		||||
 * |<C-G>|                {@link com.maddyhome.idea.vim.action.motion.select.SelectToggleVisualMode}
 | 
			
		||||
 * |<S-Down>|             {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction}
 | 
			
		||||
 * |<S-Left>|             {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction}
 | 
			
		||||
 * |<S-Right>|            {@link com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction}
 | 
			
		||||
 * |<S-Up>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction}
 | 
			
		||||
 * |<Down>|               {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowDownAction}
 | 
			
		||||
 * |<Left>|               {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionLeftAction}
 | 
			
		||||
 * |<Right>|              {@link com.maddyhome.idea.vim.action.motion.select.motion.SelectMotionRightAction}
 | 
			
		||||
 * |<Up>|                 {@link com.maddyhome.idea.vim.action.motion.updown.MotionArrowUpAction}
 | 
			
		||||
 *
 | 
			
		||||
 * 5. Command line editing
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    action
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |c_CTRL-A|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-B|             {@link javax.swing.text.DefaultEditorKit#beginLineAction}
 | 
			
		||||
 * |c_CTRL-C|             {@link com.maddyhome.idea.vim.ui.ex.CancelEntryAction}
 | 
			
		||||
 * |c_CTRL-D|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-E|             {@link javax.swing.text.DefaultEditorKit#endLineAction}
 | 
			
		||||
 * |c_CTRL-G|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-H|             {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
 | 
			
		||||
 * |c_CTRL-I|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-J|             {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
			
		||||
 * |c_CTRL-K|             Handled by KeyHandler
 | 
			
		||||
 * |c_CTRL-L|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-M|             {@link com.maddyhome.idea.vim.action.ex.ProcessExEntryAction}
 | 
			
		||||
 * |c_CTRL-N|             {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
			
		||||
 * |c_CTRL-P|             {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
			
		||||
 * |c_CTRL-Q|             Handled by KeyHandler
 | 
			
		||||
 * |c_CTRL-R_CTRL-A|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-F|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-L|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-O|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-P|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-R|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-R_CTRL-W|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-T|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-U|             {@link com.maddyhome.idea.vim.ui.ex.DeleteToCursorAction}
 | 
			
		||||
 * |c_CTRL-V|             Handled by KeyHandler
 | 
			
		||||
 * |c_CTRL-W|             {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousWordAction}
 | 
			
		||||
 * |c_CTRL-Y|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-\_e|           TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-\_CTRL-G|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-\_CTRL-N|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-_|             not applicable
 | 
			
		||||
 * |c_CTRL-^|             not applicable
 | 
			
		||||
 * |c_CTRL-]|             TO BE IMPLEMENTED
 | 
			
		||||
 * |c_CTRL-[|             {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
 | 
			
		||||
 * |c_<BS>|               {@link com.maddyhome.idea.vim.ui.ex.DeletePreviousCharAction}
 | 
			
		||||
 * |c_<CR>|               {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
			
		||||
 * |c_<C-Left>|           {@link javax.swing.text.DefaultEditorKit#previousWordAction}
 | 
			
		||||
 * |c_<C-Right>|          {@link javax.swing.text.DefaultEditorKit#nextWordAction}
 | 
			
		||||
 * |c_<Del>|              {@link javax.swing.text.DefaultEditorKit#deleteNextCharAction}
 | 
			
		||||
 * |c_<Down>|             {@link com.maddyhome.idea.vim.ui.ex.HistoryDownFilterAction}
 | 
			
		||||
 * |c_<End>|              {@link javax.swing.text.DefaultEditorKit#endLineAction}
 | 
			
		||||
 * |c_<Esc>|              {@link com.maddyhome.idea.vim.ui.ex.EscapeCharAction}
 | 
			
		||||
 * |c_<Home>|             {@link javax.swing.text.DefaultEditorKit#beginLineAction}
 | 
			
		||||
 * |c_<Insert>|           {@link com.maddyhome.idea.vim.ui.ex.ToggleInsertReplaceAction}
 | 
			
		||||
 * |c_<Left>|             {@link javax.swing.text.DefaultEditorKit#backwardAction}
 | 
			
		||||
 * |c_<LeftMouse>|        not applicable
 | 
			
		||||
 * |c_<MiddleMouse>|      TO BE IMPLEMENTED
 | 
			
		||||
 * |c_<NL>|               {@link com.maddyhome.idea.vim.ui.ex.CompleteEntryAction}
 | 
			
		||||
 * |c_<PageUp>|           {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
			
		||||
 * |c_<PageDown>|         {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
			
		||||
 * |c_<Right>|            {@link javax.swing.text.DefaultEditorKit#forwardAction}
 | 
			
		||||
 * |c_<S-Down>|           {@link com.maddyhome.idea.vim.ui.ex.HistoryDownAction}
 | 
			
		||||
 * |c_<S-Left>|           {@link javax.swing.text.DefaultEditorKit#previousWordAction}
 | 
			
		||||
 * |c_<S-Right>|          {@link javax.swing.text.DefaultEditorKit#nextWordAction}
 | 
			
		||||
 * |c_<S-Tab>|            TO BE IMPLEMENTED
 | 
			
		||||
 * |c_<S-Up>|             {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
 | 
			
		||||
 * |c_<Tab>|              TO BE IMPLEMENTED
 | 
			
		||||
 * |c_<Up>|               {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
 | 
			
		||||
 * |c_digraph|            {char1} <BS> {char2}
 | 
			
		||||
 * |c_wildchar|           TO BE IMPLEMENTED
 | 
			
		||||
 * |'cedit'|              TO BE IMPLEMENTED
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 6. Ex commands
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    handler
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * |:map|                 {@link com.maddyhome.idea.vim.vimscript.model.commands.mapping.MapCommand}
 | 
			
		||||
 * |:nmap|                ...
 | 
			
		||||
 * |:vmap|                ...
 | 
			
		||||
 * |:omap|                ...
 | 
			
		||||
 * |:imap|                ...
 | 
			
		||||
 * |:cmap|                ...
 | 
			
		||||
 * |:noremap|             ...
 | 
			
		||||
 * |:nnoremap|            ...
 | 
			
		||||
 * |:vnoremap|            ...
 | 
			
		||||
 * |:onoremap|            ...
 | 
			
		||||
 * |:inoremap|            ...
 | 
			
		||||
 * |:cnoremap|            ...
 | 
			
		||||
 * |:shell|               {@link com.maddyhome.idea.vim.vimscript.model.commands.ShellCommand}
 | 
			
		||||
 * |:sort|                {@link com.maddyhome.idea.vim.vimscript.model.commands.SortCommand}
 | 
			
		||||
 * |:source|              {@link com.maddyhome.idea.vim.vimscript.model.commands.SourceCommand}
 | 
			
		||||
 * |:qall|                {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
			
		||||
 * |:quitall|             {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
			
		||||
 * |:quitall|             {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
			
		||||
 * |:wqall|               {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
			
		||||
 * |:xall|                {@link com.maddyhome.idea.vim.vimscript.model.commands.ExitCommand}
 | 
			
		||||
 * |:command|             {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdCommand}
 | 
			
		||||
 * |:delcommand|          {@link com.maddyhome.idea.vim.vimscript.model.commands.DelCmdCommand}
 | 
			
		||||
 * |:comclear|            {@link com.maddyhome.idea.vim.vimscript.model.commands.CmdClearCommand}
 | 
			
		||||
 * ...
 | 
			
		||||
 *
 | 
			
		||||
 * The list of supported Ex commands is incomplete.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * A. Misc commands
 | 
			
		||||
 *
 | 
			
		||||
 * tag                    handler
 | 
			
		||||
 * -------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 * |]b|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndLeftAction}
 | 
			
		||||
 * |]w|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelEndRightAction}
 | 
			
		||||
 * |[b|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelLeftAction}
 | 
			
		||||
 * |[w|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionCamelRightAction}
 | 
			
		||||
 * |g(|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSentencePreviousEndAction}
 | 
			
		||||
 * |g)|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionSentenceNextEndAction}
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * See also :help index.
 | 
			
		||||
 *
 | 
			
		||||
 * @author vlan
 | 
			
		||||
 */
 | 
			
		||||
package com.maddyhome.idea.vim;
 | 
			
		||||
@@ -192,6 +192,13 @@ private object VimActionsPopup {
 | 
			
		||||
        null,
 | 
			
		||||
      ),
 | 
			
		||||
    )
 | 
			
		||||
    actionGroup.add(
 | 
			
		||||
      HelpLink(
 | 
			
		||||
        "Take Survey ↗",
 | 
			
		||||
        "https://surveys.jetbrains.com/s3/ideavim-usage-survey",
 | 
			
		||||
        AllIcons.Actions.IntentionBulb,
 | 
			
		||||
      ),
 | 
			
		||||
    )
 | 
			
		||||
    actionGroup.addSeparator(MessageHelper.message("action.eap.choice.active.text"))
 | 
			
		||||
 | 
			
		||||
    actionGroup.add(JoinEap)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,263 +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.ui.ex
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.diagnostic.logger
 | 
			
		||||
import com.intellij.openapi.editor.textarea.TextComponentEditorImpl
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.api.LocalOptionInitialisationScenario
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import java.awt.event.ActionEvent
 | 
			
		||||
import java.awt.event.KeyEvent
 | 
			
		||||
import javax.swing.Action
 | 
			
		||||
import javax.swing.KeyStroke
 | 
			
		||||
import javax.swing.text.BadLocationException
 | 
			
		||||
import javax.swing.text.DefaultEditorKit
 | 
			
		||||
import javax.swing.text.Document
 | 
			
		||||
import javax.swing.text.TextAction
 | 
			
		||||
import kotlin.math.abs
 | 
			
		||||
import kotlin.math.min
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal interface MultiStepAction : Action {
 | 
			
		||||
  fun reset()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class HistoryUpAction : TextAction(ExEditorKit.HistoryUp) {
 | 
			
		||||
  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(actionEvent) as ExTextField
 | 
			
		||||
    target.selectHistory(true, false)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class HistoryDownAction : TextAction(ExEditorKit.HistoryDown) {
 | 
			
		||||
  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(actionEvent) as ExTextField
 | 
			
		||||
    target.selectHistory(false, false)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class HistoryUpFilterAction : TextAction(ExEditorKit.HistoryUpFilter) {
 | 
			
		||||
  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(actionEvent) as ExTextField
 | 
			
		||||
    target.selectHistory(true, true)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class HistoryDownFilterAction : TextAction(ExEditorKit.HistoryDownFilter) {
 | 
			
		||||
  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(actionEvent) as ExTextField
 | 
			
		||||
    target.selectHistory(false, true)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class CompleteEntryAction : TextAction(ExEditorKit.CompleteEntry) {
 | 
			
		||||
  override fun actionPerformed(actionEvent: ActionEvent) {
 | 
			
		||||
    logger.debug("complete entry")
 | 
			
		||||
    val stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
 | 
			
		||||
 | 
			
		||||
    // We send the <Enter> keystroke through the key handler rather than calling ProcessGroup#processExEntry directly.
 | 
			
		||||
    // We do this for a couple of reasons:
 | 
			
		||||
    // * The C mode mapping for ProcessExEntryAction handles the actual entry, and most importantly, it does so as a
 | 
			
		||||
    //   write action
 | 
			
		||||
    // * The key handler routines get the chance to clean up and reset state
 | 
			
		||||
    val entry = ExEntryPanel.getInstance().entry
 | 
			
		||||
    val keyHandler = KeyHandler.getInstance()
 | 
			
		||||
    keyHandler.handleKey(entry.editor!!.vim, stroke, entry.context.vim, keyHandler.keyHandlerState)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    private val logger = logger<CompleteEntryAction>()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class CancelEntryAction : TextAction(ExEditorKit.CancelEntry) {
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.cancel()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class EscapeCharAction : TextAction(ExEditorKit.EscapeChar) {
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.escape()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal abstract class DeleteCharAction internal constructor(name: String?) : TextAction(name) {
 | 
			
		||||
  @kotlin.jvm.Throws(BadLocationException::class)
 | 
			
		||||
  fun deleteSelection(doc: Document, dot: Int, mark: Int): Boolean {
 | 
			
		||||
    if (dot != mark) {
 | 
			
		||||
      doc.remove(min(dot, mark), abs(dot - mark))
 | 
			
		||||
      return true
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @kotlin.jvm.Throws(BadLocationException::class)
 | 
			
		||||
  fun deleteNextChar(doc: Document, dot: Int): Boolean {
 | 
			
		||||
    if (dot < doc.length) {
 | 
			
		||||
      var delChars = 1
 | 
			
		||||
      if (dot < doc.length - 1) {
 | 
			
		||||
        val dotChars = doc.getText(dot, 2)
 | 
			
		||||
        val c0 = dotChars[0]
 | 
			
		||||
        val c1 = dotChars[1]
 | 
			
		||||
        if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
 | 
			
		||||
          delChars = 2
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      doc.remove(dot, delChars)
 | 
			
		||||
      return true
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @kotlin.jvm.Throws(BadLocationException::class)
 | 
			
		||||
  fun deletePrevChar(doc: Document, dot: Int): Boolean {
 | 
			
		||||
    if (dot > 0) {
 | 
			
		||||
      var delChars = 1
 | 
			
		||||
      if (dot > 1) {
 | 
			
		||||
        val dotChars = doc.getText(dot - 2, 2)
 | 
			
		||||
        val c0 = dotChars[0]
 | 
			
		||||
        val c1 = dotChars[1]
 | 
			
		||||
        if (c0 in '\uD800'..'\uDBFF' && c1 in '\uDC00'..'\uDFFF') {
 | 
			
		||||
          delChars = 2
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      doc.remove(dot - delChars, delChars)
 | 
			
		||||
      return true
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class DeleteNextCharAction : DeleteCharAction(DefaultEditorKit.deleteNextCharAction) {
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.saveLastEntry()
 | 
			
		||||
    try {
 | 
			
		||||
      val doc = target.document
 | 
			
		||||
      val caret = target.caret
 | 
			
		||||
      val dot = caret.dot
 | 
			
		||||
      val mark = caret.mark
 | 
			
		||||
      if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
 | 
			
		||||
        target.cancel()
 | 
			
		||||
      }
 | 
			
		||||
    } catch (ex: BadLocationException) {
 | 
			
		||||
      // ignore
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class DeletePreviousCharAction : DeleteCharAction(DefaultEditorKit.deletePrevCharAction) {
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.saveLastEntry()
 | 
			
		||||
    try {
 | 
			
		||||
      val doc = target.document
 | 
			
		||||
      val caret = target.caret
 | 
			
		||||
      val dot = caret.dot
 | 
			
		||||
      val mark = caret.mark
 | 
			
		||||
      if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
 | 
			
		||||
        if (dot == 0 && doc.length == 0) {
 | 
			
		||||
          target.cancel()
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (bl: BadLocationException) {
 | 
			
		||||
      // ignore
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class DeletePreviousWordAction : TextAction(DefaultEditorKit.deletePrevWordAction) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Invoked when an action occurs.
 | 
			
		||||
   */
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.saveLastEntry()
 | 
			
		||||
    val doc = target.document
 | 
			
		||||
    val caret = target.caret
 | 
			
		||||
    val project = target.editor!!.project
 | 
			
		||||
 | 
			
		||||
    // Create a VimEditor instance on the Swing text field which we can pass to the search helpers. We need an editor
 | 
			
		||||
    // rather than just working on a buffer because the search helpers need local options (specifically the local to
 | 
			
		||||
    // buffer 'iskeyword'). We use the CMD_LINE scenario to initialise local options from the main editor. The options
 | 
			
		||||
    // service will copy all local-to-buffer and local-to-window options, effectively cloning the options.
 | 
			
		||||
    // TODO: Over time, we should migrate all ex actions to be based on VimEditor
 | 
			
		||||
    // This will mean we always have an editor that has been initialised for options, etc. But also means that we can
 | 
			
		||||
    // share the command line entry actions between IdeaVim implementations
 | 
			
		||||
    val editor = TextComponentEditorImpl(project, target).vim
 | 
			
		||||
    injector.optionGroup.initialiseLocalOptions(editor, target.editor!!.vim, LocalOptionInitialisationScenario.CMD_LINE)
 | 
			
		||||
 | 
			
		||||
    val offset = injector.searchHelper.findNextWord(editor, caret.dot, -1, bigWord = false, spaceWords = false)
 | 
			
		||||
    if (logger.isDebugEnabled) logger.debug("offset=$offset")
 | 
			
		||||
    try {
 | 
			
		||||
      val pos = caret.dot
 | 
			
		||||
      doc.remove(offset, pos - offset)
 | 
			
		||||
    } catch (ex: BadLocationException) {
 | 
			
		||||
      // ignore
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    private val logger = logger<DeletePreviousWordAction>()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class DeleteToCursorAction : TextAction(ExEditorKit.DeleteToCursor) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Invoked when an action occurs.
 | 
			
		||||
   */
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.saveLastEntry()
 | 
			
		||||
    val doc = target.document
 | 
			
		||||
    val caret = target.caret
 | 
			
		||||
    try {
 | 
			
		||||
      doc.remove(0, caret.dot)
 | 
			
		||||
    } catch (ex: BadLocationException) {
 | 
			
		||||
      // ignore
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal class ToggleInsertReplaceAction : TextAction(ExEditorKit.ToggleInsertReplace) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Invoked when an action occurs.
 | 
			
		||||
   */
 | 
			
		||||
  override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
    logger.debug("actionPerformed")
 | 
			
		||||
    val target = getTextComponent(e) as ExTextField
 | 
			
		||||
    target.toggleInsertReplace()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init {
 | 
			
		||||
    logger.debug("ToggleInsertReplaceAction()")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    private val logger = logger<ToggleInsertReplaceAction>()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,7 @@ public class ExDocument extends PlainDocument {
 | 
			
		||||
  void toggleInsertReplace() {
 | 
			
		||||
    VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
 | 
			
		||||
    if (commandLine != null) {
 | 
			
		||||
      commandLine.toggleReplaceMode();
 | 
			
		||||
      ((ExEntryPanel) commandLine).isReplaceMode = !((ExEntryPanel)commandLine).isReplaceMode;
 | 
			
		||||
    }
 | 
			
		||||
    overwrite = !overwrite;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
 */
 | 
			
		||||
package com.maddyhome.idea.vim.ui.ex
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.diagnostic.debug
 | 
			
		||||
import com.intellij.openapi.diagnostic.logger
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
@@ -15,50 +14,12 @@ import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import org.jetbrains.annotations.NonNls
 | 
			
		||||
import java.awt.event.ActionEvent
 | 
			
		||||
import java.awt.event.KeyEvent
 | 
			
		||||
import javax.swing.Action
 | 
			
		||||
import javax.swing.KeyStroke
 | 
			
		||||
import javax.swing.text.DefaultEditorKit
 | 
			
		||||
import javax.swing.text.Document
 | 
			
		||||
import javax.swing.text.TextAction
 | 
			
		||||
 | 
			
		||||
@Deprecated("ExCommands should be migrated to KeyHandler like commands for other modes")
 | 
			
		||||
internal object ExEditorKit : DefaultEditorKit() {
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val CancelEntry: String = "cancel-entry"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val CompleteEntry: String = "complete-entry"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val EscapeChar: String = "escape"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val DeleteToCursor: String = "delete-to-cursor"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val ToggleInsertReplace: String = "toggle-insert"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val HistoryUp: String = "history-up"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val HistoryDown: String = "history-down"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val HistoryUpFilter: String = "history-up-filter"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val HistoryDownFilter: String = "history-down-filter"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val StartDigraph: String = "start-digraph"
 | 
			
		||||
 | 
			
		||||
  @NonNls
 | 
			
		||||
  val StartLiteral: String = "start-literal"
 | 
			
		||||
 | 
			
		||||
  private val logger = logger<ExEditorKit>()
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets the MIME type of the data that this
 | 
			
		||||
   * kit represents support for.
 | 
			
		||||
@@ -70,19 +31,6 @@ internal object ExEditorKit : DefaultEditorKit() {
 | 
			
		||||
    return "text/ideavim"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Fetches the set of commands that can be used
 | 
			
		||||
   * on a text component that is using a model and
 | 
			
		||||
   * view produced by this kit.
 | 
			
		||||
   *
 | 
			
		||||
   * @return the set of actions
 | 
			
		||||
   */
 | 
			
		||||
  override fun getActions(): Array<Action> {
 | 
			
		||||
    val res = TextAction.augmentList(super.getActions(), exActions)
 | 
			
		||||
    logger.debug { "res.length=${res.size}" }
 | 
			
		||||
    return res
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates an uninitialized text storage model
 | 
			
		||||
   * that is appropriate for this type of editor.
 | 
			
		||||
@@ -93,48 +41,29 @@ internal object ExEditorKit : DefaultEditorKit() {
 | 
			
		||||
    return ExDocument()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private val exActions = arrayOf<Action>(
 | 
			
		||||
    CancelEntryAction(),
 | 
			
		||||
    CompleteEntryAction(),
 | 
			
		||||
    EscapeCharAction(),
 | 
			
		||||
    DeleteNextCharAction(),
 | 
			
		||||
    DeletePreviousCharAction(),
 | 
			
		||||
    DeletePreviousWordAction(),
 | 
			
		||||
    DeleteToCursorAction(),
 | 
			
		||||
    HistoryUpAction(),
 | 
			
		||||
    HistoryDownAction(),
 | 
			
		||||
    HistoryUpFilterAction(),
 | 
			
		||||
    HistoryDownFilterAction(),
 | 
			
		||||
    ToggleInsertReplaceAction(),
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  class DefaultExKeyHandler : DefaultKeyTypedAction() {
 | 
			
		||||
    override fun actionPerformed(e: ActionEvent) {
 | 
			
		||||
      val target = getTextComponent(e) as ExTextField
 | 
			
		||||
      val currentAction = target.currentAction
 | 
			
		||||
      if (currentAction != null) {
 | 
			
		||||
        currentAction.actionPerformed(e)
 | 
			
		||||
      } else {
 | 
			
		||||
        val key = convert(e)
 | 
			
		||||
        if (key != null) {
 | 
			
		||||
          val c = key.keyChar
 | 
			
		||||
          if (c.code > 0) {
 | 
			
		||||
            if (target.useHandleKeyFromEx) {
 | 
			
		||||
              val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
 | 
			
		||||
              val entry = panel.entry
 | 
			
		||||
              val editor = entry.editor
 | 
			
		||||
              val keyHandler = KeyHandler.getInstance()
 | 
			
		||||
              keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
 | 
			
		||||
            } else {
 | 
			
		||||
              val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
 | 
			
		||||
              super.actionPerformed(event)
 | 
			
		||||
            }
 | 
			
		||||
            target.saveLastEntry()
 | 
			
		||||
 | 
			
		||||
      val key = convert(e)
 | 
			
		||||
      if (key != null) {
 | 
			
		||||
        val c = key.keyChar
 | 
			
		||||
        if (c.code > 0) {
 | 
			
		||||
          if (target.useHandleKeyFromEx) {
 | 
			
		||||
            val panel = ((injector.commandLine.getActiveCommandLine() as? ExEntryPanel) ?: (injector.modalInput.getCurrentModalInput() as? WrappedAsModalInputExEntryPanel)?.exEntryPanel) ?: return
 | 
			
		||||
            val entry = panel.entry
 | 
			
		||||
            val editor = entry.editor
 | 
			
		||||
            val keyHandler = KeyHandler.getInstance()
 | 
			
		||||
            keyHandler.handleKey(editor!!.vim, key, entry.context.vim, keyHandler.keyHandlerState)
 | 
			
		||||
          } else {
 | 
			
		||||
            val event = ActionEvent(e.source, e.id, c.toString(), e.getWhen(), e.modifiers)
 | 
			
		||||
            super.actionPerformed(event)
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          super.actionPerformed(e)
 | 
			
		||||
          target.saveLastEntry()
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        super.actionPerformed(e)
 | 
			
		||||
        target.saveLastEntry()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,10 @@ import com.maddyhome.idea.vim.EventFacade;
 | 
			
		||||
import com.maddyhome.idea.vim.KeyHandler;
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
			
		||||
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
 | 
			
		||||
import com.maddyhome.idea.vim.api.*;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCommandLine;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimKeyGroupBase;
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ranges.LineRange;
 | 
			
		||||
import com.maddyhome.idea.vim.helper.SearchHighlightsHelper;
 | 
			
		||||
import com.maddyhome.idea.vim.helper.UiHelper;
 | 
			
		||||
@@ -60,7 +63,7 @@ import static com.maddyhome.idea.vim.group.KeyGroup.toShortcutSet;
 | 
			
		||||
public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
  public static ExEntryPanel instance;
 | 
			
		||||
  public static ExEntryPanel instanceWithoutShortcuts;
 | 
			
		||||
  private boolean isReplaceMode = false;
 | 
			
		||||
  public boolean isReplaceMode = false;
 | 
			
		||||
  private WeakReference<Editor> weakEditor = null;
 | 
			
		||||
 | 
			
		||||
  private VimInputInterceptor myInputInterceptor = null;
 | 
			
		||||
@@ -341,14 +344,14 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get the current count from the command builder. This value is coerced to at least 1, so will always be valid.
 | 
			
		||||
        // The aggregated value includes any counts for operator and register selections, and the uncommitted count for
 | 
			
		||||
        // the search command (`/` or `?`). E.g., `2"a3"b4"c5d6/` would return 720.
 | 
			
		||||
        // If we're showing highlights for an ex command like `:s`, there won't be a command, but the value is already
 | 
			
		||||
        // coerced to at least 1.
 | 
			
		||||
        int count1 = KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder().getAggregatedUncommittedCount();
 | 
			
		||||
        // Get a snapshot of the count for the in progress command, and coerce it to 1. This value will include all
 | 
			
		||||
        // count components - selecting register(s), operator and motions. E.g. `2"a3"b4"c5d6/` will return 720.
 | 
			
		||||
        // If we're showing highlights for an Ex command like `:s`, the command builder will be empty, but we'll still
 | 
			
		||||
        // get a valid value.
 | 
			
		||||
        int count1 = Math.max(1, KeyHandler.getInstance().getKeyHandlerState().getEditorCommandBuilder()
 | 
			
		||||
          .calculateCount0Snapshot());
 | 
			
		||||
 | 
			
		||||
        if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
 | 
			
		||||
        if ((labelText.equals("/") || labelText.equals("?") || searchCommand) && !injector.getMacro().isExecutingMacro()) {
 | 
			
		||||
          final boolean forwards = !labelText.equals("?");  // :s, :g, :v are treated as forwards
 | 
			
		||||
          int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
 | 
			
		||||
          final String pattern = searchText.substring(0, pattenEnd);
 | 
			
		||||
@@ -402,7 +405,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void toggleReplaceMode() {
 | 
			
		||||
    isReplaceMode = !isReplaceMode;
 | 
			
		||||
    entry.toggleInsertReplace();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -528,17 +531,17 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
 | 
			
		||||
  private static final Logger logger = Logger.getInstance(ExEntryPanel.class.getName());
 | 
			
		||||
 | 
			
		||||
  @NotNull
 | 
			
		||||
  @Override
 | 
			
		||||
  public VimCommandLineCaret getCaret() {
 | 
			
		||||
  public @NotNull VimCommandLineCaret getCaret() {
 | 
			
		||||
    return (VimCommandLineCaret) entry.getCaret();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void setText(@NotNull String string) {
 | 
			
		||||
  public void setText(@NotNull String string, boolean updateLastEntry) {
 | 
			
		||||
    // It's a feature of Swing that caret is moved when we set new text. However, our API is Swing independent and we do not expect this
 | 
			
		||||
    int offset = getCaret().getOffset();
 | 
			
		||||
    entry.updateText(string);
 | 
			
		||||
    if (updateLastEntry) entry.saveLastEntry();
 | 
			
		||||
    getCaret().setOffset(Math.min(offset, getVisibleText().length()));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -547,9 +550,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
    entry.clearCurrentAction();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  @Override
 | 
			
		||||
  public Integer getPromptCharacterOffset() {
 | 
			
		||||
  public @Nullable Integer getPromptCharacterOffset() {
 | 
			
		||||
    int offset = entry.currentActionPromptCharacterOffset;
 | 
			
		||||
    return offset == -1 ? null : offset;
 | 
			
		||||
  }
 | 
			
		||||
@@ -569,8 +571,7 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
    IdeFocusManager.findInstance().requestFocus(entry, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  public VimInputInterceptor<?> getInputInterceptor() {
 | 
			
		||||
  public @Nullable VimInputInterceptor<?> getInputInterceptor() {
 | 
			
		||||
    return myInputInterceptor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -583,18 +584,37 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 | 
			
		||||
    myInputInterceptor = vimInputInterceptor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  @Override
 | 
			
		||||
  public Function1<String, Unit> getInputProcessing() {
 | 
			
		||||
  public @Nullable Function1<String, Unit> getInputProcessing() {
 | 
			
		||||
    return inputProcessing;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  @Override
 | 
			
		||||
  public Character getFinishOn() {
 | 
			
		||||
  public @Nullable Character getFinishOn() {
 | 
			
		||||
    return finishOn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public int getHistIndex() {
 | 
			
		||||
    return entry.histIndex;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void setHistIndex(int i) {
 | 
			
		||||
    entry.histIndex = i;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @NotNull
 | 
			
		||||
  @Override
 | 
			
		||||
  public String getLastEntry() {
 | 
			
		||||
    return entry.lastEntry;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void setLastEntry(@NotNull String s) {
 | 
			
		||||
    entry.lastEntry = s;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static class LafListener implements LafManagerListener {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void lookAndFeelChanged(@NotNull LafManager source) {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,57 +21,6 @@ internal object ExKeyBindings {
 | 
			
		||||
 | 
			
		||||
  val bindings: Array<KeyBinding> by lazy {
 | 
			
		||||
    arrayOf(
 | 
			
		||||
      // Escape will cancel a pending insert digraph/register before cancelling
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ExEditorKit.EscapeChar),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.EscapeChar),
 | 
			
		||||
 | 
			
		||||
      // Cancel entry, ignoring any pending actions such as digraph/registry entry
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CancelEntry),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ExEditorKit.CompleteEntry),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.CompleteEntry),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(0x02.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.beginLineAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), DefaultEditorKit.beginLineAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(0x05.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.endLineAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), DefaultEditorKit.endLineAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.deletePrevCharAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(0x08.toChar().code, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevCharAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DefaultEditorKit.deleteNextCharAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.deletePrevWordAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.DeleteToCursor),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ExEditorKit.HistoryUpFilter),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryUp),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ExEditorKit.HistoryUp),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryUp),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ExEditorKit.HistoryDownFilter),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), ExEditorKit.HistoryDown),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ExEditorKit.HistoryDown),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.HistoryDown),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), ExEditorKit.ToggleInsertReplace),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.previousWordAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.previousWordAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), DefaultEditorKit.forwardAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.nextWordAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.nextWordAction),
 | 
			
		||||
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartDigraph),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK), ExEditorKit.StartLiteral),
 | 
			
		||||
 | 
			
		||||
      // These appear to be non-Vim shortcuts
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
			
		||||
      KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction),
 | 
			
		||||
 
 | 
			
		||||
@@ -59,9 +59,45 @@ internal class ExShortcutKeyAction(private val exEntryPanel: ExEntryPanel) : Dum
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun registerCustomShortcutSet() {
 | 
			
		||||
    val shortcuts = ExKeyBindings.bindings.map {
 | 
			
		||||
      KeyboardShortcut(it.key, null)
 | 
			
		||||
    }.toTypedArray()
 | 
			
		||||
    val shortcuts = listOf(
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK),
 | 
			
		||||
        KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK),
 | 
			
		||||
    )
 | 
			
		||||
      .map { KeyboardShortcut(it, null) }
 | 
			
		||||
      .toTypedArray()
 | 
			
		||||
 | 
			
		||||
    registerCustomShortcutSet({ shortcuts }, exEntryPanel)
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,9 @@ import com.intellij.util.ui.JBUI;
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCommandLine;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimCommandLineCaret;
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
			
		||||
import com.maddyhome.idea.vim.helper.UiHelper;
 | 
			
		||||
import com.maddyhome.idea.vim.history.HistoryConstants;
 | 
			
		||||
import com.maddyhome.idea.vim.history.HistoryEntry;
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
			
		||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorAttributes;
 | 
			
		||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorMode;
 | 
			
		||||
import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper;
 | 
			
		||||
@@ -67,9 +65,6 @@ public class ExTextField extends JTextField {
 | 
			
		||||
        // If we're in the middle of an action (e.g. entering a register to paste, or inserting a digraph), cancel it if
 | 
			
		||||
        // the mouse is clicked anywhere. Vim's behavior is to use the mouse click as an event, which can lead to
 | 
			
		||||
        // something like : !%!C, which I don't believe is documented, or useful
 | 
			
		||||
        if (currentAction != null) {
 | 
			
		||||
          clearCurrentAction();
 | 
			
		||||
        }
 | 
			
		||||
        super.mouseClicked(e);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
@@ -240,20 +235,15 @@ public class ExTextField extends JTextField {
 | 
			
		||||
    // This gets called for ALL events, before the IDE starts to process key events for the action system. We can add a
 | 
			
		||||
    // dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField,
 | 
			
		||||
    // dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed.
 | 
			
		||||
    if (currentAction != null) {
 | 
			
		||||
      currentAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, String.valueOf(c), modifiers));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :
 | 
			
		||||
        (stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED),
 | 
			
		||||
        (new Date()).getTime(), modifiers, keyCode, c);
 | 
			
		||||
    KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :
 | 
			
		||||
                                        (stroke.isOnKeyRelease() ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED),
 | 
			
		||||
                                  (new Date()).getTime(), modifiers, keyCode, c);
 | 
			
		||||
 | 
			
		||||
      useHandleKeyFromEx = false;
 | 
			
		||||
      try {
 | 
			
		||||
        super.processKeyEvent(event);
 | 
			
		||||
      }finally {
 | 
			
		||||
        useHandleKeyFromEx = true;
 | 
			
		||||
      }
 | 
			
		||||
    useHandleKeyFromEx = false;
 | 
			
		||||
    try {
 | 
			
		||||
      super.processKeyEvent(event);
 | 
			
		||||
    } finally {
 | 
			
		||||
      useHandleKeyFromEx = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -279,12 +269,7 @@ public class ExTextField extends JTextField {
 | 
			
		||||
   * Cancels current action, if there is one. If not, cancels entry.
 | 
			
		||||
   */
 | 
			
		||||
  void escape() {
 | 
			
		||||
    if (currentAction != null) {
 | 
			
		||||
      clearCurrentAction();
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      cancel();
 | 
			
		||||
    }
 | 
			
		||||
    cancel();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -299,19 +284,10 @@ public class ExTextField extends JTextField {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void clearCurrentAction() {
 | 
			
		||||
    if (currentAction != null) {
 | 
			
		||||
      currentAction.reset();
 | 
			
		||||
    }
 | 
			
		||||
    currentAction = null;
 | 
			
		||||
    VimCommandLine commandLine = injector.getCommandLine().getActiveCommandLine();
 | 
			
		||||
    if (commandLine != null) commandLine.clearPromptCharacter();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Nullable
 | 
			
		||||
  Action getCurrentAction() {
 | 
			
		||||
    return currentAction;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void setInsertMode() {
 | 
			
		||||
    ExDocument doc = (ExDocument)getDocument();
 | 
			
		||||
    if (doc.isOverwrite()) {
 | 
			
		||||
@@ -542,10 +518,9 @@ public class ExTextField extends JTextField {
 | 
			
		||||
 | 
			
		||||
  private DataContext context;
 | 
			
		||||
  private final CommandLineCaret caret;
 | 
			
		||||
  private String lastEntry;
 | 
			
		||||
  String lastEntry;
 | 
			
		||||
  private List<HistoryEntry> history;
 | 
			
		||||
  private int histIndex = 0;
 | 
			
		||||
  private @Nullable MultiStepAction currentAction;
 | 
			
		||||
  int histIndex = 0;
 | 
			
		||||
  int currentActionPromptCharacterOffset = -1;
 | 
			
		||||
 | 
			
		||||
  private static final Logger logger = Logger.getInstance(ExTextField.class.getName());
 | 
			
		||||
 
 | 
			
		||||
@@ -8,114 +8,20 @@
 | 
			
		||||
 | 
			
		||||
package com.maddyhome.idea.vim.vimscript
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.actionSystem.DataContext
 | 
			
		||||
import com.intellij.openapi.components.Service
 | 
			
		||||
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.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimScriptExecutorBase
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExException
 | 
			
		||||
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.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.VimLContext
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.commands.Command
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.model.commands.RepeatCommand
 | 
			
		||||
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
internal class Executor : VimScriptExecutorBase() {
 | 
			
		||||
  private val logger = logger<Executor>()
 | 
			
		||||
  override var executingVimscript = false
 | 
			
		||||
  override var executingIdeaVimRcConfiguration = false
 | 
			
		||||
 | 
			
		||||
  @Throws(ExException::class)
 | 
			
		||||
  override fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult {
 | 
			
		||||
    try {
 | 
			
		||||
      injector.vimscriptExecutor.executingVimscript = true
 | 
			
		||||
      var finalResult: ExecutionResult = ExecutionResult.Success
 | 
			
		||||
 | 
			
		||||
      val myScript = VimscriptParser.parse(script)
 | 
			
		||||
      myScript.units.forEach { it.vimContext = vimContext ?: myScript }
 | 
			
		||||
 | 
			
		||||
      for (unit in myScript.units) {
 | 
			
		||||
        try {
 | 
			
		||||
          val result = unit.execute(editor, context)
 | 
			
		||||
          if (result is ExecutionResult.Error) {
 | 
			
		||||
            finalResult = ExecutionResult.Error
 | 
			
		||||
            if (indicateErrors) {
 | 
			
		||||
              VimPlugin.indicateError()
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } catch (e: ExException) {
 | 
			
		||||
          if (e is FinishException) {
 | 
			
		||||
            break
 | 
			
		||||
          }
 | 
			
		||||
          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(e)
 | 
			
		||||
          if (injector.application.isUnitTest()) {
 | 
			
		||||
            throw e
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!skipHistory) {
 | 
			
		||||
        VimPlugin.getHistory().addEntry(HistoryConstants.COMMAND, script)
 | 
			
		||||
        if (myScript.units.size == 1 && myScript.units[0] is Command && myScript.units[0] !is RepeatCommand) {
 | 
			
		||||
          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()
 | 
			
		||||
    }
 | 
			
		||||
  override fun enableDelayedExtensions() {
 | 
			
		||||
    VimExtensionRegistrar.enableDelayedExtensions()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun executeFile(file: File, editor: VimEditor, fileIsIdeaVimRcConfig: Boolean, indicateErrors: Boolean) {
 | 
			
		||||
    val context = DataContext.EMPTY_CONTEXT.vim
 | 
			
		||||
    try {
 | 
			
		||||
      if (fileIsIdeaVimRcConfig) {
 | 
			
		||||
        injector.vimscriptExecutor.executingIdeaVimRcConfiguration = true
 | 
			
		||||
      }
 | 
			
		||||
      ensureFileIsSaved(file)
 | 
			
		||||
      execute(file.readText(), editor, context, skipHistory = true, indicateErrors)
 | 
			
		||||
    } catch (ignored: IOException) {
 | 
			
		||||
      LOG.error(ignored)
 | 
			
		||||
    } finally {
 | 
			
		||||
      if (fileIsIdeaVimRcConfig) {
 | 
			
		||||
        injector.vimrcFileState.saveFileState(file.absolutePath)
 | 
			
		||||
        injector.vimscriptExecutor.executingIdeaVimRcConfiguration = false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun ensureFileIsSaved(file: File) {
 | 
			
		||||
  override fun ensureFileIsSaved(file: File) {
 | 
			
		||||
    val documentManager = FileDocumentManager.getInstance()
 | 
			
		||||
 | 
			
		||||
    VirtualFileManager.getInstance().findFileByNioPath(file.toPath())
 | 
			
		||||
@@ -123,16 +29,4 @@ internal class Executor : VimScriptExecutorBase() {
 | 
			
		||||
      ?.takeIf(documentManager::isDocumentUnsaved)
 | 
			
		||||
      ?.let(documentManager::saveDocumentAsIs)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Throws(ExException::class)
 | 
			
		||||
  override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
			
		||||
    val reg = VimPlugin.getRegister().getRegister(':') ?: return false
 | 
			
		||||
    val text = reg.text ?: return false
 | 
			
		||||
    execute(text, editor, context, skipHistory = false, indicateErrors = true, CommandLineVimLContext)
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    val LOG = logger<Executor>()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,9 @@ internal data class ActionListCommand(val range: Range, val argument: String) :
 | 
			
		||||
      .filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } }
 | 
			
		||||
      .joinToString(lineSeparator)
 | 
			
		||||
 | 
			
		||||
    ExOutputModel.getInstance(editor.ij).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
 | 
			
		||||
    val outputPanel = injector.outputPanel.getOrCreate(editor, context)
 | 
			
		||||
    outputPanel.addText(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions))
 | 
			
		||||
    outputPanel.show()
 | 
			
		||||
    return ExecutionResult.Success
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ import com.intellij.vim.annotations.ExCommand
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ranges.Range
 | 
			
		||||
import com.maddyhome.idea.vim.helper.EditorHelper
 | 
			
		||||
import com.maddyhome.idea.vim.helper.vimLine
 | 
			
		||||
@@ -45,7 +45,9 @@ internal data class BufferListCommand(val range: Range, val argument: String) :
 | 
			
		||||
    val filter = pruneUnsupportedFilters(arg)
 | 
			
		||||
    val bufferList = getBufferList(context, filter)
 | 
			
		||||
 | 
			
		||||
    ExOutputModel.getInstance(editor.ij).output(bufferList.joinToString(separator = "\n"))
 | 
			
		||||
    val outputPanel = injector.outputPanel.getOrCreate(editor, context)
 | 
			
		||||
    outputPanel.addText(bufferList.joinToString(separator = "\n"))
 | 
			
		||||
    outputPanel.show()
 | 
			
		||||
 | 
			
		||||
    return ExecutionResult.Success
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ import com.intellij.vim.annotations.ExCommand
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.api.ExecutionContext
 | 
			
		||||
import com.maddyhome.idea.vim.api.VimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.command.OperatorArguments
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExException
 | 
			
		||||
import com.maddyhome.idea.vim.ex.ExOutputModel
 | 
			
		||||
@@ -74,7 +75,9 @@ internal data class CmdFilterCommand(val range: Range, val argument: String) : C
 | 
			
		||||
      if (range.size() == 0) {
 | 
			
		||||
        // Show command output in a window
 | 
			
		||||
        VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let {
 | 
			
		||||
          ExOutputModel.getInstance(editor.ij).output(it)
 | 
			
		||||
          val outputPanel = injector.outputPanel.getOrCreate(editor, context)
 | 
			
		||||
          outputPanel.addText(it)
 | 
			
		||||
          outputPanel.show()
 | 
			
		||||
        }
 | 
			
		||||
        lastCommand = command
 | 
			
		||||
        ExecutionResult.Success
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,4 @@
 | 
			
		||||
<!--
 | 
			
		||||
  ~ 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.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
 | 
			
		||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
 | 
			
		||||
  <name>IdeaVim</name>
 | 
			
		||||
  <id>IdeaVIM</id>
 | 
			
		||||
  <description><![CDATA[
 | 
			
		||||
@@ -21,7 +13,7 @@
 | 
			
		||||
        <li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
 | 
			
		||||
      </ul>
 | 
			
		||||
    ]]></description>
 | 
			
		||||
  <version>SNAPSHOT</version>
 | 
			
		||||
  <version>chylex</version>
 | 
			
		||||
  <vendor>JetBrains</vendor>
 | 
			
		||||
 | 
			
		||||
  <!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
 | 
			
		||||
@@ -133,10 +125,12 @@
 | 
			
		||||
  <xi:include href="/META-INF/includes/VimListeners.xml" xpointer="xpointer(/idea-plugin/*)"/>
 | 
			
		||||
 | 
			
		||||
  <actions resource-bundle="messages.IdeaVimBundle">
 | 
			
		||||
    <action id="VimPluginToggle" class="com.maddyhome.idea.vim.action.VimPluginToggleAction">
 | 
			
		||||
    <group id="com.chylex.intellij.vim" text="Vim" popup="true">
 | 
			
		||||
      <add-to-group group-id="ToolsMenu" anchor="last"/>
 | 
			
		||||
    </action>
 | 
			
		||||
 | 
			
		||||
      <action id="VimPluginToggle" class="com.maddyhome.idea.vim.action.VimPluginToggleAction"/>
 | 
			
		||||
      <action id="VimRunLastMacroInOpenFiles" class="com.maddyhome.idea.vim.action.VimRunLastMacroInOpenFiles"/>
 | 
			
		||||
    </group>
 | 
			
		||||
    
 | 
			
		||||
    <!-- Internal -->
 | 
			
		||||
    <!--suppress PluginXmlI18n -->
 | 
			
		||||
    <action id="VimInternalAddBlockInlays" class="com.maddyhome.idea.vim.action.internal.AddBlockInlaysAction" text="Add Test Block Inlays | IdeaVim Internal" internal="true"/>
 | 
			
		||||
@@ -154,5 +148,6 @@
 | 
			
		||||
    </group>
 | 
			
		||||
 | 
			
		||||
    <action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
 | 
			
		||||
    <action id="VimJumpToSource" class="com.intellij.diff.actions.impl.OpenInEditorAction" />
 | 
			
		||||
  </actions>
 | 
			
		||||
</idea-plugin>
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ viminfo
 | 
			
		||||
virtualedit
 | 
			
		||||
visualbell
 | 
			
		||||
visualdelay
 | 
			
		||||
whichwrap
 | 
			
		||||
wrapscan
 | 
			
		||||
 | 
			
		||||
nobomb
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								src/main/resources/ksp-generated/intellij_commands.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/main/resources/ksp-generated/intellij_commands.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "keys": ".",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.RepeatChangeAction",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<C-I>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<C-L>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.RedrawAction",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<Del>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorDelete",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<Down>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<Tab>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<Up>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<kDown>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "<kUp>",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
 | 
			
		||||
        "modes": "I"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "J",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "J",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction",
 | 
			
		||||
        "modes": "X"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "K",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "g@",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.OperatorAction",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "g@",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.VisualOperatorAction",
 | 
			
		||||
        "modes": "X"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "gJ",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction",
 | 
			
		||||
        "modes": "N"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "keys": "gJ",
 | 
			
		||||
        "class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction",
 | 
			
		||||
        "modes": "X"
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
    "!": "com.maddyhome.idea.vim.vimscript.model.commands.CmdFilterCommand",
 | 
			
		||||
    "actionl[ist]": "com.maddyhome.idea.vim.vimscript.model.commands.ActionListCommand",
 | 
			
		||||
    "b[uffer]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCommand",
 | 
			
		||||
    "buffers": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
 | 
			
		||||
    "files": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
 | 
			
		||||
    "h[elp]": "com.maddyhome.idea.vim.vimscript.model.commands.HelpCommand",
 | 
			
		||||
    "ls": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand"
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "col": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ColFunctionHandler",
 | 
			
		||||
    "has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
 | 
			
		||||
    "line": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LineFunctionHandler",
 | 
			
		||||
    "submatch": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler"
 | 
			
		||||
}
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.jetbrains.plugins.ideavim.action
 | 
			
		||||
 | 
			
		||||
import com.intellij.idea.TestFor
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.Mode
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.ReturnTo
 | 
			
		||||
@@ -1068,4 +1069,14 @@ foobaz
 | 
			
		||||
      Mode.NORMAL(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  @TestFor(issues = ["VIM-2074"])
 | 
			
		||||
  fun `backspace with replace mode`() {
 | 
			
		||||
    configureByText("${c}Hello world")
 | 
			
		||||
    typeText("R1111")
 | 
			
		||||
    assertState("1111o world")
 | 
			
		||||
    typeText("<BS><BS><BS>")
 | 
			
		||||
    assertState("1ello world")
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ class CopyActionTest : VimTestCase() {
 | 
			
		||||
  @TestWithoutNeovim(reason = SkipNeovimReason.DIFFERENT)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun testYankRegisterUsesLastEnteredRegister() {
 | 
			
		||||
    typeTextInFile("\"a\"byl" + "\"ap", "hel<caret>lo world\n")
 | 
			
		||||
    typeTextInFile("\"a\"byl" + "\"bp", "hel<caret>lo world\n")
 | 
			
		||||
    assertState("helllo world\n")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@ import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
 | 
			
		||||
import com.maddyhome.idea.vim.api.injector
 | 
			
		||||
import com.maddyhome.idea.vim.common.TextRange
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.state.mode.SelectionType
 | 
			
		||||
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
 | 
			
		||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
			
		||||
@@ -2173,7 +2172,7 @@ rtyfg${c}hzxc"""
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    injector.registerGroup.storeText('*', "fgh")
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(IjVimEditor(editor), editor.vim.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(IjVimEditor(editor), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("\"*P"))
 | 
			
		||||
    val after = "fg${c}hqfg${c}hwe asd zxc rty fg${c}hfgh vbn"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
 | 
			
		||||
    appReadySetup(false)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("p"))
 | 
			
		||||
 | 
			
		||||
    val notification = notifications().last()
 | 
			
		||||
@@ -53,7 +53,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
 | 
			
		||||
    appReadySetup(false)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("p"))
 | 
			
		||||
 | 
			
		||||
    val notifications = notifications()
 | 
			
		||||
@@ -71,7 +71,7 @@ class IdeaPutNotificationsTest : VimTestCase() {
 | 
			
		||||
    appReadySetup(true)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("p"))
 | 
			
		||||
 | 
			
		||||
    val notifications = EventLog.getLogModel(fixture.project).notifications
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ class PutTestAfterCursorActionTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -127,7 +127,6 @@ class PutTestAfterCursorActionTest : VimTestCase() {
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    injector.registerGroup.storeText(
 | 
			
		||||
      vimEditor,
 | 
			
		||||
      vimEditor.primaryCaret(),
 | 
			
		||||
      before rangeOf "I found it in a legendary land\n",
 | 
			
		||||
      SelectionType.LINE_WISE,
 | 
			
		||||
      false,
 | 
			
		||||
@@ -157,7 +156,7 @@ class PutTestAfterCursorActionTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("vep"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ class PutTextBeforeCursorActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    injector.registerGroup.storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    injector.registerGroup.storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "P"))
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "P"))
 | 
			
		||||
    val after = """
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ class PutViaIdeaTest : VimTestCase() {
 | 
			
		||||
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
 | 
			
		||||
    typeText("ppp")
 | 
			
		||||
    val after = "Ilegendarylegendarylegendar${c}y found it in a legendary land"
 | 
			
		||||
@@ -74,7 +74,6 @@ class PutViaIdeaTest : VimTestCase() {
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(
 | 
			
		||||
        vimEditor,
 | 
			
		||||
        vimEditor.primaryCaret(),
 | 
			
		||||
        before rangeOf "legendary$randomUUID",
 | 
			
		||||
        SelectionType.CHARACTER_WISE,
 | 
			
		||||
        false,
 | 
			
		||||
@@ -100,7 +99,6 @@ class PutViaIdeaTest : VimTestCase() {
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(
 | 
			
		||||
      vimEditor,
 | 
			
		||||
      vimEditor.primaryCaret(),
 | 
			
		||||
      before rangeOf "\nLorem ipsum dolor sit amet,\n",
 | 
			
		||||
      SelectionType.CHARACTER_WISE,
 | 
			
		||||
      false,
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = "legendar${c}y it in a legendary land"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -87,7 +87,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "2p"))
 | 
			
		||||
    val after = "legendarylegendar${c}y in a legendary land"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -99,7 +99,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v$" + "2p"))
 | 
			
		||||
    val after = "legendarylegendar${c}y"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -133,7 +133,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    val before = "I foun${c}d it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("vb" + "p"))
 | 
			
		||||
    val after = "I legendar${c}y it in a legendary land"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -154,7 +154,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -182,7 +182,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -210,7 +210,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -238,7 +238,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v$" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -455,7 +455,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -491,7 +491,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -529,7 +529,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("ve" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -640,7 +640,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -666,7 +666,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -703,7 +703,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -876,7 +876,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -902,7 +902,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -939,7 +939,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1117,7 +1117,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1172,7 +1172,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1233,7 +1233,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1409,7 +1409,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1435,7 +1435,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>3e2k" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1461,7 +1461,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1487,7 +1487,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>3j$" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1526,7 +1526,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1554,7 +1554,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "P"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1593,7 +1593,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "2p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1633,7 +1633,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1672,7 +1672,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1707,7 +1707,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e2j" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1743,7 +1743,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2e3j" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1779,7 +1779,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2ej" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1815,7 +1815,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>elj" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
@@ -1852,7 +1852,7 @@ class PutVisualTextActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-V>2j$" + "p"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            A Discovery
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "2gp"))
 | 
			
		||||
    val after = "legendarylegendary$c in a legendary land"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -45,7 +45,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "gp"))
 | 
			
		||||
    val after = """
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "gp"))
 | 
			
		||||
    val after = "legendary\n$c"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -88,7 +88,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(file)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(2, 11), SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(2, 11), SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "gp"))
 | 
			
		||||
    assertState(newFile)
 | 
			
		||||
  }
 | 
			
		||||
@@ -134,7 +134,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "gP"))
 | 
			
		||||
    val after = """
 | 
			
		||||
 | 
			
		||||
@@ -150,7 +150,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "2gP"))
 | 
			
		||||
    val after = "legendarylegendary$c in a legendary land"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -162,7 +162,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v$" + "2gP"))
 | 
			
		||||
    val after = "legendarylegendar${c}y"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -174,7 +174,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}I found it in a legendary land"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 25), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "gP"))
 | 
			
		||||
    val after = "legendary\n$c"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
@@ -273,7 +273,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.BLOCK_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<S-v>" + "gp"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            ${c}fgh
 | 
			
		||||
@@ -299,7 +299,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    """.trimIndent()
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.LINE_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.LINE_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("<C-v>" + "h" + "gp"))
 | 
			
		||||
    val after = """
 | 
			
		||||
            q
 | 
			
		||||
@@ -320,7 +320,7 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}qwe asd ${c}zxc rty ${c}fgh vbn"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    VimPlugin.getRegister().storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("v2e" + "2gp"))
 | 
			
		||||
    val after = "fghfgh$c fghfgh$c fghfgh$c"
 | 
			
		||||
    assertState(after)
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ class YankVisualActionTest : VimTestCase() {
 | 
			
		||||
    typeText(injector.parser.parseKeys("viw" + "y"))
 | 
			
		||||
    val editor = fixture.editor.vim
 | 
			
		||||
    val lastRegister = injector.registerGroup.lastRegisterChar
 | 
			
		||||
    val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
 | 
			
		||||
    val registers = editor.carets().map { injector.registerGroup.getRegister(lastRegister)?.rawText }
 | 
			
		||||
    kotlin.test.assertEquals(listOf("found", "was"), registers)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -172,7 +172,7 @@ class YankVisualActionTest : VimTestCase() {
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "y"))
 | 
			
		||||
    val editor = fixture.editor.vim
 | 
			
		||||
    val lastRegister = injector.registerGroup.lastRegisterChar
 | 
			
		||||
    val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
 | 
			
		||||
    val registers = editor.carets().map { injector.registerGroup.getRegister(lastRegister)?.rawText }
 | 
			
		||||
    kotlin.test.assertEquals(
 | 
			
		||||
      listOf("all rocks and lavender and tufted grass,\n", "hard by the torrent of a mountain pass.\n"),
 | 
			
		||||
      registers,
 | 
			
		||||
 
 | 
			
		||||
@@ -85,4 +85,33 @@ class MotionBackspaceActionTest : VimTestCase() {
 | 
			
		||||
      enterCommand("set whichwrap=b")
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test backspace motion with operator`() {
 | 
			
		||||
    doTest(
 | 
			
		||||
      "d<BS>",
 | 
			
		||||
      """
 | 
			
		||||
        lorem ${c}ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
      """
 | 
			
		||||
        lorem${c}ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test backspace motion with operator at start of line`() {
 | 
			
		||||
    doTest(
 | 
			
		||||
      "d<BS>",
 | 
			
		||||
      """
 | 
			
		||||
        lorem ipsum dolor sit amet
 | 
			
		||||
        ${c}lorem ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
      """
 | 
			
		||||
        lorem ipsum dolor sit amet${c}lorem ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -85,4 +85,35 @@ class MotionSpaceActionTest : VimTestCase() {
 | 
			
		||||
      enterCommand("set whichwrap=s")
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Suppress("SpellCheckingInspection")
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test space motion with operator`() {
 | 
			
		||||
    doTest(
 | 
			
		||||
      "d<Space>",
 | 
			
		||||
      """
 | 
			
		||||
        lorem ${c}ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
      """
 | 
			
		||||
        lorem ${c}psum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.OPTION)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test space motion with operator at end of line`() {
 | 
			
		||||
    doTest(
 | 
			
		||||
      "d<Space>",
 | 
			
		||||
      """
 | 
			
		||||
        lorem ipsum dolor sit ame${c}t
 | 
			
		||||
        lorem ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
      """
 | 
			
		||||
        lorem ipsum dolor sit am${c}e
 | 
			
		||||
        lorem ipsum dolor sit amet
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -294,20 +294,20 @@ class ExEntryTest : VimTestCase() {
 | 
			
		||||
//        assertExText("set incsearch")
 | 
			
		||||
 | 
			
		||||
    typeExInput(":<S-Up>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
    typeText("<Up>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
    typeText("<Up>")
 | 
			
		||||
    assertExText("digraph")
 | 
			
		||||
    typeText("<Up>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput(":<PageUp>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("digraph")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.CMD)
 | 
			
		||||
@@ -325,20 +325,20 @@ class ExEntryTest : VimTestCase() {
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput(":set<S-Up>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("digraph")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput(":set<PageUp>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("digraph")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("set digraph")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("set incsearch")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
@@ -357,20 +357,20 @@ class ExEntryTest : VimTestCase() {
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput("/<S-Up>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("not cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput("/<PageUp>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("not cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @VimBehaviorDiffers(description = "Vim reorders history even when cancelling entry")
 | 
			
		||||
@@ -394,20 +394,20 @@ class ExEntryTest : VimTestCase() {
 | 
			
		||||
//        assertEquals("set incsearch", exEntryPanel.text)
 | 
			
		||||
 | 
			
		||||
    typeExInput("/so<S-Up>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("not cool")
 | 
			
		||||
    typeText("<S-Up>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
 | 
			
		||||
    deactivateExEntry()
 | 
			
		||||
 | 
			
		||||
    typeExInput("/so<PageUp>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("not cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("something cool")
 | 
			
		||||
    typeText("<PageUp>")
 | 
			
		||||
    assertExText("so cool")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
 
 | 
			
		||||
@@ -130,7 +130,7 @@ class MultipleCaretsTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(commandToKeys("pu"))
 | 
			
		||||
    val after = """
 | 
			
		||||
          qwe
 | 
			
		||||
@@ -165,7 +165,7 @@ class MultipleCaretsTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(commandToKeys("pu"))
 | 
			
		||||
    val after = """
 | 
			
		||||
          qwe
 | 
			
		||||
@@ -201,7 +201,7 @@ class MultipleCaretsTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(commandToKeys("4pu"))
 | 
			
		||||
    val after = """
 | 
			
		||||
          qwe
 | 
			
		||||
@@ -237,7 +237,7 @@ class MultipleCaretsTest : VimTestCase() {
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    val vimEditor = editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(commandToKeys("4pu"))
 | 
			
		||||
    val after = """
 | 
			
		||||
          qwe
 | 
			
		||||
@@ -258,7 +258,7 @@ class MultipleCaretsTest : VimTestCase() {
 | 
			
		||||
    val before = "${c}qwe\n" + "rty\n" + "as${c}d\n" + "fgh\n" + "zxc\n" + "vbn\n"
 | 
			
		||||
    val editor = configureByText(before)
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(editor.vim, editor.vim.primaryCaret(), TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(editor.vim, TextRange(16, 19), SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
 | 
			
		||||
    typeText("vj")
 | 
			
		||||
    typeText(commandToKeys("pu"))
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.Disabled
 | 
			
		||||
import org.junit.jupiter.api.Test
 | 
			
		||||
import org.junit.jupiter.api.assertThrows
 | 
			
		||||
import kotlin.test.assertEquals
 | 
			
		||||
import kotlin.test.assertNull
 | 
			
		||||
import kotlin.test.assertTrue
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -267,7 +268,7 @@ class MapCommandTest : VimTestCase() {
 | 
			
		||||
    configureByText("${c}foo\n")
 | 
			
		||||
    typeText(commandToKeys("imap a b \\| c"))
 | 
			
		||||
    typeText(injector.parser.parseKeys("ia"))
 | 
			
		||||
    assertState("b \\| cfoo\n")
 | 
			
		||||
    assertState("b | cfoo\n")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // VIM-666 |:imap|
 | 
			
		||||
@@ -277,7 +278,7 @@ class MapCommandTest : VimTestCase() {
 | 
			
		||||
    configureByText("${c}foo\n")
 | 
			
		||||
    typeText(commandToKeys("imap a b \\| c    |"))
 | 
			
		||||
    typeText(injector.parser.parseKeys("ia"))
 | 
			
		||||
    assertState("b \\| c    foo\n")
 | 
			
		||||
    assertState("b | c    foo\n")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // VIM-670 |:map|
 | 
			
		||||
@@ -754,4 +755,23 @@ class MapCommandTest : VimTestCase() {
 | 
			
		||||
 | 
			
		||||
    assertTrue(KeyHandler.getInstance().keyStack.isEmpty())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @TestFor(issues = ["VIM-3601"])
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `mapping to something with bars`() {
 | 
			
		||||
    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 k :echo 4<CR> \\| :echo 42<CR>"))
 | 
			
		||||
    assertNull(injector.outputPanel.getCurrentOutputPanel())
 | 
			
		||||
    typeText("k")
 | 
			
		||||
    assertEquals("4\n42", injector.outputPanel.getCurrentOutputPanel()!!.text)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ class PrintCommandTest : VimTestCase() {
 | 
			
		||||
    // We should be waiting for a keypress now, such as <Enter> or <Esc> to close the output panel. But that's handled
 | 
			
		||||
    // by a separate key event loop which doesn't operate in tests.
 | 
			
		||||
    // Simulate closing the output panel in the same way as if we'd entered the right key
 | 
			
		||||
    ExOutputModel.getInstance(fixture.editor).close()
 | 
			
		||||
    injector.outputPanel.getCurrentOutputPanel()?.close()
 | 
			
		||||
    typeText(commandToKeys("p"))
 | 
			
		||||
    assertExOutput("    Lorem Ipsum")
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
package org.jetbrains.plugins.ideavim.ex.implementation.commands
 | 
			
		||||
 | 
			
		||||
import com.maddyhome.idea.vim.VimPlugin
 | 
			
		||||
import com.maddyhome.idea.vim.newapi.vim
 | 
			
		||||
import com.maddyhome.idea.vim.register.RegisterConstants
 | 
			
		||||
import org.jetbrains.plugins.ideavim.VimTestCase
 | 
			
		||||
import org.junit.jupiter.api.Test
 | 
			
		||||
@@ -303,33 +302,4 @@ class YankLinesCommandTest : VimTestCase() {
 | 
			
		||||
        |Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
 | 
			
		||||
        |""".trimMargin())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test multicaret yank`() {
 | 
			
		||||
    configureByText(
 | 
			
		||||
      """
 | 
			
		||||
        |Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 | 
			
		||||
        |${c}Morbi nec luctus tortor, id venenatis lacus.
 | 
			
		||||
        |${c}Nunc sit amet tellus vel purus cursus posuere et at purus.
 | 
			
		||||
        |${c}Ut id dapibus augue.
 | 
			
		||||
        |Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
 | 
			
		||||
        |Pellentesque orci dolor, tristique quis rutrum non, scelerisque id dui.
 | 
			
		||||
      """.trimMargin()
 | 
			
		||||
    )
 | 
			
		||||
    enterCommand("y")
 | 
			
		||||
    val carets = fixture.editor.vim.carets()
 | 
			
		||||
    assertEquals(3, carets.size)
 | 
			
		||||
    assertEquals(
 | 
			
		||||
      "Morbi nec luctus tortor, id venenatis lacus.\n",
 | 
			
		||||
      carets[0].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
 | 
			
		||||
    )
 | 
			
		||||
    assertEquals(
 | 
			
		||||
      "Nunc sit amet tellus vel purus cursus posuere et at purus.\n",
 | 
			
		||||
      carets[1].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
 | 
			
		||||
    )
 | 
			
		||||
    assertEquals(
 | 
			
		||||
      "Ut id dapibus augue.\n",
 | 
			
		||||
      carets[2].registerStorage.getRegister(RegisterConstants.UNNAMED_REGISTER)?.text
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ class VimVariableServiceTest : VimTestCase() {
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count variable without count specified`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("nnoremap <expr> n ':echo ' .. v:count .. \"\\<CR>\"")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':echo ' .. v:count .. "\<CR>"""")
 | 
			
		||||
    typeText("n")
 | 
			
		||||
    assertExOutput("0")
 | 
			
		||||
  }
 | 
			
		||||
@@ -23,15 +23,31 @@ class VimVariableServiceTest : VimTestCase() {
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count variable`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("nnoremap <expr> n ':' .. \"\\<C-u>\" .. 'echo ' .. v:count .. \"\\<CR>\"")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count .. "\<CR>"""")
 | 
			
		||||
    typeText("5n")
 | 
			
		||||
    assertExOutput("5")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count variable with additional count during select register`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count .. "\<CR>"""")
 | 
			
		||||
    typeText("2\"a5n")
 | 
			
		||||
    assertExOutput("10")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count variable with additional pathological count during select register`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count .. "\<CR>"""")
 | 
			
		||||
    typeText("2\"a3\"b4\"c5n")
 | 
			
		||||
    assertExOutput("120")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count1 variable without count specified`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("nnoremap <expr> n ':echo ' .. v:count1 .. \"\\<CR>\"")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':echo ' .. v:count1 .. "\<CR>"""")
 | 
			
		||||
    typeText("n")
 | 
			
		||||
    assertExOutput("1")
 | 
			
		||||
  }
 | 
			
		||||
@@ -39,11 +55,27 @@ class VimVariableServiceTest : VimTestCase() {
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count1 variable`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("nnoremap <expr> n ':' .. \"\\<C-u>\" .. 'echo ' .. v:count1 .. \"\\<CR>\"")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count1 .. "\<CR>"""")
 | 
			
		||||
    typeText("5n")
 | 
			
		||||
    assertExOutput("5")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count1 variable with additional count during select register`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count1 .. "\<CR>"""")
 | 
			
		||||
    typeText("2\"a5n")
 | 
			
		||||
    assertExOutput("10")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test v count1 variable with additional pathological count during select register`() {
 | 
			
		||||
    configureByText("\n")
 | 
			
		||||
    enterCommand("""nnoremap <expr> n ':' .. "\<C-u>" .. 'echo ' .. v:count1 .. "\<CR>"""")
 | 
			
		||||
    typeText("2\"a3\"b4\"c5n")
 | 
			
		||||
    assertExOutput("120")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun `test mapping with updating jumplist`() {
 | 
			
		||||
    configureByText("${c}1\n2\n3\n4\n5\n6\n7\n8\n9\n")
 | 
			
		||||
 
 | 
			
		||||
@@ -141,6 +141,16 @@ Mode.INSERT,
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun testDeleteWithMultipleCounts() {
 | 
			
		||||
    doTest(
 | 
			
		||||
      "2d2aa",
 | 
			
		||||
      "function(int <caret>arg1,    char* arg<caret>2=\"a,b,c(d,e)\", bool arg3, string arg4, int arg5)",
 | 
			
		||||
      "function(<caret>)",
 | 
			
		||||
      Mode.NORMAL(),
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  fun testSelectTwoArguments() {
 | 
			
		||||
    doTest(
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("griw"))
 | 
			
		||||
    assertState("one on${c}e three")
 | 
			
		||||
    assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
 | 
			
		||||
@@ -170,7 +170,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("3griw"))
 | 
			
		||||
    assertState("one on${c}e four")
 | 
			
		||||
    assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
 | 
			
		||||
@@ -184,7 +184,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("griw"))
 | 
			
		||||
    assertState("one two one four")
 | 
			
		||||
    assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
 | 
			
		||||
@@ -197,7 +197,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "one", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("griw" + "w" + "."))
 | 
			
		||||
    assertState("one one on${c}e four")
 | 
			
		||||
    assertEquals("one", VimPlugin.getRegister().lastRegister?.text)
 | 
			
		||||
@@ -247,7 +247,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("grr"))
 | 
			
		||||
    assertState(
 | 
			
		||||
      """
 | 
			
		||||
@@ -414,7 +414,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("viw" + "gr"))
 | 
			
		||||
    assertState(
 | 
			
		||||
      """
 | 
			
		||||
@@ -485,7 +485,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
 | 
			
		||||
    configureByText(text)
 | 
			
		||||
    val vimEditor = fixture.editor.vim
 | 
			
		||||
    VimPlugin.getRegister()
 | 
			
		||||
      .storeText(vimEditor, vimEditor.primaryCaret(), text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
      .storeText(vimEditor, text rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("V" + "gr"))
 | 
			
		||||
    assertState(
 | 
			
		||||
      """
 | 
			
		||||
 
 | 
			
		||||
@@ -660,7 +660,7 @@ abstract class VimTestCase {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun assertExOutput(expected: String, clear: Boolean = true) {
 | 
			
		||||
    val actual = ExOutputModel.getInstance(fixture.editor).text
 | 
			
		||||
    val actual = injector.outputPanel.getCurrentOutputPanel()?.text
 | 
			
		||||
    assertNotNull(actual, "No Ex output")
 | 
			
		||||
    assertEquals(expected, actual)
 | 
			
		||||
    NeovimTesting.typeCommand("<esc>", testInfo, fixture.editor)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import org.jetbrains.plugins.ideavim.TestWithoutNeovim
 | 
			
		||||
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
 | 
			
		||||
import org.jetbrains.plugins.ideavim.VimJavaTestCase
 | 
			
		||||
import org.junit.jupiter.api.Test
 | 
			
		||||
import kotlin.test.assertEquals
 | 
			
		||||
 | 
			
		||||
class ChangeActionJavaTest : VimJavaTestCase() {
 | 
			
		||||
  // VIM-511 |.|
 | 
			
		||||
@@ -120,6 +121,28 @@ and some text after""",
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // VIM-566
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.FOLDING)
 | 
			
		||||
  @Test
 | 
			
		||||
  fun testInsertAfterToggleFold() {
 | 
			
		||||
    configureByJavaText(
 | 
			
		||||
      """
 | 
			
		||||
          $c/**
 | 
			
		||||
           * I should be fold
 | 
			
		||||
           * a little more text
 | 
			
		||||
           * and final fold
 | 
			
		||||
           */
 | 
			
		||||
          and some text after
 | 
			
		||||
      """.trimIndent(),
 | 
			
		||||
    )
 | 
			
		||||
    CodeFoldingManager.getInstance(fixture.project).updateFoldRegions(fixture.editor)
 | 
			
		||||
    assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, true)
 | 
			
		||||
    typeText(injector.parser.parseKeys("za"))
 | 
			
		||||
    assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, false)
 | 
			
		||||
    typeText(injector.parser.parseKeys("za"))
 | 
			
		||||
    assertEquals(FoldingUtil.findFoldRegionStartingAtLine(fixture.editor, 0)!!.isExpanded, true)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // VIM-287 |zc| |o|
 | 
			
		||||
  @TestWithoutNeovim(SkipNeovimReason.FOLDING)
 | 
			
		||||
  @Test
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ private class AvailableActions(private val editor: Editor) : ImperativeCommand {
 | 
			
		||||
    val currentNode = KeyHandler.getInstance().keyHandlerState.commandBuilder.getCurrentTrie()
 | 
			
		||||
 | 
			
		||||
    // Note: esc is always an option
 | 
			
		||||
    val possibleKeys = (currentNode.keys.toList() + esc).sortedBy { injector.parser.toKeyNotation(it) }
 | 
			
		||||
    val possibleKeys = (currentNode.children.keys.toList() + esc).sortedBy { injector.parser.toKeyNotation(it) }
 | 
			
		||||
    println("Keys: ${possibleKeys.joinToString(", ")}")
 | 
			
		||||
    val keyGenerator = Generator.integers(0, possibleKeys.lastIndex)
 | 
			
		||||
      .suchThat { injector.parser.toKeyNotation(possibleKeys[it]) !in stinkyKeysList }
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user