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