mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-10-31 20:17:13 +01:00 
			
		
		
		
	Compare commits
	
		
			40 Commits
		
	
	
		
			943ddeb5ab
			...
			customized
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8e162bce95 | |||
| 2cdd62371e | |||
| d461f61438 | |||
| de7fe30a97 | |||
| 6d80c21344 | |||
| a57a80442c | |||
| 866e6dc831 | |||
| f11bb12f19 | |||
| 70ea1bd46f | |||
|   | 2845beaf8a | ||
|   | 1e58ead126 | ||
|   | fafa7572d0 | ||
|   | 4ddeb72bfe | ||
|   | 28ba36dddb | ||
|   | b6c501311c | ||
|   | 01d4ebe254 | ||
|   | 34dd332f0b | ||
|   | 596d0c7115 | ||
|   | 672601b028 | ||
|   | e5045f28ab | ||
|   | 12ba067db3 | ||
|   | 5413606425 | ||
|   | 72ae18557b | ||
|   | 99bd119ed6 | ||
|   | faebf66065 | ||
|   | dc030d6895 | ||
|   | 7f626005a5 | ||
|   | 28d0741e14 | ||
|   | c0e17a6c61 | ||
|   | b5046b089e | ||
|   | 1075112bfa | ||
|   | 37fddacf8e | ||
|   | 2091a59897 | ||
|   | d2a427b38f | ||
|   | c069719c1c | ||
|   | 654a443d4b | ||
|   | a6ec2d5ed7 | ||
|   | 02ac083175 | ||
|   | 561fce5d40 | ||
|   | a88263874a | 
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | * text=auto eol=lf | ||||||
							
								
								
									
										31
									
								
								.github/workflows/checkNewPlugins.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								.github/workflows/checkNewPlugins.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | # This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created | ||||||
|  | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle | ||||||
|  |  | ||||||
|  | # This workflow syncs changes from the docs folder of IdeaVim to the IdeaVim.wiki repository | ||||||
|  |  | ||||||
|  | name: Check new plugin dependencies | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   workflow_dispatch: | ||||||
|  |   schedule: | ||||||
|  |     - cron: '0 5 * * *' | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |  | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Fetch origin repo | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |  | ||||||
|  |       - name: Set up JDK 17 | ||||||
|  |         uses: actions/setup-java@v2 | ||||||
|  |         with: | ||||||
|  |           java-version: '17' | ||||||
|  |           distribution: 'adopt' | ||||||
|  |           server-id: github # Value of the distributionManagement/repository/id field of the pom.xml | ||||||
|  |           settings-path: ${{ github.workspace }} # location for the settings.xml file | ||||||
|  |  | ||||||
|  |       - name: Check new plugins | ||||||
|  |         run: ./gradlew scripts:checkNewPluginDependencies | ||||||
							
								
								
									
										19
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/mergePr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -5,7 +5,7 @@ name: Update Changelog On PR | |||||||
|  |  | ||||||
| on: | on: | ||||||
|   workflow_dispatch: |   workflow_dispatch: | ||||||
|   pull_request: |   pull_request_target: | ||||||
|     types: [ closed ] |     types: [ closed ] | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
| @@ -30,13 +30,26 @@ jobs: | |||||||
|         id: update_authors |         id: update_authors | ||||||
|         run: ./gradlew updateMergedPr -PprId=${{ github.event.number }} |         run: ./gradlew updateMergedPr -PprId=${{ github.event.number }} | ||||||
|         env: |         env: | ||||||
|           GITHUB_OAUTH: ${{ secrets.MERGE_PR }} |           GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |  | ||||||
|  |       # Reuse from update changelog | ||||||
|  |       - uses: nrwl/last-successful-commit-action@v1 | ||||||
|  |         id: last_successful_commit | ||||||
|  |         with: | ||||||
|  |           branch: 'master' | ||||||
|  |           workflow_id: 'updateChangelog.yml' | ||||||
|  |           github_token: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |  | ||||||
|  |       - name: Update changelog | ||||||
|  |         run: ./gradlew updateChangelog | ||||||
|  |         env: | ||||||
|  |           SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }} | ||||||
|  |  | ||||||
|       - name: Commit changes |       - name: Commit changes | ||||||
|         uses: stefanzweifel/git-auto-commit-action@v4 |         uses: stefanzweifel/git-auto-commit-action@v4 | ||||||
|         with: |         with: | ||||||
|           branch: master |           branch: master | ||||||
|           commit_message: Update changelog  after merging PR |           commit_message: Update changelog after merging PR | ||||||
|           commit_user_name: Alex Plate |           commit_user_name: Alex Plate | ||||||
|           commit_user_email: aleksei.plate@jetbrains.com |           commit_user_email: aleksei.plate@jetbrains.com | ||||||
|           commit_author: Alex Plate <aleksei.plate@jetbrains.com> |           commit_author: Alex Plate <aleksei.plate@jetbrains.com> | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.github/workflows/updateChangelog.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/updateChangelog.yml
									
									
									
									
										vendored
									
									
								
							| @@ -11,6 +11,7 @@ on: | |||||||
| jobs: | jobs: | ||||||
|   build: |   build: | ||||||
|  |  | ||||||
|  |     if: github.event.pull_request.merged != true | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
| @@ -44,4 +45,5 @@ jobs: | |||||||
|           commit_user_name: Alex Plate |           commit_user_name: Alex Plate | ||||||
|           commit_user_email: aleksei.plate@jetbrains.com |           commit_user_email: aleksei.plate@jetbrains.com | ||||||
|           commit_author: Alex Plate <aleksei.plate@jetbrains.com> |           commit_author: Alex Plate <aleksei.plate@jetbrains.com> | ||||||
|           file_pattern: CHANGES.md |           file_pattern: CHANGES.md | ||||||
|  |           skip_fetch: false | ||||||
| @@ -25,6 +25,9 @@ usual beta standards. | |||||||
|  |  | ||||||
| ## To Be Released | ## To Be Released | ||||||
|  |  | ||||||
|  | ### Features: | ||||||
|  | * Add IdeaVim tutor. You can access it via the status bar icon. | ||||||
|  |  | ||||||
| ### Fixes: | ### Fixes: | ||||||
| * [VIM-2797](https://youtrack.jetbrains.com/issue/VIM-2797) Introduce variable to mute default argtextobj mappings | * [VIM-2797](https://youtrack.jetbrains.com/issue/VIM-2797) Introduce variable to mute default argtextobj mappings | ||||||
| * [VIM-758](https://youtrack.jetbrains.com/issue/VIM-758) Support d mappings | * [VIM-758](https://youtrack.jetbrains.com/issue/VIM-758) Support d mappings | ||||||
| @@ -37,6 +40,9 @@ usual beta standards. | |||||||
| * [553](https://github.com/JetBrains/ideavim/pull/553) by [Matt Ellis](https://github.com/citizenmatt): Rearrange and rename some code in engine | * [553](https://github.com/JetBrains/ideavim/pull/553) by [Matt Ellis](https://github.com/citizenmatt): Rearrange and rename some code in engine | ||||||
| * [560](https://github.com/JetBrains/ideavim/pull/560) by [Runinho](https://github.com/Runinho): Fix(VIM-2577) paste not working at end of notebook cell | * [560](https://github.com/JetBrains/ideavim/pull/560) by [Runinho](https://github.com/Runinho): Fix(VIM-2577) paste not working at end of notebook cell | ||||||
| * [571](https://github.com/JetBrains/ideavim/pull/571) by [Ada](https://github.com/adaext): Remove the redundant quotation mark at the end of "packadd matchit" command | * [571](https://github.com/JetBrains/ideavim/pull/571) by [Ada](https://github.com/adaext): Remove the redundant quotation mark at the end of "packadd matchit" command | ||||||
|  | * [561](https://github.com/JetBrains/ideavim/pull/561) by [Matt Ellis](https://github.com/citizenmatt): Fix incremental search not scrolling to current match | ||||||
|  | * [559](https://github.com/JetBrains/ideavim/pull/559) by [Runinho](https://github.com/Runinho): Fix(VIM-2760) notebookCommandMode detection | ||||||
|  | * [579](https://github.com/JetBrains/ideavim/pull/579) by [Martin Yzeiri](https://github.com/myzeiri): VIM-2799: Add Matchit support for cshtml files | ||||||
|  |  | ||||||
| ## 2.0.0, 2022-11-01 | ## 2.0.0, 2022-11-01 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -89,7 +89,7 @@ Here are some examples of supported vim features and commands: | |||||||
| * Vim web help | * Vim web help | ||||||
| * `~/.ideavimrc` configuration file | * `~/.ideavimrc` configuration file | ||||||
|  |  | ||||||
| [IdeaVim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins): | [IdeaVim plugins](https://github.com/JetBrains/ideavim/wiki/IdeaVim-Plugins): | ||||||
|  |  | ||||||
| * vim-easymotion | * vim-easymotion | ||||||
| * NERDTree | * NERDTree | ||||||
| @@ -103,7 +103,8 @@ Here are some examples of supported vim features and commands: | |||||||
| * vim-highlightedyank | * vim-highlightedyank | ||||||
| * vim-paragraph-motion | * vim-paragraph-motion | ||||||
| * vim-indent-object | * vim-indent-object | ||||||
| * match.it | * match.it   | ||||||
|  | etc | ||||||
|  |  | ||||||
| See also: | See also: | ||||||
|  |  | ||||||
| @@ -202,7 +203,7 @@ Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file. | |||||||
| IdeaVim Plugins | IdeaVim Plugins | ||||||
| -------------------- | -------------------- | ||||||
|  |  | ||||||
| See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins) | See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/IdeaVim-Plugins) | ||||||
|  |  | ||||||
| Executing IDE Actions | Executing IDE Actions | ||||||
| --------------------- | --------------------- | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| IdeaVim project is licensed under MIT license except the following parts of it: | IdeaVim project is licensed under MIT license except the following parts of it: | ||||||
|  |  | ||||||
| File [RegExp.kt](src/main/java/com/maddyhome/idea/vim/regexp/RegExp.kt) is licensed under Vim License. | File [RegExp.kt](src/main/java/com/maddyhome/idea/vim/regexp/RegExp.kt) is licensed under Vim License.   | ||||||
|  | File [Tutor.kt](src/main/java/com/maddyhome/idea/vim/ui/Tutor.kt) is licensed under Vim License. | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| VIM LICENSE | VIM LICENSE | ||||||
|   | |||||||
| @@ -61,6 +61,7 @@ plugins { | |||||||
|     antlr |     antlr | ||||||
|     java |     java | ||||||
|     kotlin("jvm") version "1.7.20" |     kotlin("jvm") version "1.7.20" | ||||||
|  |     application | ||||||
|  |  | ||||||
|     id("org.jetbrains.intellij") version "1.11.1-SNAPSHOT" |     id("org.jetbrains.intellij") version "1.11.1-SNAPSHOT" | ||||||
|     id("org.jetbrains.changelog") version "1.3.1" |     id("org.jetbrains.changelog") version "1.3.1" | ||||||
| @@ -808,7 +809,7 @@ fun updateMergedPr(number: Int) { | |||||||
|     if (pullRequest.user.login == "dependabot[bot]") return |     if (pullRequest.user.login == "dependabot[bot]") return | ||||||
|  |  | ||||||
|     val prNumber = pullRequest.number |     val prNumber = pullRequest.number | ||||||
|     val userName = pullRequest.user.name |     val userName = pullRequest.user.name ?: pullRequest.user.login | ||||||
|     val login = pullRequest.user.login |     val login = pullRequest.user.login | ||||||
|     val title = pullRequest.title |     val title = pullRequest.title | ||||||
|     val section = |     val section = | ||||||
|   | |||||||
| @@ -381,3 +381,18 @@ Original plugin: [matchit.vim](https://github.com/chrisbra/matchit). | |||||||
| https://github.com/adelarsq/vim-matchit/blob/master/doc/matchit.txt | https://github.com/adelarsq/vim-matchit/blob/master/doc/matchit.txt | ||||||
|  |  | ||||||
| </details> | </details> | ||||||
|  |  | ||||||
|  | <details> | ||||||
|  | <summary><h2>IdeaVim-Quickscope</h2></summary> | ||||||
|  |  | ||||||
|  | Original plugin: [quick-scope](https://github.com/unblevable/quick-scope). | ||||||
|  |  | ||||||
|  | ### Setup: | ||||||
|  | - Install [IdeaVim-sneak](https://plugins.jetbrains.com/plugin/15348-ideavim-sneak) plugin. | ||||||
|  | - Add the following command to `~/.ideavimrc`: `set quickscope` | ||||||
|  |  | ||||||
|  | ### Instructions | ||||||
|  |  | ||||||
|  | https://plugins.jetbrains.com/plugin/19417-ideavim-quickscope | ||||||
|  |  | ||||||
|  | </details> | ||||||
|   | |||||||
| @@ -8,15 +8,14 @@ | |||||||
|  |  | ||||||
| # suppress inspection "UnusedProperty" for whole file | # suppress inspection "UnusedProperty" for whole file | ||||||
|  |  | ||||||
| ideaVersion=LATEST-EAP-SNAPSHOT | ideaVersion=2022.3 | ||||||
| downloadIdeaSources=true | downloadIdeaSources=true | ||||||
| instrumentPluginCode=true | instrumentPluginCode=true | ||||||
| version=SNAPSHOT | version=chylex-15 | ||||||
| javaVersion=17 | javaVersion=17 | ||||||
| remoteRobotVersion=0.11.15 | remoteRobotVersion=0.11.15 | ||||||
| antlrVersion=4.10.1 | antlrVersion=4.10.1 | ||||||
|  |  | ||||||
|  |  | ||||||
| # Please don't forget to update kotlin version in buildscript section | # Please don't forget to update kotlin version in buildscript section | ||||||
| kotlinVersion=1.7.20 | kotlinVersion=1.7.20 | ||||||
| publishToken=token | publishToken=token | ||||||
| @@ -29,4 +28,4 @@ youtrackToken= | |||||||
| org.gradle.jvmargs='-Dfile.encoding=UTF-8' | org.gradle.jvmargs='-Dfile.encoding=UTF-8' | ||||||
|  |  | ||||||
| # Disable warning from gradle-intellij-plugin. Kotlin stdlib is included as compileOnly, so the warning is unnecessary | # Disable warning from gradle-intellij-plugin. Kotlin stdlib is included as compileOnly, so the warning is unnecessary | ||||||
| kotlin.stdlib.default.dependency=false | kotlin.stdlib.default.dependency=false | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								scripts/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								scripts/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2003-2022 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | plugins { | ||||||
|  |     java | ||||||
|  |     kotlin("jvm") | ||||||
|  |     application | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // group 'org.jetbrains.ideavim' | ||||||
|  | // version 'SNAPSHOT' | ||||||
|  |  | ||||||
|  | repositories { | ||||||
|  |     mavenCentral() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | dependencies { | ||||||
|  |     compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20") | ||||||
|  |  | ||||||
|  |     implementation("io.ktor:ktor-client-core:2.1.3") | ||||||
|  |     implementation("io.ktor:ktor-client-cio:2.1.3") | ||||||
|  |     implementation("io.ktor:ktor-client-content-negotiation:2.1.3") | ||||||
|  |     implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.3") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | tasks { | ||||||
|  |     compileKotlin { | ||||||
|  |         kotlinOptions { | ||||||
|  |             freeCompilerArgs = listOf("-Xjvm-default=all-compatibility") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | tasks.register("generateIdeaVimConfigurations", JavaExec::class) { | ||||||
|  |     group = "verification" | ||||||
|  |     description = "This job tracks if there are any new plugins in marketplace we don't know about" | ||||||
|  |     mainClass.set("scripts.MainKt") | ||||||
|  |     classpath = sourceSets["main"].runtimeClasspath | ||||||
|  | } | ||||||
|  |  | ||||||
|  | tasks.register("checkNewPluginDependencies", JavaExec::class) { | ||||||
|  |     group = "verification" | ||||||
|  |     description = "This job tracks if there are any new plugins in marketplace we don't know about" | ||||||
|  |     mainClass.set("scripts.CheckNewPluginDependenciesKt") | ||||||
|  |     classpath = sourceSets["main"].runtimeClasspath | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								scripts/src/main/kotlin/scripts/Main.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								scripts/src/main/kotlin/scripts/Main.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2003-2022 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 scripts | ||||||
|  |  | ||||||
|  | fun main() { | ||||||
|  |   println("Hello") | ||||||
|  | } | ||||||
| @@ -0,0 +1,54 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2003-2022 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 scripts | ||||||
|  |  | ||||||
|  | import io.ktor.client.* | ||||||
|  | import io.ktor.client.call.* | ||||||
|  | import io.ktor.client.engine.cio.* | ||||||
|  | import io.ktor.client.plugins.contentnegotiation.* | ||||||
|  | import io.ktor.client.request.* | ||||||
|  | import io.ktor.serialization.kotlinx.json.* | ||||||
|  | import kotlinx.coroutines.runBlocking | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Marketplace has a API to get all plugins that depend on our plugin. | ||||||
|  |  * Here we have a list of dependent plugins at some moment and we check if something changed in that. | ||||||
|  |  * If so, we need to update our list of plugins. | ||||||
|  |  * | ||||||
|  |  * This script makes no actions and aimed to notify the devs in case they need to update the list of IdeaVim plugins. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | val knownPlugins = listOf( | ||||||
|  |   "IdeaVimExtension", | ||||||
|  |   "github.zgqq.intellij-enhance", | ||||||
|  |   "org.jetbrains.IdeaVim-EasyMotion", | ||||||
|  |   "io.github.mishkun.ideavimsneak", | ||||||
|  |   "eu.theblob42.idea.whichkey", | ||||||
|  |   "com.github.copilot", | ||||||
|  |   "com.github.dankinsoid.multicursor", | ||||||
|  |   "com.joshestein.ideavim-quickscope", | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | fun main() { | ||||||
|  |   val client = HttpClient(CIO) { | ||||||
|  |     install(ContentNegotiation) { | ||||||
|  |       json() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   runBlocking { | ||||||
|  |     val res = client.get("https://plugins.jetbrains.com/api/plugins/") { | ||||||
|  |       parameter("dependency", "IdeaVIM") | ||||||
|  |       parameter("includeOptional", true) | ||||||
|  |     } | ||||||
|  |     val output = res.body<List<String>>() | ||||||
|  |     println(output) | ||||||
|  |     if (knownPlugins != output) error("Unknown plugins list: ${output}") | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -10,4 +10,5 @@ pluginManagement { | |||||||
|  |  | ||||||
| rootProject.name = 'IdeaVIM' | rootProject.name = 'IdeaVIM' | ||||||
| include 'vim-engine' | include 'vim-engine' | ||||||
|  | include 'scripts' | ||||||
|  |  | ||||||
|   | |||||||
| @@ -92,6 +92,16 @@ public class EventFacade { | |||||||
|     EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); |     EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public void addCaretListener(@NotNull Editor editor, | ||||||
|  |                                @NotNull CaretListener listener, | ||||||
|  |                                @NotNull Disposable disposable) { | ||||||
|  |     editor.getCaretModel().addCaretListener(listener, disposable); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void removeCaretListener(@NotNull Editor editor, @NotNull CaretListener listener) { | ||||||
|  |     editor.getCaretModel().removeCaretListener(listener); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public void addEditorMouseListener(@NotNull Editor editor, |   public void addEditorMouseListener(@NotNull Editor editor, | ||||||
|                                      @NotNull EditorMouseListener listener, |                                      @NotNull EditorMouseListener listener, | ||||||
|                                      @NotNull Disposable disposable) { |                                      @NotNull Disposable disposable) { | ||||||
|   | |||||||
| @@ -242,12 +242,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable | |||||||
|  |  | ||||||
|   public static @NotNull String getVersion() { |   public static @NotNull String getVersion() { | ||||||
|     final IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(getPluginId()); |     final IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(getPluginId()); | ||||||
|     if (!ApplicationManager.getApplication().isInternal()) { |     return plugin != null ? plugin.getVersion() : "SNAPSHOT"; | ||||||
|       return plugin != null ? plugin.getVersion() : "SNAPSHOT"; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       return "INTERNAL" + (plugin != null ? " - " + plugin.getVersion() : ""); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public static boolean isEnabled() { |   public static boolean isEnabled() { | ||||||
|   | |||||||
| @@ -143,6 +143,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ { | |||||||
|       if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false |       if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false | ||||||
|  |  | ||||||
|       if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false |       if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false | ||||||
|  |        | ||||||
|  |       if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT) return false | ||||||
|  |       if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) return false | ||||||
|  |       if (keyCode == KeyEvent.VK_HOME || keyCode == KeyEvent.VK_END) return false | ||||||
|  |  | ||||||
|       if (editor.inInsertMode) { |       if (editor.inInsertMode) { | ||||||
|         if (keyCode == KeyEvent.VK_TAB) { |         if (keyCode == KeyEvent.VK_TAB) { | ||||||
|   | |||||||
| @@ -228,12 +228,13 @@ private object FileTypePatterns { | |||||||
|     } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") { |     } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") { | ||||||
|       this.cMakePatterns |       this.cMakePatterns | ||||||
|     } else { |     } else { | ||||||
|       return null |       this.htmlPatterns | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private val htmlLikeFileTypes = setOf( |   private val htmlLikeFileTypes = setOf( | ||||||
|     "HTML", "XML", "XHTML", "JSP", "JavaScript", "JSX Harmony", "TypeScript", "TypeScript JSX", "Vue.js", "Handlebars/Mustache" |     "HTML", "XML", "XHTML", "JSP", "JavaScript", "JSX Harmony", "TypeScript", | ||||||
|  |     "TypeScript JSX", "Vue.js", "Handlebars/Mustache", "Razor" | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   private val htmlPatterns = createHtmlPatterns() |   private val htmlPatterns = createHtmlPatterns() | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import com.intellij.openapi.editor.Editor | |||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| import com.maddyhome.idea.vim.api.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
|  | import com.maddyhome.idea.vim.api.VimChangeGroup | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.getLineEndOffset | import com.maddyhome.idea.vim.api.getLineEndOffset | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
| @@ -30,6 +31,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissin | |||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||||||
| import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret | import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret | ||||||
| import com.maddyhome.idea.vim.helper.editorMode | import com.maddyhome.idea.vim.helper.editorMode | ||||||
|  | import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore | ||||||
| import com.maddyhome.idea.vim.key.OperatorFunction | import com.maddyhome.idea.vim.key.OperatorFunction | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimCaret | import com.maddyhome.idea.vim.newapi.IjVimCaret | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
| @@ -75,22 +77,20 @@ class VimSurroundExtension : VimExtension { | |||||||
|     override val isRepeatable = true |     override val isRepeatable = true | ||||||
|  |  | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       setOperatorFunction(Operator()) |       setOperatorFunction(Operator(supportsMultipleCursors = false)) // TODO | ||||||
|       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) |       executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private class VSurroundHandler : ExtensionHandler { |   private class VSurroundHandler : ExtensionHandler { | ||||||
|     override fun execute(editor: VimEditor, context: ExecutionContext) { |     override fun execute(editor: VimEditor, context: ExecutionContext) { | ||||||
|       val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart |  | ||||||
|       // NB: Operator ignores SelectionType anyway |       // NB: Operator ignores SelectionType anyway | ||||||
|       if (!Operator().apply(editor, context, SelectionType.CHARACTER_WISE)) { |       if (!Operator(supportsMultipleCursors = true).apply(editor, context, SelectionType.CHARACTER_WISE)) { | ||||||
|         return |         return | ||||||
|       } |       } | ||||||
|       runWriteAction { |       runWriteAction { | ||||||
|         // Leave visual mode |         // Leave visual mode | ||||||
|         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) |         executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) | ||||||
|         editor.ij.caretModel.moveToOffset(selectionStart) |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -111,6 +111,10 @@ class VimSurroundExtension : VimExtension { | |||||||
|  |  | ||||||
|     companion object { |     companion object { | ||||||
|       fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { |       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 |         // Save old register values for carets | ||||||
|         val surroundings = editor.sortedCarets() |         val surroundings = editor.sortedCarets() | ||||||
|           .map { |           .map { | ||||||
| @@ -209,26 +213,44 @@ class VimSurroundExtension : VimExtension { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private class Operator : OperatorFunction { |   private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction { | ||||||
|     override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { |     override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean { | ||||||
|       val editor = vimEditor.ij |       val editor = vimEditor.ij | ||||||
|       val c = getChar(editor) |       val c = getChar(editor) | ||||||
|       if (c.code == 0) return true |       if (c.code == 0) return true | ||||||
|  |  | ||||||
|       val pair = getOrInputPair(c, editor) ?: return false |       val pair = getOrInputPair(c, editor) ?: return false | ||||||
|       // XXX: Will it work with line-wise or block-wise selections? |  | ||||||
|       val range = getSurroundRange(editor) ?: return false |  | ||||||
|       runWriteAction { |       runWriteAction { | ||||||
|         val change = VimPlugin.getChange() |         val change = VimPlugin.getChange() | ||||||
|         val leftSurround = pair.first |         if (supportsMultipleCursors) { | ||||||
|         val primaryCaret = editor.caretModel.primaryCaret |           editor.runWithEveryCaretAndRestore { | ||||||
|         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, leftSurround) |             applyOnce(editor, change, pair) | ||||||
|         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + leftSurround.length, pair.second) |           } | ||||||
|         // Jump back to start |         } | ||||||
|         executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) |         else { | ||||||
|  |           applyOnce(editor, change, pair) | ||||||
|  |           // Jump back to start | ||||||
|  |           executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       return true |       return true | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>) { | ||||||
|  |       // XXX: Will it work with line-wise or block-wise selections? | ||||||
|  |       val range = getSurroundRange(editor) | ||||||
|  |       if (range != null) { | ||||||
|  |         val primaryCaret = editor.caretModel.primaryCaret | ||||||
|  |         change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, pair.first) | ||||||
|  |         change.insertText( | ||||||
|  |           IjVimEditor(editor), | ||||||
|  |           IjVimCaret(primaryCaret), | ||||||
|  |           range.endOffset + pair.first.length, | ||||||
|  |           pair.second | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) { |     private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) { | ||||||
|       VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim) |       VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim) | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|     String initText = getRange(((IjVimEditor) editor).getEditor(), cmd); |     String initText = getRange(((IjVimEditor) editor).getEditor(), cmd); | ||||||
|     VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE); |     VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE); | ||||||
|     ExEntryPanel panel = ExEntryPanel.getInstance(); |     ExEntryPanel panel = ExEntryPanel.getInstance(); | ||||||
|     panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, 1); |     panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, cmd.getCount()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -113,7 +113,7 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|  |  | ||||||
|       logger.debug("processing command"); |       logger.debug("processing command"); | ||||||
|  |  | ||||||
|       final String text = panel.getText(); |       String text = panel.getText(); | ||||||
|  |  | ||||||
|       if (!panel.getLabel().equals(":")) { |       if (!panel.getLabel().equals(":")) { | ||||||
|         // Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for |         // Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for | ||||||
| @@ -124,7 +124,15 @@ public class ProcessGroup extends VimProcessGroupBase { | |||||||
|  |  | ||||||
|       if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); |       if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); | ||||||
|  |  | ||||||
|       VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE); |       int repeat = 1; | ||||||
|  |       if (text.contains("raction ")) { | ||||||
|  |         text = text.replace("raction ", "action "); | ||||||
|  |         repeat = panel.getCount(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for (int i = 0; i < repeat; i++) { | ||||||
|  |         VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     catch (ExException e) { |     catch (ExException e) { | ||||||
|       VimPlugin.showMessage(e.getMessage()); |       VimPlugin.showMessage(e.getMessage()); | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys | |||||||
| import com.intellij.openapi.editor.Caret | import com.intellij.openapi.editor.Caret | ||||||
| import com.intellij.openapi.editor.RangeMarker | import com.intellij.openapi.editor.RangeMarker | ||||||
| import com.intellij.openapi.ide.CopyPasteManager | import com.intellij.openapi.ide.CopyPasteManager | ||||||
|  | import com.intellij.util.PlatformUtils | ||||||
| import com.maddyhome.idea.vim.VimPlugin | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| import com.maddyhome.idea.vim.api.VimCaret | import com.maddyhome.idea.vim.api.VimCaret | ||||||
| @@ -146,6 +147,9 @@ class PutGroup : VimPutBase() { | |||||||
|     startOffset: Int, |     startOffset: Int, | ||||||
|     endOffset: Int, |     endOffset: Int, | ||||||
|   ): Int { |   ): Int { | ||||||
|  |     // Temp fix for VIM-2808. Should be removed after rider will fix it's issues | ||||||
|  |     if (PlatformUtils.isRider()) return endOffset | ||||||
|  |  | ||||||
|     val startLine = editor.offsetToBufferPosition(startOffset).line |     val startLine = editor.offsetToBufferPosition(startOffset).line | ||||||
|     val endLine = editor.offsetToBufferPosition(endOffset - 1).line |     val endLine = editor.offsetToBufferPosition(endOffset - 1).line | ||||||
|     val startLineOffset = (editor as IjVimEditor).editor.document.getLineStartOffset(startLine) |     val startLineOffset = (editor as IjVimEditor).editor.document.getLineStartOffset(startLine) | ||||||
|   | |||||||
| @@ -8,13 +8,17 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.group.visual | package com.maddyhome.idea.vim.group.visual | ||||||
|  |  | ||||||
|  | import com.intellij.openapi.editor.Caret | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.maddyhome.idea.vim.api.getLineEndForOffset | import com.maddyhome.idea.vim.api.getLineEndForOffset | ||||||
| import com.maddyhome.idea.vim.api.getLineStartForOffset | import com.maddyhome.idea.vim.api.getLineStartForOffset | ||||||
| import com.maddyhome.idea.vim.command.VimStateMachine | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
|  | import com.maddyhome.idea.vim.helper.inBlockSubMode | ||||||
| import com.maddyhome.idea.vim.helper.isEndAllowed | import com.maddyhome.idea.vim.helper.isEndAllowed | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | ||||||
|  | import com.maddyhome.idea.vim.helper.vimSelectionStart | ||||||
| import com.maddyhome.idea.vim.newapi.IjVimEditor | import com.maddyhome.idea.vim.newapi.IjVimEditor | ||||||
|  | import com.maddyhome.idea.vim.newapi.vim | ||||||
|  |  | ||||||
| fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: VimStateMachine.Mode) { | fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: VimStateMachine.Mode) { | ||||||
|   if (predictedMode != VimStateMachine.Mode.VISUAL) { |   if (predictedMode != VimStateMachine.Mode.VISUAL) { | ||||||
| @@ -40,3 +44,10 @@ fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: VimState | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @Deprecated("Use same method on VimCaret") | ||||||
|  | fun Caret.vimSetSelection(start: Int, end: Int = start, moveCaretToSelectionEnd: Boolean = false) { | ||||||
|  |   vimSelectionStart = start | ||||||
|  |   setVisualSelection(start, end, this.vim) | ||||||
|  |   if (moveCaretToSelectionEnd && !editor.inBlockSubMode) moveToInlayAwareOffset(end) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -46,6 +46,12 @@ public class EditorHelper { | |||||||
|     return editor.getScrollingModel().getVisibleAreaOnScrollingFinished(); |     return editor.getScrollingModel().getVisibleAreaOnScrollingFinished(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //("Use extension function with the same name on VimEditor") | ||||||
|  |   @Deprecated | ||||||
|  |   public static boolean isLineEmpty(final @NotNull Editor editor, final int line, final boolean allowBlanks) { | ||||||
|  |     return EngineEditorHelperKt.isLineEmpty(new IjVimEditor(editor), line, allowBlanks); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public static boolean scrollVertically(@NotNull Editor editor, int verticalOffset) { |   public static boolean scrollVertically(@NotNull Editor editor, int verticalOffset) { | ||||||
|     final ScrollingModel scrollingModel = editor.getScrollingModel(); |     final ScrollingModel scrollingModel = editor.getScrollingModel(); | ||||||
|     final Rectangle area = scrollingModel.getVisibleAreaOnScrollingFinished(); |     final Rectangle area = scrollingModel.getVisibleAreaOnScrollingFinished(); | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ package com.maddyhome.idea.vim.helper | |||||||
|  |  | ||||||
| import com.intellij.codeWithMe.ClientId | import com.intellij.codeWithMe.ClientId | ||||||
| import com.intellij.openapi.editor.Caret | import com.intellij.openapi.editor.Caret | ||||||
|  | import com.intellij.openapi.editor.CaretState | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.editor.ex.util.EditorUtil | import com.intellij.openapi.editor.ex.util.EditorUtil | ||||||
| import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx | ||||||
| @@ -96,3 +97,41 @@ val Caret.vimLine: Int | |||||||
|  */ |  */ | ||||||
| val Editor.vimLine: Int | val Editor.vimLine: Int | ||||||
|   get() = this.caretModel.currentCaret.vimLine |   get() = this.caretModel.currentCaret.vimLine | ||||||
|  |  | ||||||
|  | inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) { | ||||||
|  |   val caretModel = this.caretModel | ||||||
|  |   val carets = if (this.inBlockSubMode) null else caretModel.allCarets | ||||||
|  |   if (carets == null || carets.size == 1) { | ||||||
|  |     action() | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     var initialDocumentSize = this.document.textLength | ||||||
|  |     var documentSizeDifference = 0 | ||||||
|  |  | ||||||
|  |     val caretOffsets = carets.map { it.selectionStart to it.selectionEnd } | ||||||
|  |     val restoredCarets = mutableListOf<CaretState>() | ||||||
|  |  | ||||||
|  |     caretModel.removeSecondaryCarets() | ||||||
|  |      | ||||||
|  |     for ((selectionStart, selectionEnd) in caretOffsets) { | ||||||
|  |       if (selectionStart == selectionEnd) { | ||||||
|  |         caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference) | ||||||
|  |       } | ||||||
|  |       else { | ||||||
|  |         caretModel.primaryCaret.setSelection( | ||||||
|  |           selectionStart + documentSizeDifference, | ||||||
|  |           selectionEnd + documentSizeDifference | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       action() | ||||||
|  |       restoredCarets.add(caretModel.caretsAndSelections.single()) | ||||||
|  |  | ||||||
|  |       val documentLength = this.document.textLength | ||||||
|  |       documentSizeDifference += documentLength - initialDocumentSize | ||||||
|  |       initialDocumentSize = documentLength | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     caretModel.caretsAndSelections = restoredCarets | ||||||
|  |   }  | ||||||
|  | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|  |  | ||||||
| package com.maddyhome.idea.vim.helper | package com.maddyhome.idea.vim.helper | ||||||
|  |  | ||||||
|  | import com.intellij.openapi.actionSystem.ex.ActionUtil | ||||||
| import com.intellij.openapi.editor.Editor | import com.intellij.openapi.editor.Editor | ||||||
| import com.intellij.openapi.editor.actionSystem.TypedAction | import com.intellij.openapi.editor.actionSystem.TypedAction | ||||||
| import com.intellij.openapi.editor.actionSystem.TypedActionHandler | import com.intellij.openapi.editor.actionSystem.TypedActionHandler | ||||||
| @@ -49,7 +50,15 @@ class HandlerInjector { | |||||||
|     fun notebookCommandMode(editor: Editor?): Boolean { |     fun notebookCommandMode(editor: Editor?): Boolean { | ||||||
|       return if (editor != null) { |       return if (editor != null) { | ||||||
|         val inEditor = EditorHelper.getVirtualFile(editor)?.extension == "ipynb" |         val inEditor = EditorHelper.getVirtualFile(editor)?.extension == "ipynb" | ||||||
|         TypedAction.getInstance().rawHandler::class.java.simpleName.equals("JupyterCommandModeTypingBlocker") && inEditor |         return if (TypedAction.getInstance().rawHandler::class.java.simpleName.equals("JupyterCommandModeTypingBlocker")) { | ||||||
|  |           inEditor | ||||||
|  |         } else { | ||||||
|  |           // only true in command mode. | ||||||
|  |           // Set by `org.jetbrains.plugins.notebooks.ui.editor.actions.command.mode.NotebookEditorModeListenerAdapter` | ||||||
|  |           // appears to be null in non Notebook editors | ||||||
|  |           val allow_plain_letter_shortcuts = editor.contentComponent.getClientProperty(ActionUtil.ALLOW_PlAIN_LETTER_SHORTCUTS) | ||||||
|  |           inEditor && (allow_plain_letter_shortcuts != null && allow_plain_letter_shortcuts as Boolean) | ||||||
|  |         } | ||||||
|       } else { |       } else { | ||||||
|         TypedAction.getInstance().rawHandler::class.java.simpleName.equals("JupyterCommandModeTypingBlocker") |         TypedAction.getInstance().rawHandler::class.java.simpleName.equals("JupyterCommandModeTypingBlocker") | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -15,9 +15,11 @@ import com.intellij.openapi.command.impl.UndoManagerImpl | |||||||
| import com.intellij.openapi.command.undo.UndoManager | import com.intellij.openapi.command.undo.UndoManager | ||||||
| import com.intellij.openapi.components.Service | import com.intellij.openapi.components.Service | ||||||
| import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider | import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider | ||||||
|  | import com.maddyhome.idea.vim.VimPlugin | ||||||
| import com.maddyhome.idea.vim.api.ExecutionContext | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
| import com.maddyhome.idea.vim.api.VimEditor | import com.maddyhome.idea.vim.api.VimEditor | ||||||
| import com.maddyhome.idea.vim.api.injector | import com.maddyhome.idea.vim.api.injector | ||||||
|  | import com.maddyhome.idea.vim.command.VimStateMachine | ||||||
| import com.maddyhome.idea.vim.common.ChangesListener | import com.maddyhome.idea.vim.common.ChangesListener | ||||||
| import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor | import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor | ||||||
| import com.maddyhome.idea.vim.newapi.ij | import com.maddyhome.idea.vim.newapi.ij | ||||||
| @@ -42,6 +44,7 @@ class UndoRedoHelper : UndoRedoBase() { | |||||||
|     if (undoManager.isUndoAvailable(fileEditor)) { |     if (undoManager.isUndoAvailable(fileEditor)) { | ||||||
|       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { |       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { | ||||||
|         SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } |         SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } | ||||||
|  |         restoreVisualMode(editor) | ||||||
|       } else { |       } else { | ||||||
|         performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) |         performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) | ||||||
|  |  | ||||||
| @@ -71,6 +74,7 @@ class UndoRedoHelper : UndoRedoBase() { | |||||||
|     if (undoManager.isRedoAvailable(fileEditor)) { |     if (undoManager.isRedoAvailable(fileEditor)) { | ||||||
|       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { |       if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) { | ||||||
|         SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } |         SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } | ||||||
|  |         restoreVisualMode(editor) | ||||||
|       } else { |       } else { | ||||||
|         performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) |         performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) | ||||||
|         CommandProcessor.getInstance().runUndoTransparentAction { |         CommandProcessor.getInstance().runUndoTransparentAction { | ||||||
| @@ -105,4 +109,21 @@ class UndoRedoHelper : UndoRedoBase() { | |||||||
|   private fun ifFilePathChanged(editor: VimEditor, oldPath: String?): Boolean { |   private fun ifFilePathChanged(editor: VimEditor, oldPath: String?): Boolean { | ||||||
|     return editor.getPath() != oldPath |     return editor.getPath() != oldPath | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private fun restoreVisualMode(editor: VimEditor) { | ||||||
|  |     if (!editor.mode.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 == VimStateMachine.SubMode.VISUAL_BLOCK) | ||||||
|  |         VimStateMachine.SubMode.VISUAL_CHARACTER | ||||||
|  |       else | ||||||
|  |         detectedMode | ||||||
|  |        | ||||||
|  |       VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode) | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,29 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright 2003-2022 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) |  | ||||||
| class VimStandalonePluginUpdateChecker : StandalonePluginUpdateChecker( |  | ||||||
|   VimPlugin.getPluginId(), |  | ||||||
|   updateTimestampProperty = PROPERTY_NAME, |  | ||||||
|   NotificationService.IDEAVIM_STICKY_GROUP, |  | ||||||
|   VimIcons.IDEAVIM, |  | ||||||
| ) { |  | ||||||
|   companion object { |  | ||||||
|     private const val PROPERTY_NAME = "ideavim.statistics.timestamp" |  | ||||||
|     val instance: VimStandalonePluginUpdateChecker = service() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -63,7 +63,9 @@ private var Caret._vimSelectionStart: Int? by userDataCaretToEditor() | |||||||
|  |  | ||||||
| // Keep a track of the column that we intended to navigate to but were unable to. This might be because of inlays, | // Keep a track of the column that we intended to navigate to but were unable to. This might be because of inlays, | ||||||
| // virtual indent or moving from the end of a long line to the end of a short line. Keep a track of the position when | // virtual indent or moving from the end of a long line to the end of a short line. Keep a track of the position when | ||||||
| // the value is set, if it's not the same during get, we've been moved by IJ and so no longer valid | // the value is set, if it's not the same during get, we've been moved by IJ and so no longer valid. We also invalidate | ||||||
|  | // the cached value through a caret listener handler, to prevent issues with the caret being moved and returned before | ||||||
|  | // the cache is checked/invalidated | ||||||
| var Caret.vimLastColumn: Int | var Caret.vimLastColumn: Int | ||||||
|   get() { |   get() { | ||||||
|     if (visualPosition != _vimLastColumnPos) { |     if (visualPosition != _vimLastColumnPos) { | ||||||
|   | |||||||
| @@ -52,7 +52,6 @@ import com.maddyhome.idea.vim.group.visual.VimVisualTimer | |||||||
| import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd | import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd | ||||||
| import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently | import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently | ||||||
| import com.maddyhome.idea.vim.helper.GuicursorChangeListener | import com.maddyhome.idea.vim.helper.GuicursorChangeListener | ||||||
| import com.maddyhome.idea.vim.helper.VimStandalonePluginUpdateChecker |  | ||||||
| import com.maddyhome.idea.vim.helper.exitSelectMode | import com.maddyhome.idea.vim.helper.exitSelectMode | ||||||
| import com.maddyhome.idea.vim.helper.exitVisualMode | import com.maddyhome.idea.vim.helper.exitVisualMode | ||||||
| import com.maddyhome.idea.vim.helper.forceBarCursor | import com.maddyhome.idea.vim.helper.forceBarCursor | ||||||
| @@ -62,6 +61,7 @@ import com.maddyhome.idea.vim.helper.isEndAllowed | |||||||
| import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere | ||||||
| import com.maddyhome.idea.vim.helper.localEditors | import com.maddyhome.idea.vim.helper.localEditors | ||||||
| import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset | ||||||
|  | import com.maddyhome.idea.vim.helper.resetVimLastColumn | ||||||
| import com.maddyhome.idea.vim.helper.subMode | import com.maddyhome.idea.vim.helper.subMode | ||||||
| import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes | import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes | ||||||
| import com.maddyhome.idea.vim.helper.vimDisabled | import com.maddyhome.idea.vim.helper.vimDisabled | ||||||
| @@ -157,6 +157,7 @@ object VimListenerManager { | |||||||
|       eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable) |       eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable) | ||||||
|       eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable) |       eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable) | ||||||
|       eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable) |       eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable) | ||||||
|  |       eventFacade.addCaretListener(editor, EditorCaretHandler, disposable) | ||||||
|  |  | ||||||
|       VimPlugin.getEditor().editorCreated(editor) |       VimPlugin.getEditor().editorCreated(editor) | ||||||
|  |  | ||||||
| @@ -175,6 +176,7 @@ object VimListenerManager { | |||||||
|       eventFacade.removeEditorMouseMotionListener(editor, EditorMouseHandler) |       eventFacade.removeEditorMouseMotionListener(editor, EditorMouseHandler) | ||||||
|       eventFacade.removeEditorSelectionListener(editor, EditorSelectionHandler) |       eventFacade.removeEditorSelectionListener(editor, EditorSelectionHandler) | ||||||
|       eventFacade.removeComponentMouseListener(editor.contentComponent, ComponentMouseListener) |       eventFacade.removeComponentMouseListener(editor.contentComponent, ComponentMouseListener) | ||||||
|  |       eventFacade.removeCaretListener(editor, EditorCaretHandler) | ||||||
|  |  | ||||||
|       VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased) |       VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased) | ||||||
|  |  | ||||||
| @@ -206,7 +208,6 @@ object VimListenerManager { | |||||||
|   private object VimEditorFactoryListener : EditorFactoryListener { |   private object VimEditorFactoryListener : EditorFactoryListener { | ||||||
|     override fun editorCreated(event: EditorFactoryEvent) { |     override fun editorCreated(event: EditorFactoryEvent) { | ||||||
|       add(event.editor) |       add(event.editor) | ||||||
|       VimStandalonePluginUpdateChecker.instance.pluginUsed() |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun editorReleased(event: EditorFactoryEvent) { |     override fun editorReleased(event: EditorFactoryEvent) { | ||||||
| @@ -494,6 +495,12 @@ object VimListenerManager { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private object EditorCaretHandler : CaretListener { | ||||||
|  |     override fun caretPositionChanged(event: CaretEvent) { | ||||||
|  |       event.caret?.resetVimLastColumn() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   enum class SelectionSource { |   enum class SelectionSource { | ||||||
|     MOUSE, |     MOUSE, | ||||||
|     OTHER |     OTHER | ||||||
|   | |||||||
| @@ -11,12 +11,17 @@ package com.maddyhome.idea.vim.ui | |||||||
| import com.intellij.icons.AllIcons | import com.intellij.icons.AllIcons | ||||||
| import com.intellij.ide.BrowserUtil | import com.intellij.ide.BrowserUtil | ||||||
| import com.intellij.ide.DataManager | import com.intellij.ide.DataManager | ||||||
|  | import com.intellij.ide.projectView.ProjectView | ||||||
|  | import com.intellij.ide.scratch.ScratchRootType | ||||||
|  | import com.intellij.ide.util.PsiNavigationSupport | ||||||
| import com.intellij.openapi.actionSystem.ActionManager | import com.intellij.openapi.actionSystem.ActionManager | ||||||
| import com.intellij.openapi.actionSystem.ActionPlaces | import com.intellij.openapi.actionSystem.ActionPlaces | ||||||
| import com.intellij.openapi.actionSystem.ActionUpdateThread | import com.intellij.openapi.actionSystem.ActionUpdateThread | ||||||
| import com.intellij.openapi.actionSystem.AnActionEvent | import com.intellij.openapi.actionSystem.AnActionEvent | ||||||
| import com.intellij.openapi.actionSystem.DataContext | import com.intellij.openapi.actionSystem.DataContext | ||||||
| import com.intellij.openapi.actionSystem.DefaultActionGroup | import com.intellij.openapi.actionSystem.DefaultActionGroup | ||||||
|  | import com.intellij.openapi.application.impl.LaterInvocator | ||||||
|  | import com.intellij.openapi.fileTypes.PlainTextLanguage | ||||||
| import com.intellij.openapi.options.ShowSettingsUtil | import com.intellij.openapi.options.ShowSettingsUtil | ||||||
| import com.intellij.openapi.project.DumbAwareAction | import com.intellij.openapi.project.DumbAwareAction | ||||||
| import com.intellij.openapi.project.Project | import com.intellij.openapi.project.Project | ||||||
| @@ -30,6 +35,7 @@ import com.intellij.openapi.wm.StatusBarWidget | |||||||
| import com.intellij.openapi.wm.StatusBarWidgetFactory | import com.intellij.openapi.wm.StatusBarWidgetFactory | ||||||
| import com.intellij.openapi.wm.WindowManager | import com.intellij.openapi.wm.WindowManager | ||||||
| import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager | import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager | ||||||
|  | import com.intellij.psi.PsiManager | ||||||
| import com.intellij.ui.awt.RelativePoint | import com.intellij.ui.awt.RelativePoint | ||||||
| import com.intellij.util.Consumer | import com.intellij.util.Consumer | ||||||
| import com.intellij.util.ui.LafIconLookup | import com.intellij.util.ui.LafIconLookup | ||||||
| @@ -193,6 +199,10 @@ private object VimActionsPopup { | |||||||
|       ) |       ) | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |     actionGroup.addSeparator("Learn") | ||||||
|  |  | ||||||
|  |     actionGroup.add(TutorAction()) | ||||||
|  |  | ||||||
|     actionGroup.addSeparator(MessageHelper.message("action.contacts.help.text")) |     actionGroup.addSeparator(MessageHelper.message("action.contacts.help.text")) | ||||||
|     actionGroup.add( |     actionGroup.add( | ||||||
|       HelpLink( |       HelpLink( | ||||||
| @@ -220,6 +230,22 @@ private object VimActionsPopup { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | private class TutorAction() : DumbAwareAction("Tutor") { | ||||||
|  |   override fun actionPerformed(e: AnActionEvent) { | ||||||
|  |     val project = e.project ?: return | ||||||
|  |     val file = ScratchRootType.getInstance() | ||||||
|  |       .createScratchFile(project, "Tutor.txt", PlainTextLanguage.INSTANCE, tutor) ?: return | ||||||
|  |  | ||||||
|  |     PsiNavigationSupport.getInstance() | ||||||
|  |       .createNavigatable(project, file, 0) | ||||||
|  |       .navigate(!LaterInvocator.isInModalContextForProject(project)) | ||||||
|  |  | ||||||
|  |     PsiManager.getInstance(project).findFile(file)?.let { | ||||||
|  |       ProjectView.getInstance(project).selectPsiElement(it, false) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| private class HelpLink( | private class HelpLink( | ||||||
|   @NlsActions.ActionText name: String, |   @NlsActions.ActionText name: String, | ||||||
|   val link: String, |   val link: String, | ||||||
|   | |||||||
							
								
								
									
										927
									
								
								src/main/java/com/maddyhome/idea/vim/ui/Tutor.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										927
									
								
								src/main/java/com/maddyhome/idea/vim/ui/Tutor.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,927 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2003-2022 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 | ||||||
|  |  | ||||||
|  | internal val tutor = """ | ||||||
|  |   =============================================================================== | ||||||
|  |   =                       Welcome to the IdeaVim Tutor                          = | ||||||
|  |   =============================================================================== | ||||||
|  |  | ||||||
|  |        Based on the original VIM Tutor: | ||||||
|  |        https://github.com/vim/vim/blob/master/runtime/tutor/tutor | ||||||
|  |  | ||||||
|  |        Vim is a very powerful editor that has many commands, too many to | ||||||
|  |        explain in a tutor such as this.  This tutor is designed to describe | ||||||
|  |        enough of the commands that you will be able to easily use Vim as | ||||||
|  |        an all-purpose editor. | ||||||
|  |         | ||||||
|  |        IdeaVim is a Vim engine for JetBrains IDEs, such as IntelliJ IDEA, PyCharm, | ||||||
|  |        and more. It allows you to use Vim-style editing inside of a full-fledged IDE. | ||||||
|  |  | ||||||
|  |        This tutorial doesn't cover a few things that are explained in Vim tutor, | ||||||
|  |        but aren’t relevant to IdeaVim (for example, how to exit Vim). If you’re | ||||||
|  |        still interested in them, see the last section. | ||||||
|  |  | ||||||
|  |        The approximate time required to complete the tutor is 30 minutes, | ||||||
|  |        depending upon how much time is spent with experimentation. | ||||||
|  |  | ||||||
|  |        It is important to remember that this tutor is set up to teach by | ||||||
|  |        use.  That means that you need to execute the commands to learn them | ||||||
|  |        properly.  If you only read the text, you will forget the commands! | ||||||
|  |  | ||||||
|  |        Now, make sure that your Caps-Lock key is NOT depressed and press | ||||||
|  |        the   j   key enough times to move the cursor so that lesson 1.1 | ||||||
|  |        completely fills the screen. | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                    Lesson 1.1:  MOVING THE CURSOR | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      ** To move the cursor, press the h,j,k,l keys as indicated. ** | ||||||
|  |              ^ | ||||||
|  |              k        Hint:  The h key is at the left and moves left. | ||||||
|  |         < h     l >          The l key is at the right and moves right. | ||||||
|  |              j               The j key looks like a down arrow. | ||||||
|  |              v | ||||||
|  |     1. Move the cursor around the screen until you are comfortable. | ||||||
|  |  | ||||||
|  |     2. Hold down the down key (j) until it repeats. | ||||||
|  |        Now you know how to move to the next lesson. | ||||||
|  |  | ||||||
|  |     3. Using the down key, move to lesson 1.2. | ||||||
|  |  | ||||||
|  |   NOTE: If you are ever unsure about something you typed, press <ESC> to place | ||||||
|  |         you in Normal mode.  Then retype the command you wanted. | ||||||
|  |  | ||||||
|  |   NOTE: The cursor keys should also work.  But using hjkl you will be able to | ||||||
|  |         move around much faster, once you get used to it.  Really! | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                  Lesson 1.2: TEXT EDITING - DELETION | ||||||
|  |  | ||||||
|  |  | ||||||
|  |        ** Press  x  to delete the character under the cursor. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the line below marked --->. | ||||||
|  |  | ||||||
|  |     2. To fix the errors, move the cursor until it is on top of the | ||||||
|  |        character to be deleted. | ||||||
|  |  | ||||||
|  |     3. Press the  x  key to delete the unwanted character. | ||||||
|  |  | ||||||
|  |     4. Repeat steps 2 through 4 until the sentence is correct. | ||||||
|  |  | ||||||
|  |   ---> The ccow jumpedd ovverr thhe mooon. | ||||||
|  |  | ||||||
|  |     5. Now that the line is correct, go on to lesson 1.4. | ||||||
|  |  | ||||||
|  |   NOTE: As you go through this tutor, do not try to memorize, learn by usage. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                Lesson 1.3: TEXT EDITING - INSERTION | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                  ** Press  i  to insert text. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. To make the first line the same as the second, move the cursor on top | ||||||
|  |        of the character BEFORE which the text is to be inserted. | ||||||
|  |  | ||||||
|  |     3. Press  i  and type in the necessary additions. | ||||||
|  |  | ||||||
|  |     4. As each error is fixed press <ESC> to return to Normal mode. | ||||||
|  |        Repeat steps 2 through 4 to correct the sentence. | ||||||
|  |  | ||||||
|  |   ---> There is text misng this . | ||||||
|  |   ---> There is some text missing from this line. | ||||||
|  |  | ||||||
|  |     5. When you are comfortable inserting text move to lesson 1.5. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                 Lesson 1.4: TEXT EDITING - APPENDING | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                   ** Press  A  to append text. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |        It does not matter on what character the cursor is in that line. | ||||||
|  |  | ||||||
|  |     2. Press  A  and type in the necessary additions. | ||||||
|  |  | ||||||
|  |     3. As the text has been appended press <ESC> to return to Normal mode. | ||||||
|  |  | ||||||
|  |     4. Move the cursor to the second line marked ---> and repeat | ||||||
|  |        steps 2 and 3 to correct this sentence. | ||||||
|  |  | ||||||
|  |   ---> There is some text missing from th | ||||||
|  |        There is some text missing from this line. | ||||||
|  |   ---> There is also some text miss | ||||||
|  |        There is also some text missing here. | ||||||
|  |  | ||||||
|  |     5. When you are comfortable appending text move to lesson 1.6. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  |                          Lesson 1 SUMMARY | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     1. The cursor is moved using either the arrow keys or the hjkl keys. | ||||||
|  |            h (left)  j (down)       k (up)      l (right) | ||||||
|  |  | ||||||
|  |     2. To delete the character at the cursor type:  x | ||||||
|  |  | ||||||
|  |     3. To insert or append text type: | ||||||
|  |           i   type inserted text   <ESC>         insert before the cursor | ||||||
|  |           A   type appended text   <ESC>         append after the line | ||||||
|  |  | ||||||
|  |   NOTE: Pressing <ESC> will place you in Normal mode or will cancel | ||||||
|  |         an unwanted and partially completed command. | ||||||
|  |  | ||||||
|  |   Now continue with lesson 2. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                     Lesson 2.1: DELETION COMMANDS | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                   ** Type  dw  to delete a word. ** | ||||||
|  |  | ||||||
|  |     1. Press  <ESC>  to make sure you are in Normal mode. | ||||||
|  |  | ||||||
|  |     2. Move the cursor to the line below marked --->. | ||||||
|  |  | ||||||
|  |     3. Move the cursor to the beginning of a word that needs to be deleted. | ||||||
|  |  | ||||||
|  |     4. Type   dw   to make the word disappear. | ||||||
|  |  | ||||||
|  |     NOTE: The letter  d  will appear in the status bar as you type it. | ||||||
|  |           Vim is waiting for you to type  w .  If you see another character | ||||||
|  |           than  d  you typed something wrong; press  <ESC>  and start over. | ||||||
|  |  | ||||||
|  |   ---> There are a some words fun that don't belong paper in this sentence. | ||||||
|  |  | ||||||
|  |     5. Repeat steps 3 and 4 until the sentence is correct and go to lesson 2.2. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                  Lesson 2.2: MORE DELETION COMMANDS | ||||||
|  |  | ||||||
|  |  | ||||||
|  |        ** Type  d${'$'}  to delete to the end of the line. ** | ||||||
|  |  | ||||||
|  |     1. Press  <ESC>  to make sure you are in Normal mode. | ||||||
|  |  | ||||||
|  |     2. Move the cursor to the line below marked --->. | ||||||
|  |  | ||||||
|  |     3. Move the cursor to the end of the correct line (AFTER the first . ). | ||||||
|  |  | ||||||
|  |     4. Type    d${'$'}    to delete to the end of the line. | ||||||
|  |  | ||||||
|  |   ---> Somebody typed the end of this line twice. end of this line twice. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     5. Move on to lesson 2.3 to understand what is happening. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                   Lesson 2.3: ON OPERATORS AND MOTIONS | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Many commands that change text are made from an operator and a motion. | ||||||
|  |     The format for a delete command with the  d  delete operator is as follows: | ||||||
|  |  | ||||||
|  |          d   motion | ||||||
|  |  | ||||||
|  |     Where: | ||||||
|  |       d      - is the delete operator. | ||||||
|  |       motion - is what the operator will operate on (listed below). | ||||||
|  |  | ||||||
|  |     A short list of motions: | ||||||
|  |       w - until the start of the next word, EXCLUDING its first character. | ||||||
|  |       e - to the end of the current word, INCLUDING the last character. | ||||||
|  |       ${'$'} - to the end of the line, INCLUDING the last character. | ||||||
|  |  | ||||||
|  |     Thus typing  de  will delete from the cursor to the end of the word. | ||||||
|  |  | ||||||
|  |   NOTE:  Pressing just the motion while in Normal mode without an operator will | ||||||
|  |          move the cursor as specified. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                   Lesson 2.4: USING A COUNT FOR A MOTION | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      ** Typing a number before a motion repeats it that many times. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the start of the line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Type  2w  to move the cursor two words forward. | ||||||
|  |  | ||||||
|  |     3. Type  3e  to move the cursor to the end of the third word forward. | ||||||
|  |  | ||||||
|  |     4. Type  0  (zero) to move to the start of the line. | ||||||
|  |  | ||||||
|  |     5. Repeat steps 2 and 3 with different numbers. | ||||||
|  |  | ||||||
|  |   ---> This is just a line with words you can move around in. | ||||||
|  |  | ||||||
|  |     6. Move on to lesson 2.5. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                  Lesson 2.5: USING A COUNT TO DELETE MORE | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      ** Typing a number with an operator repeats it that many times. ** | ||||||
|  |  | ||||||
|  |     In the combination of the delete operator and a motion mentioned above you | ||||||
|  |     insert a count before the motion to delete more: | ||||||
|  |            d   number   motion | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first UPPER CASE word in the line marked --->. | ||||||
|  |  | ||||||
|  |     2. Type  d2w  to delete the two UPPER CASE words. | ||||||
|  |  | ||||||
|  |     3. Repeat steps 1 and 2 with a different count to delete the consecutive | ||||||
|  |        UPPER CASE words with one command. | ||||||
|  |  | ||||||
|  |   --->  this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                      Lesson 2.6: OPERATING ON LINES | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          ** Type  dd   to delete a whole line. ** | ||||||
|  |  | ||||||
|  |     Due to the frequency of whole line deletion, the designers of Vi decided | ||||||
|  |     it would be easier to simply type two d's to delete a line. | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the second line in the phrase below. | ||||||
|  |     2. Type  dd  to delete the line. | ||||||
|  |     3. Now move to the fourth line. | ||||||
|  |     4. Type   2dd   to delete two lines. | ||||||
|  |  | ||||||
|  |   --->  1)  Roses are red, | ||||||
|  |   --->  2)  Mud is fun, | ||||||
|  |   --->  3)  Violets are blue, | ||||||
|  |   --->  4)  I have a car, | ||||||
|  |   --->  5)  Clocks tell time, | ||||||
|  |   --->  6)  Sugar is sweet | ||||||
|  |   --->  7)  And so are you. | ||||||
|  |  | ||||||
|  |   Doubling to operate on a line also works for operators mentioned below. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                    Lesson 2.7: THE UNDO COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      ** Press  u  to undo the last commands. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the line below marked ---> and place it on the | ||||||
|  |        first error. | ||||||
|  |     2. Type  x  to delete the first unwanted character. | ||||||
|  |     3. Now type  u  to undo the last command executed. | ||||||
|  |     4. This time fix all the errors on the line using the  x  command. | ||||||
|  |     6. Now type  u  a few times to undo the preceding commands. | ||||||
|  |     7. Now type CTRL-R (keeping CTRL key pressed while hitting R) a few times | ||||||
|  |        to redo the commands. | ||||||
|  |  | ||||||
|  |   ---> Fiix the errors oon thhis line and reeplace them witth undo. | ||||||
|  |  | ||||||
|  |     8. These are very useful commands.  Now move on to the lesson 2 Summary. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                         Lesson 2 SUMMARY | ||||||
|  |  | ||||||
|  |     1. To delete from the cursor up to the next word type:        dw | ||||||
|  |     2. To delete from the cursor up to the end of the word type:  de | ||||||
|  |     3. To delete from the cursor to the end of a line type:       d${'$'} | ||||||
|  |     4. To delete a whole line type:                               dd | ||||||
|  |  | ||||||
|  |     5. To repeat a motion prepend it with a number:   2w | ||||||
|  |     6. The format for a change command is: | ||||||
|  |                  operator   [number]   motion | ||||||
|  |        where: | ||||||
|  |          operator - is what to do, such as  d  for delete | ||||||
|  |          [number] - is an optional count to repeat the motion | ||||||
|  |          motion   - moves over the text to operate on, such as  w (word), | ||||||
|  |                     e (end of word),  ${'$'} (end of the line), etc. | ||||||
|  |  | ||||||
|  |     7. To move to the start of the line use a zero:  0 | ||||||
|  |  | ||||||
|  |     8. To undo previous actions, type:           u  (lowercase u) | ||||||
|  |        To undo the undo's, type:                 CTRL-R | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                           Lesson 3.1: THE PUT COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          ** Type  p  to put previously deleted text after the cursor. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Type  dd  to delete the line and store it in a Vim register. | ||||||
|  |  | ||||||
|  |     3. Move the cursor to the c) line, ABOVE where the deleted line should go. | ||||||
|  |  | ||||||
|  |     4. Type   p   to put the line below the cursor. | ||||||
|  |  | ||||||
|  |     5. Repeat steps 2 through 4 to put all the lines in correct order. | ||||||
|  |  | ||||||
|  |   ---> d) Can you learn too? | ||||||
|  |   ---> b) Violets are blue, | ||||||
|  |   ---> c) Intelligence is learned, | ||||||
|  |   ---> a) Roses are red, | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                          Lesson 3.2: THE REPLACE COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          ** Type  rx  to replace the character at the cursor with  x . ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Move the cursor so that it is on top of the first error. | ||||||
|  |  | ||||||
|  |     3. Type   r  and then the character which should be there. | ||||||
|  |  | ||||||
|  |     4. Repeat steps 2 and 3 until the first line is equal to the second one. | ||||||
|  |  | ||||||
|  |   --->  Whan this lime was tuoed in, someone presswd some wrojg keys! | ||||||
|  |   --->  When this line was typed in, someone pressed some wrong keys! | ||||||
|  |  | ||||||
|  |     5. Now move on to lesson 3.3. | ||||||
|  |  | ||||||
|  |   NOTE: Remember that you should be learning by doing, not memorization. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                     Lesson 3.3: THE CHANGE OPERATOR | ||||||
|  |  | ||||||
|  |  | ||||||
|  |           ** To change until the end of a word, type  ce . ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Place the cursor on the  u  in  lubw. | ||||||
|  |  | ||||||
|  |     3. Type  ce  and the correct word (in this case, type  ine ). | ||||||
|  |  | ||||||
|  |     4. Press <ESC> and move to the next character that needs to be changed. | ||||||
|  |  | ||||||
|  |     5. Repeat steps 3 and 4 until the first sentence is the same as the second. | ||||||
|  |  | ||||||
|  |   ---> This lubw has a few wptfd that mrrf changing usf the change operator. | ||||||
|  |   ---> This line has a few words that need changing using the change operator. | ||||||
|  |  | ||||||
|  |   Notice that  ce  deletes the word and places you in Insert mode. | ||||||
|  |                cc  does the same for the whole line. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                         Lesson 3.4: MORE CHANGES USING c | ||||||
|  |  | ||||||
|  |  | ||||||
|  |        ** The change operator is used with the same motions as delete. ** | ||||||
|  |  | ||||||
|  |     1. The change operator works in the same way as delete.  The format is: | ||||||
|  |  | ||||||
|  |            c    [number]   motion | ||||||
|  |  | ||||||
|  |     2. The motions are the same, such as   w (word) and  ${'$'} (end of line). | ||||||
|  |  | ||||||
|  |     3. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     4. Move the cursor to the first error. | ||||||
|  |  | ||||||
|  |     5. Type  c${'$'}  and type the rest of the line like the second and press <ESC>. | ||||||
|  |  | ||||||
|  |   ---> The end of this line needs some help to make it like the second. | ||||||
|  |   ---> The end of this line needs to be corrected using the  c${'$'}  command. | ||||||
|  |  | ||||||
|  |   NOTE:  You can use the Backspace key to correct mistakes while typing. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                            Lesson 3 SUMMARY | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     1. To put back text that has just been deleted, type   p .  This puts the | ||||||
|  |        deleted text AFTER the cursor (if a line was deleted it will go on the | ||||||
|  |        line below the cursor). | ||||||
|  |  | ||||||
|  |     2. To replace the character under the cursor, type   r   and then the | ||||||
|  |        character you want to have there. | ||||||
|  |  | ||||||
|  |     3. The change operator allows you to change from the cursor to where the | ||||||
|  |        motion takes you.  eg. Type  ce  to change from the cursor to the end of | ||||||
|  |        the word,  c${'$'}  to change to the end of a line. | ||||||
|  |  | ||||||
|  |     4. The format for change is: | ||||||
|  |  | ||||||
|  |            c   [number]   motion | ||||||
|  |  | ||||||
|  |   Now go on to the next lesson. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                Lesson 4.1: CURSOR LOCATION AND FILE STATUS | ||||||
|  |  | ||||||
|  |               ** Type  G  to move to a line in the file. ** | ||||||
|  |  | ||||||
|  |     NOTE: Read this entire lesson before executing any of the steps!! | ||||||
|  |  | ||||||
|  |     1. Remember the line number for Step 3. | ||||||
|  |  | ||||||
|  |     2. Press  G  to move you to the bottom of the file. | ||||||
|  |        Type  gg  to move you to the start of the file. | ||||||
|  |  | ||||||
|  |     3. Type the number of the line you were on and then  G .  This will | ||||||
|  |        return you to the line you were on before pressing  G. | ||||||
|  |  | ||||||
|  |     4. If you feel confident to do this, execute steps 1 through 3. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                          Lesson 4.2: THE SEARCH COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |        ** Type  /  followed by a phrase to search for the phrase. ** | ||||||
|  |  | ||||||
|  |     1. In Normal mode type the  /  character.  Notice that it and the cursor | ||||||
|  |        appear at the bottom of the screen as with the  :  command. | ||||||
|  |  | ||||||
|  |     2. Now type 'errroor' <ENTER>.  This is the word you want to search for. | ||||||
|  |  | ||||||
|  |     3. To search for the same phrase again, simply type  n . | ||||||
|  |        To search for the same phrase in the opposite direction, type  N . | ||||||
|  |  | ||||||
|  |     4. To search for a phrase in the backward direction, use  ?  instead of  / . | ||||||
|  |  | ||||||
|  |   --->  "errroor" is not the way to spell error;  errroor is an error. | ||||||
|  |   NOTE: When the search reaches the end of the file it will continue at the | ||||||
|  |         start, unless the 'wrapscan' option has been reset. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                  Lesson 4.3: MATCHING PARENTHESES SEARCH | ||||||
|  |  | ||||||
|  |  | ||||||
|  |               ** Type  %  to find a matching ),], or } . ** | ||||||
|  |  | ||||||
|  |     1. Place the cursor on any (, [, or { in the line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Now type the  %  character. | ||||||
|  |  | ||||||
|  |     3. The cursor will move to the matching parenthesis or bracket. | ||||||
|  |  | ||||||
|  |     4. Type  %  to move the cursor to the other matching bracket. | ||||||
|  |  | ||||||
|  |     5. Move the cursor to another (,),[,],{ or } and see what  %  does. | ||||||
|  |  | ||||||
|  |   ---> This ( is a test line with ('s, ['s ] and {'s } in it. )) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   NOTE: This is very useful in debugging a program with unmatched parentheses! | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                     Lesson 4.4: THE SUBSTITUTE COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |           ** Type  :s/old/new/g  to substitute 'new' for 'old'. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Type  :s/thee/the <ENTER>  .  Note that this command only changes the | ||||||
|  |        first occurrence of "thee" in the line. | ||||||
|  |  | ||||||
|  |     3. Now type  :s/thee/the/g .  Adding the  g  flag means to substitute | ||||||
|  |        globally in the line, change all occurrences of "thee" in the line. | ||||||
|  |  | ||||||
|  |   ---> thee best time to see thee flowers is in thee spring. | ||||||
|  |  | ||||||
|  |     4. To change every occurrence of a character string between two lines, | ||||||
|  |        type   :#,#s/old/new/g    where #,# are the line numbers of the range | ||||||
|  |                                  of lines where the substitution is to be done. | ||||||
|  |        Type   :%s/old/new/g      to change every occurrence in the whole file. | ||||||
|  |        Type   :%s/old/new/gc     to find every occurrence in the whole file, | ||||||
|  |                     with a prompt whether to substitute or not. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                             Lesson 4 SUMMARY | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     1. G  moves to the end of the file. | ||||||
|  |        number  G  moves to that line number. | ||||||
|  |               gg  moves to the first line. | ||||||
|  |  | ||||||
|  |     2. Typing  /  followed by a phrase searches FORWARD for the phrase. | ||||||
|  |        Typing  ?  followed by a phrase searches BACKWARD for the phrase. | ||||||
|  |        After a search type  n  to find the next occurrence in the same direction | ||||||
|  |        or  N  to search in the opposite direction. | ||||||
|  |  | ||||||
|  |     3. Typing  %  while the cursor is on a (,),[,],{, or } goes to its match. | ||||||
|  |  | ||||||
|  |     4. To substitute new for the first old in a line type    :s/old/new | ||||||
|  |        To substitute new for all 'old's on a line type       :s/old/new/g | ||||||
|  |        To substitute phrases between two line #'s type       :#,#s/old/new/g | ||||||
|  |        To substitute all occurrences in the file type        :%s/old/new/g | ||||||
|  |        To ask for confirmation each time add 'c'             :%s/old/new/gc | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                          Lesson 5.1: THE OPEN COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    ** Type  o  to open a line below the cursor and place you in Insert mode. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Type the lowercase letter  o  to open up a line BELOW the cursor and place | ||||||
|  |        you in Insert mode. | ||||||
|  |  | ||||||
|  |     3. Now type some text and press <ESC> to exit Insert mode. | ||||||
|  |  | ||||||
|  |   ---> After typing  o  the cursor is placed on the open line in Insert mode. | ||||||
|  |  | ||||||
|  |     4. To open up a line ABOVE the cursor, simply type a capital  O , rather | ||||||
|  |        than a lowercase  o.  Try this on the line below. | ||||||
|  |  | ||||||
|  |   ---> Open up a line above this by typing O while the cursor is on this line. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                    Lesson 5.2: THE APPEND COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          ** Type  a  to insert text AFTER the cursor. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the start of the first line below marked --->. | ||||||
|  |  | ||||||
|  |     2. Press  e  until the cursor is on the end of  li . | ||||||
|  |  | ||||||
|  |     3. Type an  a  (lowercase) to append text AFTER the cursor. | ||||||
|  |  | ||||||
|  |     4. Complete the word like the line below it.  Press <ESC> to exit Insert | ||||||
|  |        mode. | ||||||
|  |  | ||||||
|  |     5. Use  e  to move to the next incomplete word and repeat steps 3 and 4. | ||||||
|  |  | ||||||
|  |   ---> This li will allow you to pract appendi text to a line. | ||||||
|  |   ---> This line will allow you to practice appending text to a line. | ||||||
|  |  | ||||||
|  |   NOTE:  a, i and A all go to the same Insert mode, the only difference is where | ||||||
|  |          the characters are inserted. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                       Lesson 5.3: ANOTHER WAY TO REPLACE | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         ** Type a capital  R  to replace more than one character. ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to the first line below marked --->.  Move the cursor to | ||||||
|  |        the beginning of the first  xxx . | ||||||
|  |  | ||||||
|  |     2. Now press  R  and type the number below it in the second line, so that it | ||||||
|  |        replaces the xxx . | ||||||
|  |  | ||||||
|  |     3. Press <ESC> to leave Replace mode.  Notice that the rest of the line | ||||||
|  |        remains unmodified. | ||||||
|  |  | ||||||
|  |     4. Repeat the steps to replace the remaining xxx. | ||||||
|  |  | ||||||
|  |   ---> Adding 123 to xxx gives you xxx. | ||||||
|  |   ---> Adding 123 to 456 gives you 579. | ||||||
|  |  | ||||||
|  |   NOTE:  Replace mode is like Insert mode, but every typed character deletes an | ||||||
|  |          existing character. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                  Lesson 5.4: COPY AND PASTE TEXT | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       ** Use the  y  operator to copy text and  p  to paste it ** | ||||||
|  |  | ||||||
|  |     1. Move to the line below marked ---> and place the cursor after "a)". | ||||||
|  |  | ||||||
|  |     2. Start Visual mode with  v  and move the cursor to just before "first". | ||||||
|  |  | ||||||
|  |     3. Type  y  to yank (copy) the highlighted text. | ||||||
|  |  | ||||||
|  |     4. Move the cursor to the end of the next line:  j${'$'} | ||||||
|  |  | ||||||
|  |     5. Type  p  to put (paste) the text.  Then type:  a second <ESC> . | ||||||
|  |  | ||||||
|  |     6. Use Visual mode to select " item.", yank it with  y , move to the end of | ||||||
|  |        the next line with  j${'$'}  and put the text there with  p . | ||||||
|  |  | ||||||
|  |   --->  a) this is the first item. | ||||||
|  |         b) | ||||||
|  |  | ||||||
|  |     NOTE: You can also use  y  as an operator:  yw  yanks one word, | ||||||
|  |           yy  yanks the whole line, then  p  puts that line. | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                      Lesson 5.5: SET OPTION | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       ** Set an option so a search or substitute ignores case ** | ||||||
|  |  | ||||||
|  |     1. Search for 'ignore' by entering:  /ignore <ENTER> | ||||||
|  |        Repeat several times by pressing  n . | ||||||
|  |  | ||||||
|  |     2. Set the 'ic' (Ignore case) option by entering:   :set ic | ||||||
|  |  | ||||||
|  |     3. Now search for 'ignore' again by pressing  n | ||||||
|  |        Notice that Ignore and IGNORE are now also found. | ||||||
|  |  | ||||||
|  |     4. Set the 'hlsearch' and 'incsearch' options:  :set hls is | ||||||
|  |  | ||||||
|  |     5. Now type the search command again and see what happens:  /ignore <ENTER> | ||||||
|  |  | ||||||
|  |     6. To disable ignoring case enter:  :set noic | ||||||
|  |  | ||||||
|  |   NOTE:  To remove the highlighting of matches enter:   :nohlsearch | ||||||
|  |   NOTE:  If you want to ignore case for just one search command, use  \c | ||||||
|  |          in the phrase:  /ignore\c <ENTER> | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                       Lesson 5 SUMMARY | ||||||
|  |  | ||||||
|  |     1. Type  o  to open a line BELOW the cursor and start Insert mode. | ||||||
|  |        Type  O  to open a line ABOVE the cursor. | ||||||
|  |  | ||||||
|  |     2. Type  a  to insert text AFTER the cursor. | ||||||
|  |        Type  A  to insert text after the end of the line. | ||||||
|  |  | ||||||
|  |     3. The  e  command moves to the end of a word. | ||||||
|  |  | ||||||
|  |     4. The  y  operator yanks (copies) text,  p  puts (pastes) it. | ||||||
|  |  | ||||||
|  |     5. Typing a capital  R  enters Replace mode until  <ESC>  is pressed. | ||||||
|  |  | ||||||
|  |     6. Typing ":set xxx" sets the option "xxx".  Some options are: | ||||||
|  |       'ic'  'ignorecase'  ignore upper/lower case when searching | ||||||
|  |       'is'  'incsearch'   show partial matches for a search phrase | ||||||
|  |       'hls' 'hlsearch'    highlight all matching phrases | ||||||
|  |        You can either use the long or the short option name. | ||||||
|  |  | ||||||
|  |     7. Prepend "no" to switch an option off:   :set noic | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  |             Lesson 6.1: CREATE A STARTUP SCRIPT | ||||||
|  |  | ||||||
|  |  | ||||||
|  |               ** Enable IdeaVim features ** | ||||||
|  |                | ||||||
|  |     IdeaVim and Vim have many more features than Vi, but most of them are disabled | ||||||
|  |     by default. To start using more features, first create an "ideavimrc" file. | ||||||
|  |     For Vim it’s a "vimrc" file. | ||||||
|  |  | ||||||
|  |     To do so, click the IdeaVim status bar icon | ||||||
|  |     (the green V letter) and click "Create ~/.ideavimrc". This will create a | ||||||
|  |     ".ideavimrc" file in your home directory. | ||||||
|  |  | ||||||
|  |     Add the following lines to the file: | ||||||
|  |      | ||||||
|  |           Plug 'machakann/vim-highlightedyank' | ||||||
|  |           set incsearch | ||||||
|  |  | ||||||
|  |     Click on the reload icon in the upper-right corner of the editor. | ||||||
|  |  | ||||||
|  |     With these commands, you've enable the "highlightedyank" plugin and incremental | ||||||
|  |     search. The "highlightedyank" plugin highlights the text that was yanked. | ||||||
|  |     The incremental search feature shows search matches as you type the query. | ||||||
|  |  | ||||||
|  |     You can find more plugins by clicking “Status bar icon | Plugins…”. | ||||||
|  |  | ||||||
|  |     You can add all of your preferred settings to this "ideavimrc" file. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |                          Lesson 6 SUMMARY | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     1. Create an ideavimrc startup script to keep your preferred settings. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  |     This concludes the IdeaVim Tutor.  It was intended to give a brief overview of | ||||||
|  |     the IdeaVim plugin, just enough to allow you to use the editor fairly easily. | ||||||
|  |     It is far from complete as IdeaVim and Vim have many many more commands. | ||||||
|  |  | ||||||
|  |     For further reading and studying, this book is recommended: | ||||||
|  |        Vim - Vi Improved - by Steve Oualline | ||||||
|  |        Publisher: New Riders | ||||||
|  |     The first book completely dedicated to Vim.  Especially useful for beginners. | ||||||
|  |     There are many examples and pictures. | ||||||
|  |     See https://iccf-holland.org/click5.html | ||||||
|  |  | ||||||
|  |     This book is older and more about Vi than Vim, but also recommended: | ||||||
|  |        Learning the Vi Editor - by Linda Lamb | ||||||
|  |         Publisher: O'Reilly & Associates Inc. | ||||||
|  |     It is a good book to get to know almost anything you want to do with Vi. | ||||||
|  |     The sixth edition also includes information on Vim. | ||||||
|  |  | ||||||
|  |     This tutorial was written by Michael C. Pierce and Robert K. Ware, | ||||||
|  |     Colorado School of Mines using ideas supplied by Charles Smith, | ||||||
|  |     Colorado State University.  E-mail: bware@mines.colorado.edu. | ||||||
|  |  | ||||||
|  |     To learn more about IdeaVim, visit the official GitHub repository: | ||||||
|  |     https://github.com/JetBrains/ideavim | ||||||
|  |  | ||||||
|  |     Modified for Vim by Bram Moolenaar. | ||||||
|  |  | ||||||
|  |     Modified for IdeaVim by Alex Plate. | ||||||
|  |  | ||||||
|  |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  |     We removed the Vim Tutor sections that are related to the Vim editor, | ||||||
|  |     but not really applicable to the IdeaVim plugin. | ||||||
|  |     We recommend running these steps in an actual Vim editor. | ||||||
|  |  | ||||||
|  |             Lesson 1.2: EXITING VIM | ||||||
|  |        | ||||||
|  |          !! NOTE: Before executing any of the steps below, read this entire lesson!! | ||||||
|  |  | ||||||
|  |     1. Press the <ESC> key (to make sure you are in Normal mode). | ||||||
|  |  | ||||||
|  |     2. Type:  :q! <ENTER>. | ||||||
|  |        This exits the editor, DISCARDING any changes you have made. | ||||||
|  |  | ||||||
|  |     3. Get back here by executing the command that got you into this tutor. That | ||||||
|  |        might be:  vimtutor <ENTER> | ||||||
|  |  | ||||||
|  |     4. If you have these steps memorized and are confident, execute steps | ||||||
|  |        1 through 3 to exit and re-enter the editor. | ||||||
|  |  | ||||||
|  |   NOTE:  :q! <ENTER>  discards any changes you made.  In a few lessons you | ||||||
|  |          will learn how to save the changes to a file. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |            Lesson 1.6: EDITING A FILE | ||||||
|  |  | ||||||
|  |           ** Use  :wq  to save a file and exit. ** | ||||||
|  |  | ||||||
|  |     !! NOTE: Before executing any of the steps below, read this entire lesson!! | ||||||
|  |  | ||||||
|  |     1.  If you have access to another terminal, do the following there. | ||||||
|  |         Otherwise, exit this tutor as you did in lesson 1.2:  :q! | ||||||
|  |  | ||||||
|  |     2. At the shell prompt type this command:  vim file.txt <ENTER> | ||||||
|  |        'vim' is the command to start the Vim editor, 'file.txt' is the name of | ||||||
|  |        the file you wish to edit.  Use the name of a file that you can change. | ||||||
|  |  | ||||||
|  |     3. Insert and delete text as you learned in the previous lessons. | ||||||
|  |  | ||||||
|  |     4. Save the file with changes and exit Vim with:  :wq <ENTER> | ||||||
|  |  | ||||||
|  |     5. If you have quit vimtutor in step 1 restart the vimtutor and move down to | ||||||
|  |        the following summary. | ||||||
|  |  | ||||||
|  |     6. After reading the above steps and understanding them: do it. | ||||||
|  |  | ||||||
|  |       Lesson 5.1: HOW TO EXECUTE AN EXTERNAL COMMAND | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      ** Type  :!  followed by an external command to execute that command. ** | ||||||
|  |  | ||||||
|  |     1. Type the familiar command  :  to set the cursor at the bottom of the | ||||||
|  |        screen.  This allows you to enter a command-line command. | ||||||
|  |  | ||||||
|  |     2. Now type the  !  (exclamation point) character.  This allows you to | ||||||
|  |        execute any external shell command. | ||||||
|  |  | ||||||
|  |     3. As an example type   ls   following the ! and then hit <ENTER>.  This | ||||||
|  |        will show you a listing of your directory, just as if you were at the | ||||||
|  |        shell prompt.  Or use  :!dir  if ls doesn't work. | ||||||
|  |  | ||||||
|  |   NOTE:  It is possible to execute any external command this way, also with | ||||||
|  |          arguments. | ||||||
|  |  | ||||||
|  |   NOTE:  All  :  commands must be finished by hitting <ENTER> | ||||||
|  |          From here on we will not always mention it. | ||||||
|  |  | ||||||
|  |             Lesson 5.2: MORE ON WRITING FILES | ||||||
|  |  | ||||||
|  |  | ||||||
|  |        ** To save the changes made to the text, type  :w FILENAME  ** | ||||||
|  |  | ||||||
|  |     1. Type  :!dir  or  :!ls  to get a listing of your directory. | ||||||
|  |        You already know you must hit <ENTER> after this. | ||||||
|  |  | ||||||
|  |     2. Choose a filename that does not exist yet, such as TEST. | ||||||
|  |  | ||||||
|  |     3. Now type:   :w TEST   (where TEST is the filename you chose.) | ||||||
|  |  | ||||||
|  |     4. This saves the whole file (the Vim Tutor) under the name TEST. | ||||||
|  |        To verify this, type    :!dir  or  :!ls   again to see your directory. | ||||||
|  |  | ||||||
|  |   NOTE: If you were to exit Vim and start it again with  vim TEST , the file | ||||||
|  |         would be an exact copy of the tutor when you saved it. | ||||||
|  |  | ||||||
|  |     5. Now remove the file by typing (Windows):   :!del TEST | ||||||
|  |           or (Unix):  :!rm TEST | ||||||
|  |  | ||||||
|  |           Lesson 5.3: SELECTING TEXT TO WRITE | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     ** To save part of the file, type  v  motion  :w FILENAME ** | ||||||
|  |  | ||||||
|  |     1. Move the cursor to this line. | ||||||
|  |  | ||||||
|  |     2. Press  v  and move the cursor to the fifth item below.  Notice that the | ||||||
|  |        text is highlighted. | ||||||
|  |  | ||||||
|  |     3. Press the  :  character.  At the bottom of the screen  :'<,'> will appear. | ||||||
|  |  | ||||||
|  |     4. Type  w TEST  , where TEST is a filename that does not exist yet.  Verify | ||||||
|  |        that you see  :'<,'>w TEST  before you press <ENTER>. | ||||||
|  |  | ||||||
|  |     5. Vim will write the selected lines to the file TEST.  Use  :!dir  or  :!ls | ||||||
|  |        to see it.  Do not remove it yet!  We will use it in the next lesson. | ||||||
|  |  | ||||||
|  |   NOTE:  Pressing  v  starts Visual selection.  You can move the cursor around | ||||||
|  |          to make the selection bigger or smaller.  Then you can use an operator | ||||||
|  |          to do something with the text.  For example,  d  deletes the text. | ||||||
|  |  | ||||||
|  |          Lesson 5.4: RETRIEVING AND MERGING FILES | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          ** To insert the contents of a file, type  :r FILENAME  ** | ||||||
|  |  | ||||||
|  |     1. Place the cursor just above this line. | ||||||
|  |  | ||||||
|  |   NOTE:  After executing Step 2 you will see text from lesson 5.3.  Then move | ||||||
|  |          DOWN to see this lesson again. | ||||||
|  |  | ||||||
|  |     2. Now retrieve your TEST file using the command   :r TEST   where TEST is | ||||||
|  |        the name of the file you used. | ||||||
|  |        The file you retrieve is placed below the cursor line. | ||||||
|  |  | ||||||
|  |     3. To verify that a file was retrieved, cursor back and notice that there | ||||||
|  |        are now two copies of lesson 5.3, the original and the file version. | ||||||
|  |  | ||||||
|  |   NOTE:  You can also read the output of an external command.  For example, | ||||||
|  |          :r !ls  reads the output of the ls command and puts it below the | ||||||
|  |          cursor. | ||||||
|  |  | ||||||
|  |              Lesson 7.1: GETTING HELP | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             ** Use the on-line help system ** | ||||||
|  |  | ||||||
|  |     Vim has a comprehensive on-line help system.  To get started, try one of | ||||||
|  |     these three: | ||||||
|  |     - press the <HELP> key (if you have one) | ||||||
|  |     - press the <F1> key (if you have one) | ||||||
|  |     - type   :help <ENTER> | ||||||
|  |  | ||||||
|  |     Read the text in the help window to find out how the help works. | ||||||
|  |     Type  CTRL-W CTRL-W   to jump from one window to another. | ||||||
|  |     Type    :q <ENTER>    to close the help window. | ||||||
|  |  | ||||||
|  |     You can find help on just about any subject, by giving an argument to the | ||||||
|  |     ":help" command.  Try these (don't forget pressing <ENTER>): | ||||||
|  |  | ||||||
|  |     :help w | ||||||
|  |     :help c_CTRL-D | ||||||
|  |     :help insert-index | ||||||
|  |     :help user-manual | ||||||
|  |  | ||||||
|  |              Lesson 7.3: COMPLETION | ||||||
|  |  | ||||||
|  |  | ||||||
|  |           ** Command line completion with CTRL-D and <TAB> ** | ||||||
|  |  | ||||||
|  |     1. Make sure Vim is not in compatible mode:  :set nocp | ||||||
|  |  | ||||||
|  |     2. Look what files exist in the directory:  :!ls   or  :!dir | ||||||
|  |  | ||||||
|  |     3. Type the start of a command:  :e | ||||||
|  |  | ||||||
|  |     4. Press  CTRL-D  and Vim will show a list of commands that start with "e". | ||||||
|  |  | ||||||
|  |     5. Type  d<TAB>  and Vim will complete the command name to ":edit". | ||||||
|  |  | ||||||
|  |     6. Now add a space and the start of an existing file name:  :edit FIL | ||||||
|  |  | ||||||
|  |     7. Press <TAB>.  Vim will complete the name (if it is unique). | ||||||
|  |  | ||||||
|  |   NOTE:  Completion works for many commands.  Just try pressing CTRL-D and | ||||||
|  |          <TAB>.  It is especially useful for  :help . | ||||||
|  | """.trimIndent() | ||||||
| @@ -293,7 +293,7 @@ public class ExEntryPanel extends JPanel { | |||||||
|         VimPlugin.getEditor().closeEditorSearchSession(editor); |         VimPlugin.getEditor().closeEditorSearchSession(editor); | ||||||
|         final int matchOffset = SearchHighlightsHelper.updateIncsearchHighlights(editor, pattern, forwards, caretOffset, searchRange); |         final int matchOffset = SearchHighlightsHelper.updateIncsearchHighlights(editor, pattern, forwards, caretOffset, searchRange); | ||||||
|         if (matchOffset != -1) { |         if (matchOffset != -1) { | ||||||
|           editor.getCaretModel().getPrimaryCaret().moveToOffset(matchOffset); |           new IjVimCaret(editor.getCaretModel().getPrimaryCaret()).moveToOffset(matchOffset); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|           resetCaretOffset(editor); |           resetCaretOffset(editor); | ||||||
|   | |||||||
| @@ -0,0 +1,48 @@ | |||||||
|  | /* | ||||||
|  |  * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform | ||||||
|  |  * Copyright (C) 2003-2021 The IdeaVim authors | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 2 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package com.maddyhome.idea.vim.vimscript.model.functions.handlers | ||||||
|  |  | ||||||
|  | import com.intellij.refactoring.rename.inplace.InplaceRefactoring | ||||||
|  | import com.maddyhome.idea.vim.api.ExecutionContext | ||||||
|  | import com.maddyhome.idea.vim.api.VimEditor | ||||||
|  | import com.maddyhome.idea.vim.newapi.ij | ||||||
|  | import com.maddyhome.idea.vim.vimscript.model.VimLContext | ||||||
|  | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType | ||||||
|  | import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt | ||||||
|  | import com.maddyhome.idea.vim.vimscript.model.expressions.Expression | ||||||
|  | import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler | ||||||
|  |  | ||||||
|  | object RenamingFunctionHandler : FunctionHandler() { | ||||||
|  |  | ||||||
|  |   override val name = "renaming" | ||||||
|  |   override val minimumNumberOfArguments = 0 | ||||||
|  |   override val maximumNumberOfArguments = 0 | ||||||
|  |    | ||||||
|  |   override fun doFunction( | ||||||
|  |     argumentValues: List<Expression>, | ||||||
|  |     editor: VimEditor, | ||||||
|  |     context: ExecutionContext, | ||||||
|  |     vimContext: VimLContext, | ||||||
|  |   ): VimDataType { | ||||||
|  |     return if (InplaceRefactoring.getActiveInplaceRenamer(editor.ij) == null) | ||||||
|  |       VimInt.ZERO | ||||||
|  |     else | ||||||
|  |       VimInt.ONE | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -226,12 +226,12 @@ | |||||||
|  |  | ||||||
|     <!-- Change --> |     <!-- Change --> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction" mappingModes="N" keys="gu"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerMotionAction" mappingModes="N" keys="gu"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction" mappingModes="X" keys="u"/> | <!--    <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseLowerVisualAction" mappingModes="X" keys="u"/>--> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction" mappingModes="N" keys="~"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleCharacterAction" mappingModes="N" keys="~"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction" mappingModes="N" keys="g~"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleMotionAction" mappingModes="N" keys="g~"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction" mappingModes="X" keys="~"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseToggleVisualAction" mappingModes="X" keys="~"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction" mappingModes="N" keys="gU"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperMotionAction" mappingModes="N" keys="gU"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction" mappingModes="X" keys="U"/> | <!--    <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCaseUpperVisualAction" mappingModes="X" keys="U"/>--> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction" mappingModes="N" keys="r"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCharacterAction" mappingModes="N" keys="r"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction" mappingModes="N" keys="s"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeCharactersAction" mappingModes="N" keys="s"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction" mappingModes="N" keys="C"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.change.ChangeEndOfLineAction" mappingModes="N" keys="C"/> | ||||||
| @@ -329,8 +329,8 @@ | |||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.RepeatChangeAction" mappingModes="N" keys="."/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.RepeatChangeAction" mappingModes="N" keys="."/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.ExEntryAction" mappingModes="NXO" keys=":"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.ExEntryAction" mappingModes="NXO" keys=":"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.ResetModeAction" mappingModes="ALL" keys="«C-\»«C-N»"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.ResetModeAction" mappingModes="ALL" keys="«C-\»«C-N»"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.RedoAction" mappingModes="N" keys="«C-R»"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.RedoAction" mappingModes="NX" keys="U,«C-R»"/> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.UndoAction" mappingModes="N"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.UndoAction" mappingModes="NX"/> | ||||||
|  |  | ||||||
|     <!-- Keys --> |     <!-- Keys --> | ||||||
|     <vimAction implementation="com.maddyhome.idea.vim.action.change.OperatorAction" mappingModes="N" keys="g@"/> |     <vimAction implementation="com.maddyhome.idea.vim.action.change.OperatorAction" mappingModes="N" keys="g@"/> | ||||||
|   | |||||||
| @@ -22,5 +22,6 @@ | |||||||
|     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler" name="tolower"/> |     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler" name="tolower"/> | ||||||
|     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler" name="toupper"/> |     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler" name="toupper"/> | ||||||
|     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/> |     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/> | ||||||
|  |     <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.RenamingFunctionHandler" name="renaming"/> | ||||||
|   </extensions> |   </extensions> | ||||||
| </idea-plugin> | </idea-plugin> | ||||||
|   | |||||||
| @@ -1,39 +1,35 @@ | |||||||
| <!-- | <idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude"> | ||||||
|   ~ Copyright 2003-2022 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"> |  | ||||||
|   <name>IdeaVim</name> |   <name>IdeaVim</name> | ||||||
|   <id>IdeaVIM</id> |   <id>IdeaVIM</id> | ||||||
|   <change-notes><![CDATA[ |   <change-notes><![CDATA[ | ||||||
|     <h3>Changes:</h3> |  | ||||||
|     <ul> |  | ||||||
|       <li>IdeaVim changes license from GPL-2.0 or later to MIT. <a href="https://youtrack.jetbrains.com/issue/VIM-2782">VIM-2782</a> |  | ||||||
|       </li> |  | ||||||
|     </ul> |  | ||||||
|     <h3>Fixes:</h3> |     <h3>Fixes:</h3> | ||||||
|     <ul> |     <ul> | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-1758">VIM-1758</a> Commentary plugin in rider</li> |       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2797">VIM-2797</a> Introduce variable to mute default argtextobj | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-1903">VIM-1903</a> Autoindent now works in rider</li> |         mappings | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2744">VIM-2744</a> Fix undo from ex line</li> |  | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2749">VIM-2749</a> Fix :tabn and :tabN commands</li> |  | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2718">VIM-2718</a> Fixed case where the primary caret was |  | ||||||
|         changed |  | ||||||
|       </li> |       </li> | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2766">VIM-2766</a> Move NERDTree update to background thread |       <li><a href="https://youtrack.jetbrains.com/issue/VIM-758">VIM-758</a> Support d mappings</li> | ||||||
|  |       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2577">VIM-2577</a> Fix paste at the end of notebook cell</li> | ||||||
|  |       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2813">VIM-2813</a> Migrate update checker to | ||||||
|  |         VimStandalonePluginUpdateChecker | ||||||
|       </li> |       </li> | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2768">VIM-2768</a> Refactor listeners</li> |  | ||||||
|       <li><a href="https://youtrack.jetbrains.com/issue/VIM-2776">VIM-2776</a> Use filename index for file search</li> |  | ||||||
|     </ul> |     </ul> | ||||||
|  |  | ||||||
|     <h3>Merged PRs:</h3> |     <h3>Merged PRs:</h3> | ||||||
|     <ul> |     <ul> | ||||||
|       <li><a href="https://github.com/JetBrains/ideavim/pull/550">550</a> by <a href="https://github.com/citizenmatt">Matt |       <li><a href="https://github.com/JetBrains/ideavim/pull/558">558</a> by <a href="https://github.com/citizenmatt">Matt | ||||||
|         Ellis</a>: Fix(VIM-2778) Remove override of editor scroll setting |         Ellis</a>: Fix incorrect normalising for trailing inlay | ||||||
|  |       </li> | ||||||
|  |       <li><a href="https://github.com/JetBrains/ideavim/pull/554">554</a> by <a href="https://github.com/citizenmatt">Matt | ||||||
|  |         Ellis</a>: Refactor "last column" calculations | ||||||
|  |       </li> | ||||||
|  |       <li><a href="https://github.com/JetBrains/ideavim/pull/553">553</a> by <a href="https://github.com/citizenmatt">Matt | ||||||
|  |         Ellis</a>: Rearrange and rename some code in engine | ||||||
|  |       </li> | ||||||
|  |       <li><a href="https://github.com/JetBrains/ideavim/pull/560">560</a> by <a | ||||||
|  |           href="https://github.com/Runinho">Runinho</a>: Fix(VIM-2577) paste not working at end of notebook cell | ||||||
|  |       </li> | ||||||
|  |       <li><a href="https://github.com/JetBrains/ideavim/pull/571">571</a> by <a href="https://github.com/adaext">Ada</a>: | ||||||
|  |         Remove the redundant quotation mark at the end of "packadd matchit" command | ||||||
|       </li> |       </li> | ||||||
|     </ul> |     </ul> | ||||||
|     ]]> |     ]]> | ||||||
| @@ -50,7 +46,7 @@ | |||||||
|         <li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li> |         <li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li> | ||||||
|       </ul> |       </ul> | ||||||
|     ]]></description> |     ]]></description> | ||||||
|   <version>SNAPSHOT</version> |   <version>chylex</version> | ||||||
|   <vendor>JetBrains</vendor> |   <vendor>JetBrains</vendor> | ||||||
|  |  | ||||||
|   <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version --> |   <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version --> | ||||||
|   | |||||||
| @@ -80,6 +80,28 @@ class MotionLastColumnActionTest : VimTestCase() { | |||||||
|     doTest(keys, before, after, VimStateMachine.Mode.VISUAL, VimStateMachine.SubMode.VISUAL_BLOCK) |     doTest(keys, before, after, VimStateMachine.Mode.VISUAL, VimStateMachine.SubMode.VISUAL_BLOCK) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   fun `test dollar motion resets intended location after motion`() { | ||||||
|  |     doTest( | ||||||
|  |       "\$hlj", | ||||||
|  |       """ | ||||||
|  |           A Discovery | ||||||
|  |  | ||||||
|  |           I ${c}found it in a legendary land | ||||||
|  |           all rocks and lavender and tufted grass,[ additional symbols] | ||||||
|  |           where it was settled on some sodden sand | ||||||
|  |           hard by the torrent of a mountain pass. | ||||||
|  |       """.trimIndent(), | ||||||
|  |       """ | ||||||
|  |           A Discovery | ||||||
|  |  | ||||||
|  |           I found it in a legendary land | ||||||
|  |           all rocks and lavender and tu${c}fted grass,[ additional symbols] | ||||||
|  |           where it was settled on some sodden sand | ||||||
|  |           hard by the torrent of a mountain pass. | ||||||
|  |       """.trimIndent() | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @VimBehaviorDiffers( |   @VimBehaviorDiffers( | ||||||
|     originalVimAfter = """ |     originalVimAfter = """ | ||||||
|             A Discovery |             A Discovery | ||||||
|   | |||||||
| @@ -213,7 +213,7 @@ class KeyHandler { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * See the description for [com.maddyhome.idea.vim.action.DuplicableOperatorAction] |    * See the description for [com.maddyhome.idea.vim.command.DuplicableOperatorAction] | ||||||
|    */ |    */ | ||||||
|   private fun mapOpCommand( |   private fun mapOpCommand( | ||||||
|     key: KeyStroke, |     key: KeyStroke, | ||||||
|   | |||||||
| @@ -176,7 +176,8 @@ abstract class VimChangeGroupBase : VimChangeGroup { | |||||||
|       val startOffsets = updatedRange.startOffsets |       val startOffsets = updatedRange.startOffsets | ||||||
|       val endOffsets = updatedRange.endOffsets |       val endOffsets = updatedRange.endOffsets | ||||||
|       for (i in updatedRange.size() - 1 downTo 0) { |       for (i in updatedRange.size() - 1 downTo 0) { | ||||||
|         editor.deleteString(TextRange(startOffsets[i], endOffsets[i])) |         val (newRange, _) = editor.search(startOffsets[i].offset to endOffsets[i].offset, editor, LineDeleteShift.NL_ON_END) ?: continue | ||||||
|  |         editor.deleteString(TextRange(newRange.first.point, newRange.second.point)) | ||||||
|       } |       } | ||||||
|       if (type != null) { |       if (type != null) { | ||||||
|         val start = updatedRange.startOffset |         val start = updatedRange.startOffset | ||||||
|   | |||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | package com.maddyhome.idea.vim.option | ||||||
|  |  | ||||||
|  | import com.maddyhome.idea.vim.api.injector | ||||||
|  | import com.maddyhome.idea.vim.options.OptionConstants | ||||||
|  | import com.maddyhome.idea.vim.options.OptionScope | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Deprecated("Please use StrictMode from com.maddyhome.idea.vim.options.helpers", replaceWith = ReplaceWith("com.maddyhome.idea.vim.options.helpers.StrictMode")) | ||||||
|  | object StrictMode { | ||||||
|  |   @JvmName("assertTrue") | ||||||
|  |   fun assert(condition: Boolean, message: String) { | ||||||
|  |     if (!condition) { | ||||||
|  |       fail(message) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   fun fail(message: String) { | ||||||
|  |     if (injector.optionService.isSet(OptionScope.GLOBAL, OptionConstants.ideastrictmodeName)) { | ||||||
|  |       error(message) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user