1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-08-17 16:31:45 +02:00

Compare commits

...

43 Commits

Author SHA1 Message Date
Alex Plate
cdf7fd8ce6 Update markdown to slack version 2020-11-03 12:14:58 +03:00
Alex Plate
8fe07e7b20 Verify plugin only against last major versions of IJ 2020-11-03 11:26:32 +03:00
Alex Plate
b800237606 Refactor common extension test 2020-11-03 11:24:34 +03:00
Alex Plate
fed02e5b8a Update plugin.xml 2020-11-03 11:20:22 +03:00
Alex Plate
2d4d3e9410 Update markdown to slack parser version 2020-11-03 11:20:21 +03:00
Alex Pláte
880d4c6888 Update CONTRIBUTING.md 2020-11-02 14:16:44 +03:00
Alex Plate
6a3d606032 New extension registration process
The new process gives as lazy loading of extension classes
2020-11-01 03:30:00 +03:00
Alex Plate
612a86c4d9 Add new option to enable extensions 2020-11-01 00:51:22 +03:00
Alex Plate
14abc25c01 Update detekt config 2020-11-01 00:47:05 +03:00
Alex Plate
52673d1a02 Remove unnecessary semicolon 2020-10-31 22:04:20 +03:00
Alex Plate
b7caee119e Rename detekt folder 2020-10-31 21:44:53 +03:00
Alex Plate
a148446912 Change order of checks 2020-10-31 19:43:19 +03:00
Alex Plate
1ee9075976 Inline findParentByCondition 2020-10-31 19:40:48 +03:00
Alex Plate
b03627a110 Add info about prepared configurations to contributing guide 2020-10-31 19:27:06 +03:00
Alex Plate
04ac0ab743 [TC] Extract plugin verification into the separate build 2020-10-31 19:21:12 +03:00
Alex Plate
e7aa985ad5 Add run configurations 2020-10-31 18:49:37 +03:00
Alex Plate
4177f4e4f3 Rename ideavim.neovim.test to ideavim.nvim.test 2020-10-31 18:44:53 +03:00
Alex Plate
c1e415b76a [TC] Update nvim config 2020-10-31 18:44:16 +03:00
Alex Plate
8ae656dee3 Remove unused export 2020-10-31 18:42:35 +03:00
aleksei.plate
d48576f48a TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: parameters of 'NVIM' build configuration were updated 2020-10-31 15:42:17 +00:00
Alex Plate
c0c5075072 [TC] Use -P to set env var 2020-10-31 18:16:41 +03:00
Alex Plate
59d106b8c4 [TC] Update nvim config 2020-10-31 17:42:58 +03:00
Alex Plate
d96c313ecb [TC] Add execution privilege to nvim 2020-10-31 17:12:22 +03:00
Alex Plate
212c708150 [TC] Use env variable to set nvim path 2020-10-31 17:00:16 +03:00
Alex Plate
3739eb173e Remove nvim branch 2020-10-31 16:54:56 +03:00
Alex Plate
0d3ecce8a2 Read env variable to get nvim path 2020-10-31 16:53:09 +03:00
Alex Plate
164d7a4200 [TC] Update nvim config 2020-10-31 16:45:18 +03:00
Alex Plate
1258e602e6 [TC] Reformat code 2020-10-31 16:38:06 +03:00
Alex Plate
8a5ad713ea Trying to setup neovim tests 2020-10-31 16:29:34 +03:00
Alex Plate
12be65fa09 Update teamcity config: refactoring 2020-10-31 16:00:35 +03:00
Alex Plate
0720431c91 More cleanup 2020-10-31 14:29:26 +03:00
Alex Plate
6f1ac1de97 Add more time checks for is db cell 2020-10-31 14:03:11 +03:00
Alex Plate
99d2d4b594 Update the color of yank highlighting after laf changing 2020-10-31 13:46:08 +03:00
Alex Plate
2bf9b97e49 Continuation of qodana cleanup 2020-10-31 13:11:13 +03:00
Alex Plate
c6600f3348 Fixes base of qodana run 2020-10-30 19:54:26 +03:00
Alex Plate
e29ab54b0e Make default register in RegisterGroup non static field 2020-10-30 19:18:46 +03:00
Alex Plate
197565d4cb Get rid of info logs 2020-10-30 16:47:44 +03:00
Alex Plate
3d570d2020 Make property private 2020-10-30 15:59:56 +03:00
Alex Plate
fe364dc6dc Reduce the depth of "parentByCondition" function 2020-10-30 11:56:50 +03:00
Alex Plate
5d0e82781f Enable teamcity output format for plugin verifier 2020-10-30 11:37:36 +03:00
Alex Plate
24f005a340 Integrate plugin verifier to the project 2020-10-30 11:08:49 +03:00
Alex Plate
1743c08091 Update isIdeaVimdisableHere logging 2020-10-29 12:40:30 +03:00
Alex Plate
81b095c899 Update detekt configuration 2020-10-29 11:43:47 +03:00
92 changed files with 1123 additions and 724 deletions

View File

@@ -1,23 +1,18 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<SmellBaseline> <SmellBaseline>
<ManuallySuppressedIssues></ManuallySuppressedIssues> <ManuallySuppressedIssues>
<CurrentIssues>
<ID>ComplexMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID> <ID>ComplexMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID>
<ID>ComplexMethod:CommandHandler.kt$CommandHandler$ @Throws(ExException::class) fun process(editor: Editor, context: DataContext, cmd: ExCommand, count: Int): Boolean</ID>
<ID>ComplexMethod:CommandState.kt$CommandState$ fun toVimNotation(): String</ID> <ID>ComplexMethod:CommandState.kt$CommandState$ fun toVimNotation(): String</ID>
<ID>ComplexMethod:CommandState.kt$CommandState$private fun getStatusString(pos: Int): String</ID> </ManuallySuppressedIssues>
<CurrentIssues>
<ID>ComplexMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID> <ID>ComplexMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ComplexMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID> <ID>ComplexMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
<ID>ComplexMethod:OptionsManager.kt$OptionsManager$ private fun showOptions(editor: Editor?, opts: Collection&lt;Option&lt;*&gt;&gt;, showIntro: Boolean)</ID>
<ID>ComplexMethod:PutGroup.kt$PutGroup$private fun moveCaretToEndPosition( editor: Editor, caret: Caret, startOffset: Int, endOffset: Int, typeInRegister: SelectionType, modeInEditor: CommandState.SubMode, caretAfterInsertedText: Boolean )</ID>
<ID>ComplexMethod:PutGroup.kt$PutGroup$private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map&lt;String, Any&gt;): List&lt;Int&gt;</ID> <ID>ComplexMethod:PutGroup.kt$PutGroup$private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map&lt;String, Any&gt;): List&lt;Int&gt;</ID>
<ID>ComplexMethod:SearchHelperKt.kt$// bounds are considered inside corresponding quotes fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean</ID> <ID>ComplexMethod:SearchHelperKt.kt$// bounds are considered inside corresponding quotes fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean</ID>
<ID>ComplexMethod:TabCloseHandler.kt$TabCloseHandler$ private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int?</ID> <ID>ComplexMethod:TabCloseHandler.kt$TabCloseHandler$ private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int?</ID>
<ID>ComplexMethod:VimExchangeExtension.kt$VimExchangeExtension.Operator$private fun compareExchanges(x: Exchange, y: Exchange): ExchangeCompareResult</ID> <ID>ComplexMethod:VimExchangeExtension.kt$VimExchangeExtension.Operator$private fun compareExchanges(x: Exchange, y: Exchange): ExchangeCompareResult</ID>
<ID>ComplexMethod:VimExtensionFacade.kt$VimExtensionFacade$ @JvmStatic fun inputString(editor: Editor, prompt: String, finishOn: Char?): String</ID>
<ID>ComplexMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID> <ID>ComplexMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
<ID>ComplexMethod:VimShortcutKeyAction.kt$VimShortcutKeyAction$private fun isEnabled(e: AnActionEvent): Boolean</ID> <ID>ComplexMethod:VimShortcutKeyAction.kt$VimShortcutKeyAction$private fun isEnabled(e: AnActionEvent): Boolean</ID>
<ID>ComplexMethod:VisualGroup.kt$private fun setVisualSelection(selectionStart: Int, selectionEnd: Int, caret: Caret)</ID>
<ID>LongMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID> <ID>LongMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID>
<ID>LongMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID> <ID>LongMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>LongMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID> <ID>LongMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
@@ -140,7 +135,7 @@
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$private fun seemsLikeBlockMode(editor: Editor): Boolean</ID> <ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$private fun seemsLikeBlockMode(editor: Editor): Boolean</ID>
<ID>ReturnCount:VisualOperatorActionHandler.kt$VisualOperatorActionHandler$final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean</ID> <ID>ReturnCount:VisualOperatorActionHandler.kt$VisualOperatorActionHandler$final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:YankGroup.kt$YankGroup$ fun yankMotion(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument): Boolean</ID> <ID>ReturnCount:YankGroup.kt$YankGroup$ fun yankMotion(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument): Boolean</ID>
<ID>ThrowsCount:CommandHandler.kt$CommandHandler$ @Throws(ExException::class) fun process(editor: Editor, context: DataContext, cmd: ExCommand, count: Int): Boolean</ID> <ID>ThrowsCount:CommandHandler.kt$CommandHandler$private fun checkArgs(cmd: ExCommand)</ID>
<ID>TooManyFunctions:CommandBuilder.kt$CommandBuilder</ID> <ID>TooManyFunctions:CommandBuilder.kt$CommandBuilder</ID>
<ID>TooManyFunctions:CommandState.kt$CommandState</ID> <ID>TooManyFunctions:CommandState.kt$CommandState</ID>
<ID>TooManyFunctions:PutGroup.kt$PutGroup</ID> <ID>TooManyFunctions:PutGroup.kt$PutGroup</ID>

View File

@@ -11,6 +11,8 @@ complexity:
threshold: 6 threshold: 6
ComplexCondition: ComplexCondition:
threshold: 6 threshold: 6
ComplexMethod:
threshold: 20
exceptions: exceptions:
TooGenericExceptionCaught: TooGenericExceptionCaught:
active: false active: false
@@ -25,3 +27,5 @@ style:
active: false active: false
MaxLineLength: MaxLineLength:
maxLineLength: 160 maxLineLength: 160
ReturnCount:
max: 5

View File

@@ -0,0 +1,24 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IdeaVim full verification" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="check" />
<option value="runPluginVerifier" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IdeaVim tests" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start IJ with IdeaVim" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,7 +1,23 @@
package _Self package _Self
import _Self.buildTypes.* import _Self.buildTypes.GitHubPullRequests
import _Self.vcsRoots.* import _Self.buildTypes.Nvim
import _Self.buildTypes.PluginVerifier
import _Self.buildTypes.Release
import _Self.buildTypes.ReleaseEap
import _Self.buildTypes.TestsForIntelliJ20181
import _Self.buildTypes.TestsForIntelliJ20182
import _Self.buildTypes.TestsForIntelliJ20183
import _Self.buildTypes.TestsForIntelliJ20191
import _Self.buildTypes.TestsForIntelliJ20192
import _Self.buildTypes.TestsForIntelliJ20193
import _Self.buildTypes.TestsForIntelliJ20201
import _Self.buildTypes.TestsForIntelliJ20202
import _Self.buildTypes.TestsForIntelliJEAP
import _Self.vcsRoots.Branch_181
import _Self.vcsRoots.Branch_183
import _Self.vcsRoots.Branch_191_193
import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.Project import jetbrains.buildServer.configs.kotlin.v2019_2.Project
object Project : Project({ object Project : Project({
@@ -11,7 +27,6 @@ object Project : Project({
vcsRoot(Branch_181) vcsRoot(Branch_181)
vcsRoot(GitHubPullRequest) vcsRoot(GitHubPullRequest)
vcsRoot(Branch_191_193) vcsRoot(Branch_191_193)
vcsRoot(Branch_Nvim)
buildType(GitHubPullRequests) buildType(GitHubPullRequests)
buildType(Release) buildType(Release)
@@ -22,10 +37,11 @@ object Project : Project({
buildType(TestsForIntelliJ20182) buildType(TestsForIntelliJ20182)
buildType(TestsForIntelliJ20193) buildType(TestsForIntelliJ20193)
buildType(TestsForIntelliJ20183) buildType(TestsForIntelliJ20183)
// buildType(Nvim) buildType(Nvim)
buildType(ReleaseEap) buildType(ReleaseEap)
buildType(TestsForIntelliJ20202) buildType(TestsForIntelliJ20202)
buildType(TestsForIntelliJEAP) buildType(TestsForIntelliJEAP)
buildType(PluginVerifier)
features { features {
feature { feature {

View File

@@ -1,7 +1,8 @@
package _Self.buildTypes package _Self.buildTypes
import _Self.vcsRoots.GitHubPullRequest import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.PullRequests import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.PullRequests
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.commitStatusPublisher import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.pullRequests import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.pullRequests

View File

@@ -2,36 +2,40 @@ package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object Nvim : BuildType({ object Nvim : BuildType({
name = "NVIM" name = "Tests with nvim"
description = "branch EAP" description = "Running tests with nvim integration"
params { params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "LATEST-EAP-SNAPSHOT") param("env.ORG_GRADLE_PROJECT_ideaVersion", "LATEST-EAP-SNAPSHOT")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ideavim.nvim.path", "./nvim-linux64/bin/nvim")
} }
vcs { vcs {
root(_Self.vcsRoots.Branch_Nvim) root(DslContext.settingsRoot)
checkoutMode = CheckoutMode.ON_SERVER checkoutMode = CheckoutMode.ON_SERVER
} }
steps { steps {
script { script {
scriptContent = "apt-get install neovim" name = "Set up NeoVim"
scriptContent = """
wget https://github.com/neovim/neovim/releases/download/v0.4.4/nvim-linux64.tar.gz
tar xzf nvim-linux64.tar.gz
cd nvim-linux64/bin
chmod +x nvim
""".trimIndent()
} }
gradle { gradle {
tasks = "--version" tasks = "clean testWithNeovim"
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
gradle {
tasks = "clean test"
buildFile = "" buildFile = ""
enableStacktrace = true enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")

View File

@@ -0,0 +1,40 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object PluginVerifier : BuildType({
name = "Plugin verification"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
}
vcs {
root(DslContext.settingsRoot)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean runPluginVerifier"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -1,6 +1,8 @@
package _Self.buildTypes package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
object Release : BuildType({ object Release : BuildType({
@@ -12,7 +14,11 @@ object Release : BuildType({
params { params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
password("env.ORG_GRADLE_PROJECT_publishToken", "credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4", label = "Password") password(
"env.ORG_GRADLE_PROJECT_publishToken",
"credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4",
label = "Password"
)
param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan") param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan")
param("env.ORG_GRADLE_PROJECT_version", "%build.number%") param("env.ORG_GRADLE_PROJECT_version", "%build.number%")
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")

View File

@@ -17,12 +17,20 @@ object ReleaseEap : BuildType({
params { params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
password("env.ORG_GRADLE_PROJECT_publishToken", "credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4", label = "Token") password(
"env.ORG_GRADLE_PROJECT_publishToken",
"credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4",
label = "Token"
)
param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan") param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan")
param("env.ORG_GRADLE_PROJECT_version", "%build.number%") param("env.ORG_GRADLE_PROJECT_version", "%build.number%")
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_publishChannels", "eap") param("env.ORG_GRADLE_PROJECT_publishChannels", "eap")
password("env.ORG_GRADLE_PROJECT_slackUrl", "credentialsJSON:a8ab8150-e6f8-4eaf-987c-bcd65eac50b5", label = "Slack Token") password(
"env.ORG_GRADLE_PROJECT_slackUrl",
"credentialsJSON:a8ab8150-e6f8-4eaf-987c-bcd65eac50b5",
label = "Slack Token"
)
} }
vcs { vcs {

View File

@@ -1,42 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object TestsForIntelliJ20181 : BuildType({
name = "Tests for IntelliJ 2018.1"
description = "branch 181"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2018.1")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_181)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -1,42 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object TestsForIntelliJ20182 : BuildType({
name = "Tests for IntelliJ 2018.2"
description = "branch 182"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2018.2")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_181)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -1,6 +1,7 @@
package _Self.buildTypes package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs

View File

@@ -1,43 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object TestsForIntelliJ20191 : BuildType({
name = "Tests for IntelliJ 2019.1"
description = "branch 191"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2019.1")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_191_193)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -1,43 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object TestsForIntelliJ20192 : BuildType({
name = "Tests for IntelliJ 2019.2"
description = "branch 192"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2019.2")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_191_193)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -1,43 +0,0 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object TestsForIntelliJ20193 : BuildType({
name = "Tests for IntelliJ 2019.3"
description = "branch 193"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2019.3")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_191_193)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})

View File

@@ -0,0 +1,47 @@
@file:Suppress("ClassName")
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
sealed class TestsForIntelliJ_181_branch(private val version: String) : BuildType({
name = "Tests for IntelliJ $version"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-$version")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_181)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})
object TestsForIntelliJ20181 : TestsForIntelliJ_181_branch("2018.1")
object TestsForIntelliJ20182 : TestsForIntelliJ_181_branch("2018.2")

View File

@@ -0,0 +1,49 @@
@file:Suppress("ClassName")
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
sealed class TestsForIntelliJ_191_193_branch(private val version: String) : BuildType({
name = "Tests for IntelliJ $version"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-$version")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_191_193)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})
object TestsForIntelliJ20191 : TestsForIntelliJ_191_193_branch("2019.1")
object TestsForIntelliJ20192 : TestsForIntelliJ_191_193_branch("2019.2")
object TestsForIntelliJ20193 : TestsForIntelliJ_191_193_branch("2019.3")

View File

@@ -1,11 +0,0 @@
@file:Suppress("ClassName")
package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_Nvim : GitVcsRoot({
name = "https://github.com/JetBrains/ideavim (branch nvim)"
url = "https://github.com/JetBrains/ideavim.git"
branch = "neovim"
})

View File

@@ -29,11 +29,21 @@ usual beta standards.
Check out `README.md` for the details. Check out `README.md` for the details.
* `IdeaVim: track action Ids` command to find action ids for the `:action` command. * `IdeaVim: track action Ids` command to find action ids for the `:action` command.
Enable this option in "Search everywhere" (double shift). Enable this option in "Search everywhere" (double shift).
* Ability to enable extensions using `vim-plug` or `vundle` syntax.
E.g. to enable commentary extension you can use one of the following commands:
```vim
set commentary
Plug 'tpope/vim-commentary'
Plug 'https://github.com/tpope/vim-commentary'
Plugin 'tpope/vim-commentary'
...
```
This approach is especially handy if you have `.vimrc` with plugins registered via `vim-plug` or `vundle`.
### Changes: ### Changes:
* Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode. * Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode.
* Add option to disable IdeaVim * Add option to disable IdeaVim in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors. Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors.
_Note for EAP users: the option name can be changed for the stable release_ _Note for EAP users: the option name can be changed for the stable release_

View File

@@ -26,7 +26,12 @@ OK, ready to do some coding?
* Fork the repository and clone it to the local machine. * Fork the repository and clone it to the local machine.
* Open the project with IntelliJ IDEA. * Open the project with IntelliJ IDEA.
Yoo hoo! Youre all set to begin contributing. Here are some useful gradle commands: Yoo hoo! Youre all set to begin contributing.
We've prepared some useful configurations for you:
![Prepared configurations](resources/contributing/configurations.png)
And here are useful gradle commands:
* `./gradlew runIde` — start the dev version of IntelliJ IDEA with IdeaVim installed. * `./gradlew runIde` — start the dev version of IntelliJ IDEA with IdeaVim installed.
* `./gradlew test` — run tests. * `./gradlew test` — run tests.
@@ -136,5 +141,5 @@ This is just terrible. [You know what to do](https://github.com/JetBrains/ideavi
* [Changelog](CHANGES.md) * [Changelog](CHANGES.md)
* [Contributors listing](AUTHORS.md) * [Contributors listing](AUTHORS.md)
[teamcity-build-status]: https://teamcity.jetbrains.com/viewType.html?buildTypeId=IdeaVim_TestsForIntelliJ20201&guest=1 [teamcity-build-status]: https://teamcity.jetbrains.com/viewType.html?buildTypeId=IdeaVim_TestsForIntelliJEAP&guest=1
[teamcity-build-status-svg]: https://teamcity.jetbrains.com/app/rest/builds/buildType:(id:IdeaVim_TestsForIntelliJ20201)/statusIcon.svg?guest=1 [teamcity-build-status-svg]: https://teamcity.jetbrains.com/app/rest/builds/buildType:(id:IdeaVim_TestsForIntelliJEAP)/statusIcon.svg?guest=1

View File

@@ -8,12 +8,12 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.github.AlexPl292:mark-down-to-slack:1.0.1" classpath "com.github.AlexPl292:mark-down-to-slack:1.1.2"
} }
} }
plugins { plugins {
id 'org.jetbrains.intellij' version '0.5.0' id 'org.jetbrains.intellij' version '0.6.1'
id 'io.gitlab.arturbosch.detekt' version '1.14.1' id 'io.gitlab.arturbosch.detekt' version '1.14.1'
id "org.jetbrains.changelog" version "0.6.2" id "org.jetbrains.changelog" version "0.6.2"
} }
@@ -52,6 +52,12 @@ intellij {
} }
} }
runPluginVerifier {
ideVersions = ["IC-2020.1.4", "IC-2020.2.3"]
downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
teamCityOutputFormat = true
}
repositories { repositories {
mavenCentral() mavenCentral()
jcenter() jcenter()
@@ -77,8 +83,8 @@ compileTestKotlin {
} }
detekt { detekt {
config = files("./detekt/config.yaml") config = files("${rootProject.projectDir}/.detekt/config.yaml")
baseline = file("${rootProject.projectDir}/detekt/baseline.xml") baseline = file("${rootProject.projectDir}/.detekt/baseline.xml")
input = files("src") input = files("src")
buildUponDefaultConfig = true buildUponDefaultConfig = true
@@ -94,7 +100,7 @@ tasks.detekt.jvmTarget = javaVersion
task testWithNeovim(type: Test) { task testWithNeovim(type: Test) {
group = "verification" group = "verification"
systemProperty "ideavim.neovim.test", 'true' systemProperty "ideavim.nvim.test", 'true'
} }
changelog { changelog {
@@ -112,7 +118,7 @@ tasks.register("slackEapNotification") {
if (!slackUrl) return if (!slackUrl) return
def post = new URL(slackUrl).openConnection() def post = new URL(slackUrl).openConnection()
def changeLog = changelog.getUnreleased().toText() def changeLog = changelog.getUnreleased().toText()
def slackDown = new DownParser(changeLog).toSlack().toString() def slackDown = new DownParser(changeLog, true).toSlack().toString()
def message = """ def message = """
{ {
"text": "New version of IdeaVim", "text": "New version of IdeaVim",

View File

@@ -64,5 +64,6 @@
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.TabCloseHandler" names="tabc[lose]"/> <vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.TabCloseHandler" names="tabc[lose]"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.BufferListHandler" names="buffers,ls,files"/> <vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.BufferListHandler" names="buffers,ls,files"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.BufferHandler" names="b[uffer]"/> <vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.BufferHandler" names="b[uffer]"/>
<vimExCommand implementation="com.maddyhome.idea.vim.ex.handler.PlugHandler" names="Plug[in]"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@@ -1,12 +1,84 @@
<idea-plugin> <idea-plugin>
<extensions defaultExtensionNs="IdeaVIM"> <extensions defaultExtensionNs="IdeaVIM">
<vimExtension implementation="com.maddyhome.idea.vim.extension.surround.VimSurroundExtension"/> <vimExtension implementation="com.maddyhome.idea.vim.extension.surround.VimSurroundExtension" name="surround">
<vimExtension implementation="com.maddyhome.idea.vim.extension.multiplecursors.VimMultipleCursorsExtension"/> <aliases>
<vimExtension implementation="com.maddyhome.idea.vim.extension.commentary.CommentaryExtension"/> <alias name="https://github.com/tpope/vim-surround"/>
<vimExtension implementation="com.maddyhome.idea.vim.extension.textobjentire.VimTextObjEntireExtension"/> <alias name="tpope/vim-surround"/>
<vimExtension implementation="com.maddyhome.idea.vim.extension.argtextobj.VimArgTextObjExtension"/> <alias name="vim-surround"/>
<vimExtension implementation="com.maddyhome.idea.vim.extension.replacewithregister.ReplaceWithRegister"/> <alias name="https://www.vim.org/scripts/script.php?script_id=1697"/>
<vimExtension implementation="com.maddyhome.idea.vim.extension.exchange.VimExchangeExtension"/> </aliases>
<vimExtension implementation="com.maddyhome.idea.vim.extension.highlightedyank.VimHighlightedYank"/> </vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.multiplecursors.VimMultipleCursorsExtension"
name="multiple-cursors">
<aliases>
<alias name="https://github.com/terryma/vim-multiple-cursors"/>
<alias name="terryma/vim-multiple-cursors"/>
<alias name="vim-multiple-cursors"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.commentary.CommentaryExtension" name="commentary">
<aliases>
<alias name="https://github.com/tpope/vim-commentary"/>
<alias name="tpope/vim-commentary"/>
<alias name="vim-commentary"/>
<alias name="https://www.vim.org/scripts/script.php?script_id=3695"/>
<alias name="https://github.com/tomtom/tcomment_vim"/>
<alias name="tomtom/tcomment_vim"/>
<alias name="tcomment_vim"/>
<alias name="https://www.vim.org/scripts/script.php?script_id=1173"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.textobjentire.VimTextObjEntireExtension"
name="textobj-entire">
<aliases>
<alias name="https://github.com/kana/vim-textobj-entire"/>
<alias name="kana/vim-textobj-entire"/>
<alias name="vim-textobj-entire"/>
<alias name="https://www.vim.org/scripts/script.php?script_id=2610"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.argtextobj.VimArgTextObjExtension"
name="argtextobj">
<aliases>
<alias name="https://github.com/vim-scripts/argtextobj.vim"/>
<alias name="vim-scripts/argtextobj.vim"/>
<alias name="argtextobj.vim"/>
<alias name="https://www.vim.org/scripts/script.php?script_id=2699"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.replacewithregister.ReplaceWithRegister"
name="ReplaceWithRegister">
<aliases>
<alias name="https://github.com/vim-scripts/ReplaceWithRegister"/>
<alias name="vim-scripts/ReplaceWithRegister"/>
<alias name="ReplaceWithRegister"/>
<alias name="https://github.com/inkarkat/vim-ReplaceWithRegister"/>
<alias name="inkarkat/vim-ReplaceWithRegister"/>
<alias name="vim-ReplaceWithRegister"/>
<alias name="https://www.vim.org/scripts/script.php?script_id=2703"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.exchange.VimExchangeExtension" name="exchange">
<aliases>
<alias name="https://github.com/tommcdo/vim-exchange"/>
<alias name="tommcdo/vim-exchange"/>
<alias name="vim-exchange"/>
</aliases>
</vimExtension>
<vimExtension implementation="com.maddyhome.idea.vim.extension.highlightedyank.VimHighlightedYank"
name="highlightedyank">
<aliases>
<alias name="https://github.com/machakann/vim-highlightedyank"/>
<alias name="machakann/vim-highlightedyank"/>
<alias name="vim-highlightedyank"/>
</aliases>
</vimExtension>
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@@ -2,6 +2,8 @@
<applicationListeners> <applicationListeners>
<listener class="com.maddyhome.idea.vim.ui.ExEntryPanel$LafListener" <listener class="com.maddyhome.idea.vim.ui.ExEntryPanel$LafListener"
topic="com.intellij.ide.ui.LafManagerListener"/> topic="com.intellij.ide.ui.LafManagerListener"/>
<listener class="com.maddyhome.idea.vim.extension.highlightedyank.HighlightColorResetter"
topic="com.intellij.ide.ui.LafManagerListener"/>
</applicationListeners> </applicationListeners>
<projectListeners> <projectListeners>
<listener class="com.maddyhome.idea.vim.ui.ExOutputPanel$LafListener" <listener class="com.maddyhome.idea.vim.ui.ExOutputPanel$LafListener"

View File

@@ -7,7 +7,7 @@
<li>Add option to disable IdeaVim in dialogs and single line editors</li> <li>Add option to disable IdeaVim in dialogs and single line editors</li>
<li>Ability to map IDE actions via the &lt;Action&gt; keyword.</li> <li>Ability to map IDE actions via the &lt;Action&gt; keyword.</li>
<li>"IdeaVim: track action Ids" command to find action ids for the :action command. <li>"IdeaVim: track action Ids" command to find action ids for the :action command.
Enable this option in &quot;Search everywhere&quot; (double shift).</li> <li>Add new option to register IdeaVim extensions. Please read the changelog for details</li>
</ul> </ul>
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p> <p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
]]></change-notes> ]]></change-notes>
@@ -38,7 +38,10 @@
</application-components> </application-components>
<extensionPoints> <extensionPoints>
<extensionPoint name="vimExtension" interface="com.maddyhome.idea.vim.extension.VimExtension" dynamic="true"/> <extensionPoint name="vimExtension" beanClass="com.maddyhome.idea.vim.extension.ExtensionBeanClass" dynamic="true">
<with attribute="implementation" implements="com.maddyhome.idea.vim.extension.VimExtension"/>
</extensionPoint>
<!-- For internal use only --> <!-- For internal use only -->
<extensionPoint name="vimExCommand" beanClass="com.maddyhome.idea.vim.ex.ExBeanClass" dynamic="true"> <extensionPoint name="vimExCommand" beanClass="com.maddyhome.idea.vim.ex.ExBeanClass" dynamic="true">

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -24,10 +24,7 @@ import com.intellij.notification.NotificationListener;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application; import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.*;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.Keymap;

View File

@@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
sealed class IncNumber(val inc: Int, val avalanche: Boolean) : VisualOperatorActionHandler.ForEachCaret() { sealed class IncNumber(val inc: Int, private val avalanche: Boolean) : VisualOperatorActionHandler.ForEachCaret() {
override val type: Command.Type = Command.Type.CHANGE override val type: Command.Type = Command.Type.CHANGE
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_EXIT_VISUAL) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_EXIT_VISUAL)

View File

@@ -10,7 +10,7 @@ import javax.swing.KeyStroke
class InsertCompletedDigraphAction : VimActionHandler.SingleExecution() { class InsertCompletedDigraphAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.INSERT override val type: Command.Type = Command.Type.INSERT
override val argumentType: Argument.Type? = Argument.Type.DIGRAPH override val argumentType: Argument.Type = Argument.Type.DIGRAPH
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean { override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
// The converted digraph character has been captured as an argument, push it back through key handler // The converted digraph character has been captured as an argument, push it back through key handler

View File

@@ -10,7 +10,7 @@ import javax.swing.KeyStroke
class InsertCompletedLiteralAction : VimActionHandler.SingleExecution() { class InsertCompletedLiteralAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.INSERT override val type: Command.Type = Command.Type.INSERT
override val argumentType: Argument.Type? = Argument.Type.DIGRAPH override val argumentType: Argument.Type = Argument.Type.DIGRAPH
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean { override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
// The converted literal character has been captured as an argument, push it back through key handler // The converted literal character has been captured as an argument, push it back through key handler

View File

@@ -37,7 +37,7 @@ class MotionInnerSentenceAction : TextObjectActionHandler() {
override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? { override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange {
return VimPlugin.getMotion().getSentenceRange(editor, caret, count, false) return VimPlugin.getMotion().getSentenceRange(editor, caret, count, false)
} }
} }

View File

@@ -31,7 +31,7 @@ class MotionInnerWordAction : TextObjectActionHandler() {
override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? { override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange {
return VimPlugin.getMotion().getWordRange(editor, caret, count, false, false) return VimPlugin.getMotion().getWordRange(editor, caret, count, false, false)
} }
} }

View File

@@ -32,7 +32,7 @@ class MotionOuterBigWordAction : TextObjectActionHandler() {
override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? { override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange {
return VimPlugin.getMotion().getWordRange(editor, caret, count, true, true) return VimPlugin.getMotion().getWordRange(editor, caret, count, true, true)
} }
} }

View File

@@ -37,7 +37,7 @@ class MotionOuterSentenceAction : TextObjectActionHandler() {
override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? { override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange {
return VimPlugin.getMotion().getSentenceRange(editor, caret, count, true) return VimPlugin.getMotion().getSentenceRange(editor, caret, count, true)
} }
} }

View File

@@ -32,7 +32,7 @@ class MotionOuterWordAction : TextObjectActionHandler() {
override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? { override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange {
return VimPlugin.getMotion().getWordRange(editor, caret, count, true, false) return VimPlugin.getMotion().getWordRange(editor, caret, count, true, false)
} }
} }

View File

@@ -42,12 +42,12 @@ class SelectMotionLeftAction : MotionActionHandler.ForEachCaret() {
override fun getOffset(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Int { override fun getOffset(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Int {
val keymodel = OptionsManager.keymodel val keymodel = OptionsManager.keymodel
if (KeyModelOptionData.stopsel in keymodel || KeyModelOptionData.stopselect in keymodel) { if (KeyModelOptionData.stopsel in keymodel || KeyModelOptionData.stopselect in keymodel) {
logger.info("Keymodel option has stopselect. Exiting select mode") logger.debug("Keymodel option has stopselect. Exiting select mode")
val startSelection = caret.selectionStart val startSelection = caret.selectionStart
val endSelection = caret.selectionEnd val endSelection = caret.selectionEnd
editor.exitSelectMode(false) editor.exitSelectMode(false)
if (editor.isTemplateActive()) { if (editor.isTemplateActive()) {
logger.info("Template is active. Activate insert mode") logger.debug("Template is active. Activate insert mode")
VimPlugin.getChange().insertBeforeCursor(editor, context) VimPlugin.getChange().insertBeforeCursor(editor, context)
if (caret.offset in startSelection..endSelection) { if (caret.offset in startSelection..endSelection) {
return startSelection return startSelection

View File

@@ -42,12 +42,12 @@ class SelectMotionRightAction : MotionActionHandler.ForEachCaret() {
override fun getOffset(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Int { override fun getOffset(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Int {
val keymodel = OptionsManager.keymodel val keymodel = OptionsManager.keymodel
if (KeyModelOptionData.stopsel in keymodel || KeyModelOptionData.stopselect in keymodel) { if (KeyModelOptionData.stopsel in keymodel || KeyModelOptionData.stopselect in keymodel) {
logger.info("Keymodel option has stopselect. Exiting select mode") logger.debug("Keymodel option has stopselect. Exiting select mode")
val startSelection = caret.selectionStart val startSelection = caret.selectionStart
val endSelection = caret.selectionEnd val endSelection = caret.selectionEnd
editor.exitSelectMode(false) editor.exitSelectMode(false)
if (editor.isTemplateActive()) { if (editor.isTemplateActive()) {
logger.info("Template is active. Activate insert mode") logger.debug("Template is active. Activate insert mode")
VimPlugin.getChange().insertBeforeCursor(editor, context) VimPlugin.getChange().insertBeforeCursor(editor, context)
if (caret.offset in startSelection..endSelection) { if (caret.offset in startSelection..endSelection) {
return endSelection return endSelection

View File

@@ -75,7 +75,7 @@ class CommandState private constructor() {
fun pushModes(mode: Mode, submode: SubMode) { fun pushModes(mode: Mode, submode: SubMode) {
val newModeState = ModeState(mode, submode) val newModeState = ModeState(mode, submode)
logger.info("Push new mode state: ${newModeState.toSimpleString()}") logger.debug("Push new mode state: ${newModeState.toSimpleString()}")
logger.debug { "Stack of mode states before push: ${toSimpleString()}" } logger.debug { "Stack of mode states before push: ${toSimpleString()}" }
modeStates.push(newModeState) modeStates.push(newModeState)
setMappingMode() setMappingMode()
@@ -86,7 +86,7 @@ class CommandState private constructor() {
val popped = modeStates.pop() val popped = modeStates.pop()
setMappingMode() setMappingMode()
updateStatus() updateStatus()
logger.info("Popped mode state: ${popped.toSimpleString()}") logger.debug("Popped mode state: ${popped.toSimpleString()}")
logger.debug { "Stack of mode states after pop: ${toSimpleString()}" } logger.debug { "Stack of mode states after pop: ${toSimpleString()}" }
} }

View File

@@ -121,31 +121,8 @@ sealed class CommandHandler {
@Throws(ExException::class) @Throws(ExException::class)
fun process(editor: Editor, context: DataContext, cmd: ExCommand, count: Int): Boolean { fun process(editor: Editor, context: DataContext, cmd: ExCommand, count: Int): Boolean {
// No range allowed checkArgs(cmd)
if (RangeFlag.RANGE_FORBIDDEN == argFlags.rangeFlag && cmd.ranges.size() != 0) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_norange))
throw NoRangeAllowedException()
}
if (RangeFlag.RANGE_REQUIRED == argFlags.rangeFlag && cmd.ranges.size() == 0) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_rangereq))
throw MissingRangeException()
}
if (RangeFlag.RANGE_IS_COUNT == argFlags.rangeFlag) {
cmd.ranges.setDefaultLine(1)
}
// Argument required
if (ArgumentFlag.ARGUMENT_REQUIRED == argFlags.argumentFlag && cmd.argument.isEmpty()) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_argreq))
throw MissingArgumentException()
}
if (ArgumentFlag.ARGUMENT_FORBIDDEN == argFlags.argumentFlag && cmd.argument.isNotEmpty()) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_argforb))
throw NoArgumentAllowedException()
}
if (editor.inVisualMode && Flag.SAVE_VISUAL !in argFlags.flags) { if (editor.inVisualMode && Flag.SAVE_VISUAL !in argFlags.flags) {
editor.exitVisualMode() editor.exitVisualMode()
} }
@@ -179,6 +156,34 @@ sealed class CommandHandler {
return false return false
} }
} }
private fun checkArgs(cmd: ExCommand) {
// No range allowed
if (RangeFlag.RANGE_FORBIDDEN == argFlags.rangeFlag && cmd.ranges.size() != 0) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_norange))
throw NoRangeAllowedException()
}
if (RangeFlag.RANGE_REQUIRED == argFlags.rangeFlag && cmd.ranges.size() == 0) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_rangereq))
throw MissingRangeException()
}
if (RangeFlag.RANGE_IS_COUNT == argFlags.rangeFlag) {
cmd.ranges.setDefaultLine(1)
}
// Argument required
if (ArgumentFlag.ARGUMENT_REQUIRED == argFlags.argumentFlag && cmd.argument.isEmpty()) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_argreq))
throw MissingArgumentException()
}
if (ArgumentFlag.ARGUMENT_FORBIDDEN == argFlags.argumentFlag && cmd.argument.isNotEmpty()) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_argforb))
throw NoArgumentAllowedException()
}
}
} }
data class CommandHandlerFlags( data class CommandHandlerFlags(

View File

@@ -126,7 +126,6 @@ public class CommandParser {
private void processCommand(@NotNull Editor editor, @NotNull DataContext context, @NotNull String cmd, private void processCommand(@NotNull Editor editor, @NotNull DataContext context, @NotNull String cmd,
int count, int aliasCountdown) throws ExException { int count, int aliasCountdown) throws ExException {
// Nothing entered // Nothing entered
int result = 0;
if (cmd.length() == 0) { if (cmd.length() == 0) {
logger.warn("CMD is empty"); logger.warn("CMD is empty");
return; return;
@@ -326,13 +325,12 @@ public class CommandParser {
if (ch == '/' || ch == '?' || ch == '&') { if (ch == '/' || ch == '?' || ch == '&') {
location.append(ch); location.append(ch);
state = State.RANGE_PATTERN_MAYBE_DONE; state = State.RANGE_PATTERN_MAYBE_DONE;
reprocess = false;
} }
else { else {
error = MessageHelper.message(Msg.e_backslash); error = MessageHelper.message(Msg.e_backslash);
state = State.ERROR; state = State.ERROR;
reprocess = false;
} }
reprocess = false;
break; break;
case RANGE_PATTERN: // Reading a pattern range case RANGE_PATTERN: // Reading a pattern range
// No trailing / or ? required if there is no command so look for newline to tell us we are done // No trailing / or ? required if there is no command so look for newline to tell us we are done

View File

@@ -34,7 +34,7 @@ import java.io.IOException
class CmdFilterHandler : CommandHandler.SingleExecution() { class CmdFilterHandler : CommandHandler.SingleExecution() {
override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.WRITABLE) override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.WRITABLE)
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean { override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean {
logger.info("execute") logger.debug("execute")
var command = cmd.argument var command = cmd.argument
if (command.isEmpty()) { if (command.isEmpty()) {

View File

@@ -0,0 +1,56 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.ex.handler
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.CommandHandler.Access.READ_ONLY
import com.maddyhome.idea.vim.ex.CommandHandler.ArgumentFlag.ARGUMENT_REQUIRED
import com.maddyhome.idea.vim.ex.CommandHandler.RangeFlag.RANGE_FORBIDDEN
import com.maddyhome.idea.vim.ex.CommandHandlerFlags
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.ex.vimscript.VimScriptCommandHandler
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
/**
* This handler is created to support `Plug` command from vim-plug and `Plugin` command from vundle.
*/
class PlugHandler : CommandHandler.SingleExecution(), VimScriptCommandHandler {
override val argFlags: CommandHandlerFlags = flags(RANGE_FORBIDDEN, ARGUMENT_REQUIRED, READ_ONLY)
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean = doExecute(cmd)
override fun execute(cmd: ExCommand) {
doExecute(cmd)
}
private fun doExecute(cmd: ExCommand): Boolean {
val argument = cmd.argument
val firstChar = argument[0]
if (firstChar != '"' && firstChar != '\'') return false
val pluginAlias = argument.drop(1).takeWhile { it != firstChar }
val option = VimExtensionRegistrar.getToggleByAlias(pluginAlias) ?: return false
option.set()
return true
}
}

View File

@@ -95,6 +95,10 @@ object VimScriptParser {
return data return data
} }
fun executeText(vararg text: String) {
executeText(listOf(*text))
}
fun executeText(text: List<String>) { fun executeText(text: List<String>) {
for (line in text) { for (line in text) {
// TODO: Build a proper parse tree for a VimL file instead of ignoring potentially nested lines (VIM-669) // TODO: Build a proper parse tree for a VimL file instead of ignoring potentially nested lines (VIM-669)

View File

@@ -0,0 +1,64 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.extension
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.util.xmlb.annotations.Attribute
import com.intellij.util.xmlb.annotations.CollectionBean
import com.intellij.util.xmlb.annotations.Tag
import com.intellij.util.xmlb.annotations.XCollection
import java.util.concurrent.atomic.AtomicBoolean
// [Version Update] 202+
@Suppress("DEPRECATION")
class ExtensionBeanClass : AbstractExtensionPointBean() {
init {
println()
}
@Attribute("implementation")
var implementation: String? = null
@Attribute("name")
var name: String? = null
/**
* List of aliases for the extension. These aliases are used to support `Plug` and `Plugin` commands.
* Technically, it would be enough to save here github link and short version of it ('author/plugin'),
* but it may contain more aliases just in case.
*/
@Tag("aliases")
@XCollection
var aliases: List<Alias>? = null
var initialized = AtomicBoolean(false)
val handler: VimExtension by lazy {
initialized.set(true)
this.instantiateClass<VimExtension>(
implementation ?: "", ApplicationManager.getApplication().picoContainer
)
}
}
@Tag("alias")
class Alias {
@Attribute("name")
var name: String? = null
}

View File

@@ -21,16 +21,21 @@ package com.maddyhome.idea.vim.extension;
import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.ExtensionPointName;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.key.MappingOwner; import com.maddyhome.idea.vim.key.MappingOwner;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* @author vlan * @author vlan
*/ */
public interface VimExtension { public interface VimExtension {
@NotNull ExtensionPointName<VimExtension> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension"); @NotNull ExtensionPointName<ExtensionBeanClass> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension");
@NotNull /**
String getName(); * @deprecated Please set extension name in <vimExtension> tag
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "0.63")
@NotNull String getName();
default MappingOwner getOwner() { default MappingOwner getOwner() {
return MappingOwner.Plugin.Companion.get(getName()); return MappingOwner.Plugin.Companion.get(getName());
@@ -40,5 +45,5 @@ public interface VimExtension {
default void dispose() { default void dispose() {
VimPlugin.getKey().removeKeyMapping(getOwner()); VimPlugin.getKey().removeKeyMapping(getOwner());
}; }
} }

View File

@@ -22,14 +22,15 @@ import com.intellij.openapi.extensions.ExtensionPointListener
import com.intellij.openapi.extensions.PluginDescriptor import com.intellij.openapi.extensions.PluginDescriptor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
import com.maddyhome.idea.vim.option.OptionsManager
import com.maddyhome.idea.vim.option.OptionsManager.addOption import com.maddyhome.idea.vim.option.OptionsManager.addOption
import com.maddyhome.idea.vim.option.OptionsManager.isSet import com.maddyhome.idea.vim.option.OptionsManager.isSet
import com.maddyhome.idea.vim.option.OptionsManager.removeOption import com.maddyhome.idea.vim.option.OptionsManager.removeOption
import com.maddyhome.idea.vim.option.ToggleOption import com.maddyhome.idea.vim.option.ToggleOption
import java.util.*
object VimExtensionRegistrar { object VimExtensionRegistrar {
private val registeredExtensions: MutableSet<String> = HashSet() private val registeredExtensions: MutableSet<String> = HashSet()
private val extensionAliases = HashMap<String, String>()
private var extensionRegistered = false private var extensionRegistered = false
private val logger = logger<VimExtensionRegistrar>() private val logger = logger<VimExtensionRegistrar>()
@@ -37,48 +38,67 @@ object VimExtensionRegistrar {
fun registerExtensions() { fun registerExtensions() {
if (extensionRegistered) return if (extensionRegistered) return
extensionRegistered = true extensionRegistered = true
VimExtension.EP_NAME.extensions.forEach(this::registerExtension)
// [VERSION UPDATE] 202+ // [VERSION UPDATE] 202+
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).addExtensionPointListener(object : ExtensionPointListener<VimExtension> { VimExtension.EP_NAME.getPoint(null).addExtensionPointListener(object : ExtensionPointListener<ExtensionBeanClass> {
override fun extensionAdded(extension: VimExtension, pluginDescriptor: PluginDescriptor) { override fun extensionAdded(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) {
registerExtension(extension) registerExtension(extension)
} }
override fun extensionRemoved(extension: VimExtension, pluginDescriptor: PluginDescriptor) { override fun extensionRemoved(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) {
unregisterExtension(extension) unregisterExtension(extension)
} }
}, true, VimPlugin.getInstance()) }, false, VimPlugin.getInstance())
} }
@Synchronized @Synchronized
private fun registerExtension(extension: VimExtension) { private fun registerExtension(extensionBean: ExtensionBeanClass) {
val name = extension.name val name = extensionBean.name ?: extensionBean.handler.name
if (name in registeredExtensions) return if (name in registeredExtensions) return
registeredExtensions.add(name) registeredExtensions.add(name)
registerAliases(extensionBean)
val option = ToggleOption(name, name, false) val option = ToggleOption(name, name, false)
option.addOptionChangeListener { _, _ -> option.addOptionChangeListener { _, _ ->
for (extensionInListener in VimExtension.EP_NAME.extensionList) {
if (name != extensionInListener.name) continue
if (isSet(name)) { if (isSet(name)) {
extensionInListener.init() extensionBean.handler.init()
logger.info("IdeaVim extension '$name' initialized") logger.info("IdeaVim extension '$name' initialized")
} else { } else {
extensionInListener.dispose() extensionBean.handler.dispose()
}
} }
} }
addOption(option) addOption(option)
} }
@Synchronized @Synchronized
private fun unregisterExtension(extension: VimExtension) { private fun unregisterExtension(extension: ExtensionBeanClass) {
val name = extension.name val name = extension.name ?: extension.handler.name
if (name !in registeredExtensions) return if (name !in registeredExtensions) return
registeredExtensions.remove(name) registeredExtensions.remove(name)
extension.dispose() removeAliases(extension)
if (extension.initialized.get()) {
extension.handler.dispose()
}
removeOption(name) removeOption(name)
remove(name) remove(name)
logger.info("IdeaVim extension '$name' disposed") logger.info("IdeaVim extension '$name' disposed")
} }
fun getToggleByAlias(alias: String): ToggleOption? {
val name = extensionAliases[alias] ?: return null
return OptionsManager.getOption(name) as ToggleOption?
}
private fun registerAliases(extension: ExtensionBeanClass) {
extension.aliases
?.mapNotNull { it.name }
?.forEach { alias -> extensionAliases[alias] = extension.name ?: extension.handler.name }
}
private fun removeAliases(extension: ExtensionBeanClass) {
extension.aliases?.mapNotNull { it.name }?.forEach { extensionAliases.remove(it) }
}
} }

View File

@@ -17,8 +17,7 @@ import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.EnumSet; import java.util.*;
import java.util.Stack;
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping; import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping; import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping;
@@ -50,13 +49,13 @@ public class VimArgTextObjExtension implements VimExtension {
/** /**
* The pairs of brackets that delimit different types of argument lists. * The pairs of brackets that delimit different types of argument lists.
*/ */
static private class BracketPairs { private static class BracketPairs {
// NOTE: brackets must match by the position, and ordered by rank (highest to lowest). // NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
@NotNull private final String openBrackets; @NotNull private final String openBrackets;
@NotNull private final String closeBrackets; @NotNull private final String closeBrackets;
static class ParseError extends Exception { static class ParseException extends Exception {
public ParseError(@NotNull String message) { public ParseException(@NotNull String message) {
super(message); super(message);
} }
} }
@@ -73,10 +72,10 @@ public class VimArgTextObjExtension implements VimExtension {
* as VIM's @c matchpairs option: "(:),{:},[:]" * as VIM's @c matchpairs option: "(:),{:},[:]"
* *
* @param bracketPairs comma-separated list of colon-separated bracket pairs. * @param bracketPairs comma-separated list of colon-separated bracket pairs.
* @throws ParseError if a syntax error is detected. * @throws ParseException if a syntax error is detected.
*/ */
@NotNull @NotNull
static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseError { static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseException {
StringBuilder openBrackets = new StringBuilder(); StringBuilder openBrackets = new StringBuilder();
StringBuilder closeBrackets = new StringBuilder(); StringBuilder closeBrackets = new StringBuilder();
ParseState state = ParseState.OPEN; ParseState state = ParseState.OPEN;
@@ -90,13 +89,13 @@ public class VimArgTextObjExtension implements VimExtension {
if (ch == ':') { if (ch == ':') {
state = ParseState.CLOSE; state = ParseState.CLOSE;
} else { } else {
throw new ParseError("expecting ':', but got '" + ch + "' instead"); throw new ParseException("expecting ':', but got '" + ch + "' instead");
} }
break; break;
case CLOSE: case CLOSE:
final char lastOpenBracket = openBrackets.charAt(openBrackets.length() - 1); final char lastOpenBracket = openBrackets.charAt(openBrackets.length() - 1);
if (lastOpenBracket == ch) { if (lastOpenBracket == ch) {
throw new ParseError("open and close brackets must be different"); throw new ParseException("open and close brackets must be different");
} }
closeBrackets.append(ch); closeBrackets.append(ch);
state = ParseState.COMMA; state = ParseState.COMMA;
@@ -105,13 +104,13 @@ public class VimArgTextObjExtension implements VimExtension {
if (ch == ',') { if (ch == ',') {
state = ParseState.OPEN; state = ParseState.OPEN;
} else { } else {
throw new ParseError("expecting ',', but got '" + ch + "' instead"); throw new ParseException("expecting ',', but got '" + ch + "' instead");
} }
break; break;
} }
} }
if (state != ParseState.COMMA) { if (state != ParseState.COMMA) {
throw new ParseError("list of pairs is incomplete"); throw new ParseException("list of pairs is incomplete");
} }
return new BracketPairs(openBrackets.toString(), closeBrackets.toString()); return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
} }
@@ -183,8 +182,8 @@ public class VimArgTextObjExtension implements VimExtension {
if (bracketPairsVar != null) { if (bracketPairsVar != null) {
try { try {
bracketPairs = BracketPairs.fromBracketPairList(bracketPairsVar); bracketPairs = BracketPairs.fromBracketPairList(bracketPairsVar);
} catch (BracketPairs.ParseError parseError) { } catch (BracketPairs.ParseException parseException) {
VimPlugin.showMessage("argtextobj: Invalid value of g:argtextobj_pairs -- " + parseError.getMessage()); VimPlugin.showMessage("argtextobj: Invalid value of g:argtextobj_pairs -- " + parseException.getMessage());
VimPlugin.indicateError(); VimPlugin.indicateError();
return null; return null;
} }
@@ -590,20 +589,20 @@ public class VimArgTextObjExtension implements VimExtension {
private int skipSexp(final int start, final int end, SexpDirection dir) { private int skipSexp(final int start, final int end, SexpDirection dir) {
char lastChar = getCharAt(start); char lastChar = getCharAt(start);
assert dir.isOpenBracket(lastChar); assert dir.isOpenBracket(lastChar);
Stack<Character> bracketStack = new Stack<>(); Deque<Character> bracketStack = new ArrayDeque<>();
bracketStack.push(lastChar); bracketStack.push(lastChar);
int i = start + dir.delta(); int i = start + dir.delta();
while (!bracketStack.empty() && i != end) { while (!bracketStack.isEmpty() && i != end) {
final char ch = getCharAt(i); final char ch = getCharAt(i);
if (dir.isOpenBracket(ch)) { if (dir.isOpenBracket(ch)) {
bracketStack.push(ch); bracketStack.push(ch);
} else { } else {
if (dir.isCloseBracket(ch)) { if (dir.isCloseBracket(ch)) {
if (bracketStack.lastElement() == brackets.matchingBracket(ch)) { if (bracketStack.getLast() == brackets.matchingBracket(ch)) {
bracketStack.pop(); bracketStack.pop();
} else { } else {
//noinspection StatementWithEmptyBody //noinspection StatementWithEmptyBody
if (brackets.getBracketPrio(ch) < brackets.getBracketPrio(bracketStack.lastElement())) { if (brackets.getBracketPrio(ch) < brackets.getBracketPrio(bracketStack.getLast())) {
// (<...) -> (...) // (<...) -> (...)
bracketStack.pop(); bracketStack.pop();
// Retry the same character again for cases like (...<<...). // Retry the same character again for cases like (...<<...).
@@ -621,7 +620,7 @@ public class VimArgTextObjExtension implements VimExtension {
} }
i += dir.delta(); i += dir.delta();
} }
if (bracketStack.empty()) { if (bracketStack.isEmpty()) {
return i; return i;
} else { } else {
return start + dir.delta(); return start + dir.delta();

View File

@@ -64,6 +64,7 @@ import com.maddyhome.idea.vim.key.OperatorFunction
*/ */
class VimExchangeExtension : VimExtension { class VimExchangeExtension : VimExtension {
override fun getName() = "exchange" override fun getName() = "exchange"
override fun init() { override fun init() {

View File

@@ -18,6 +18,8 @@
package com.maddyhome.idea.vim.extension.highlightedyank package com.maddyhome.idea.vim.extension.highlightedyank
import com.intellij.ide.ui.LafManager
import com.intellij.ide.ui.LafManagerListener
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@@ -44,8 +46,19 @@ import java.util.concurrent.TimeUnit
const val DEFAULT_HIGHLIGHT_DURATION: Long = 300 const val DEFAULT_HIGHLIGHT_DURATION: Long = 300
private const val HIGHLIGHT_DURATION_VARIABLE_NAME = "g:highlightedyank_highlight_duration" private const val HIGHLIGHT_DURATION_VARIABLE_NAME = "g:highlightedyank_highlight_duration"
private const val HIGHLIGHT_COLOR_VARIABLE_NAME = "g:highlightedyank_highlight_color" private const val HIGHLIGHT_COLOR_VARIABLE_NAME = "g:highlightedyank_highlight_color"
private val DEFAULT_HIGHLIGHT_TEXT_COLOR: Color = EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES.defaultAttributes.backgroundColor private var defaultHighlightTextColor: Color? = null
private fun getDefaultHighlightTextColor(): Color {
return defaultHighlightTextColor
?: return EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES.defaultAttributes.backgroundColor
.also { defaultHighlightTextColor = it }
}
class HighlightColorResetter : LafManagerListener {
override fun lookAndFeelChanged(source: LafManager) {
defaultHighlightTextColor = null
}
}
/** /**
* @author KostkaBrukowa (@kostkabrukowa) * @author KostkaBrukowa (@kostkabrukowa)
@@ -164,7 +177,7 @@ class VimHighlightedYank: VimExtension, VimYankListener, VimInsertListener {
} }
private fun extractUsersHighlightColor(): Color { private fun extractUsersHighlightColor(): Color {
return extractVariable(HIGHLIGHT_COLOR_VARIABLE_NAME, DEFAULT_HIGHLIGHT_TEXT_COLOR) { value -> return extractVariable(HIGHLIGHT_COLOR_VARIABLE_NAME, getDefaultHighlightTextColor()) { value ->
val rgba = value val rgba = value
.substring(4) .substring(4)
.filter { it != '(' && it != ')' && !it.isWhitespace() } .filter { it != '(' && it != ')' && !it.isWhitespace() }

View File

@@ -57,6 +57,7 @@ private const val ALL_OCCURRENCES = "<Plug>AllOccurrences"
* See https://github.com/terryma/vim-multiple-cursors * See https://github.com/terryma/vim-multiple-cursors
* */ * */
class VimMultipleCursorsExtension : VimExtension { class VimMultipleCursorsExtension : VimExtension {
override fun getName() = "multiple-cursors" override fun getName() = "multiple-cursors"
override fun init() { override fun init() {

View File

@@ -34,7 +34,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionHandler import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.RegisterGroup
import com.maddyhome.idea.vim.group.copy.PutData import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.group.visual.VimSelection import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.helper.EditorDataContext import com.maddyhome.idea.vim.helper.EditorDataContext
@@ -46,6 +45,7 @@ import com.maddyhome.idea.vim.key.OperatorFunction
class ReplaceWithRegister : VimExtension { class ReplaceWithRegister : VimExtension {
override fun getName(): String = "ReplaceWithRegister" override fun getName(): String = "ReplaceWithRegister"
override fun init() { override fun init() {
@@ -144,7 +144,7 @@ class ReplaceWithRegister : VimExtension {
VimPlugin.getPut().putText(editor, EditorDataContext(editor), putData) VimPlugin.getPut().putText(editor, EditorDataContext(editor), putData)
VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister) VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister)
VimPlugin.getRegister().saveRegister(RegisterGroup.DEFAULT_REGISTER, savedRegister) VimPlugin.getRegister().saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister)
} }
} }
} }

View File

@@ -52,6 +52,7 @@ import javax.swing.KeyStroke
* @author vlan * @author vlan
*/ */
class VimSurroundExtension : VimExtension { class VimSurroundExtension : VimExtension {
override fun getName() = "surround" override fun getName() = "surround"
override fun init() { override fun init() {

View File

@@ -61,12 +61,14 @@ import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
* @author Alexandre Grison (@agrison) * @author Alexandre Grison (@agrison)
*/ */
public class VimTextObjEntireExtension implements VimExtension { public class VimTextObjEntireExtension implements VimExtension {
@Override @Override
public @NotNull public @NotNull
String getName() { String getName() {
return "textobj-entire"; return "textobj-entire";
} }
@Override @Override
public void init() { public void init() {
putExtensionHandlerMapping(MappingMode.XO, parseKeys("<Plug>textobj-entire-a"), getOwner(), putExtensionHandlerMapping(MappingMode.XO, parseKeys("<Plug>textobj-entire-a"), getOwner(),

View File

@@ -1254,10 +1254,9 @@ public class ChangeGroup {
} }
if (kludge) { if (kludge) {
int size = fileSize;
int cnt = count * motion.getCount(); int cnt = count * motion.getCount();
int pos1 = SearchHelper.findNextWordEnd(chars, offset, size, cnt, bigWord, false); int pos1 = SearchHelper.findNextWordEnd(chars, offset, fileSize, cnt, bigWord, false);
int pos2 = SearchHelper.findNextWordEnd(chars, pos1, size, -cnt, bigWord, false); int pos2 = SearchHelper.findNextWordEnd(chars, pos1, fileSize, -cnt, bigWord, false);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("pos=" + offset); logger.debug("pos=" + offset);
logger.debug("pos1=" + pos1); logger.debug("pos1=" + pos1);
@@ -1773,7 +1772,7 @@ public class ChangeGroup {
} }
private static void resetCaret(@NotNull VirtualFile virtualFile, Project proj, boolean insert) { private static void resetCaret(@NotNull VirtualFile virtualFile, Project proj, boolean insert) {
logger.info("Reset caret to a " + (insert ? "non-block" : "block") + " shape"); logger.debug("Reset caret to a " + (insert ? "non-block" : "block") + " shape");
Document doc = FileDocumentManager.getInstance().getDocument(virtualFile); Document doc = FileDocumentManager.getInstance().getDocument(virtualFile);
if (doc == null) return; // Must be no text editor (such as image) if (doc == null) return; // Must be no text editor (such as image)
Editor[] editors = EditorFactory.getInstance().getEditors(doc, proj); Editor[] editors = EditorFactory.getInstance().getEditors(doc, proj);
@@ -1978,7 +1977,7 @@ public class ChangeGroup {
if (!Character.isLetter(ch)) throw new RuntimeException("Not alpha number : " + text); if (!Character.isLetter(ch)) throw new RuntimeException("Not alpha number : " + text);
ch += count; ch += count;
if (Character.isLetter(ch)) { if (Character.isLetter(ch)) {
number = "" + ch; number = String.valueOf(ch);
} }
} }
else if (SearchHelper.NumberType.DEC.equals(numberType)) { else if (SearchHelper.NumberType.DEC.equals(numberType)) {

View File

@@ -51,7 +51,7 @@ class CommandGroup {
return name in this.aliases return name in this.aliases
} }
fun getAlias(name: String): Alias { private fun getAlias(name: String): Alias {
return this.aliases[name]!! return this.aliases[name]!!
} }

View File

@@ -498,8 +498,8 @@ public class KeyGroup implements PersistentStateComponent<Element> {
if (action instanceof VimShortcutKeyAction) { if (action instanceof VimShortcutKeyAction) {
continue; continue;
} }
final com.intellij.openapi.actionSystem.Shortcut[] shortcuts = action.getShortcutSet().getShortcuts(); final Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
for (com.intellij.openapi.actionSystem.Shortcut shortcut : shortcuts) { for (Shortcut shortcut : shortcuts) {
if (shortcut.isKeyboard() && shortcut.startsWith(keyStrokeShortcut) && !results.contains(action)) { if (shortcut.isKeyboard() && shortcut.startsWith(keyStrokeShortcut) && !results.contains(action)) {
results.add(action); results.add(action);
} }

View File

@@ -122,7 +122,7 @@ public class MarkGroup implements PersistentStateComponent<Element> {
else if (FILE_MARKS.indexOf(ch) >= 0) { else if (FILE_MARKS.indexOf(ch) >= 0) {
final HashMap<Character, Mark> fmarks = getFileMarks(editor.getDocument()); final HashMap<Character, Mark> fmarks = getFileMarks(editor.getDocument());
if (fmarks != null) { if (fmarks != null) {
mark = (Mark)fmarks.get(ch); mark = fmarks.get(ch);
if (mark != null && mark.isClear()) { if (mark != null && mark.isClear()) {
fmarks.remove(ch); fmarks.remove(ch);
mark = null; mark = null;
@@ -171,7 +171,7 @@ public class MarkGroup implements PersistentStateComponent<Element> {
if (fmarks == null) { if (fmarks == null) {
return null; return null;
} }
Mark mark = (Mark)fmarks.get(ch); Mark mark = fmarks.get(ch);
if (mark != null && mark.isClear()) { if (mark != null && mark.isClear()) {
fmarks.remove(ch); fmarks.remove(ch);
mark = null; mark = null;
@@ -752,7 +752,7 @@ public class MarkGroup implements PersistentStateComponent<Element> {
public static class MarkListener implements BookmarksListener { public static class MarkListener implements BookmarksListener {
private WeakReference<Project> project; private final WeakReference<Project> project;
private Bookmark bookmarkTemplate = null; private Bookmark bookmarkTemplate = null;
@Contract(pure = true) @Contract(pure = true)

View File

@@ -52,7 +52,7 @@ public class ProcessGroup {
} }
String initText = ""; String initText = "";
String label = "" + leader; String label = String.valueOf(leader);
ExEntryPanel panel = ExEntryPanel.getInstance(); ExEntryPanel panel = ExEntryPanel.getInstance();
panel.activate(editor, context, label, initText, count); panel.activate(editor, context, label, initText, count);

View File

@@ -88,9 +88,9 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
private static final List<Character> CLIPBOARD_REGISTERS = ImmutableList.of('*', '+'); private static final List<Character> CLIPBOARD_REGISTERS = ImmutableList.of('*', '+');
private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName()); private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName());
public final static char UNNAMED_REGISTER = '"'; public static final char UNNAMED_REGISTER = '"';
public static char DEFAULT_REGISTER = UNNAMED_REGISTER; private char defaultRegister = UNNAMED_REGISTER;
private char lastRegister = DEFAULT_REGISTER; private char lastRegister = defaultRegister;
private final @NotNull HashMap<Character, Register> registers = new HashMap<>(); private final @NotNull HashMap<Character, Register> registers = new HashMap<>();
private char recordRegister = 0; private char recordRegister = 0;
private @Nullable List<KeyStroke> recordList = null; private @Nullable List<KeyStroke> recordList = null;
@@ -99,15 +99,15 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
final ListOption clipboardOption = OptionsManager.INSTANCE.getClipboard(); final ListOption clipboardOption = OptionsManager.INSTANCE.getClipboard();
clipboardOption.addOptionChangeListenerAndExecute((oldValue, newValue) -> { clipboardOption.addOptionChangeListenerAndExecute((oldValue, newValue) -> {
if (clipboardOption.contains("unnamed")) { if (clipboardOption.contains("unnamed")) {
DEFAULT_REGISTER = '*'; defaultRegister = '*';
} }
else if (clipboardOption.contains("unnamedplus")) { else if (clipboardOption.contains("unnamedplus")) {
DEFAULT_REGISTER = '+'; defaultRegister = '+';
} }
else { else {
DEFAULT_REGISTER = UNNAMED_REGISTER; defaultRegister = UNNAMED_REGISTER;
} }
lastRegister = DEFAULT_REGISTER; lastRegister = defaultRegister;
}); });
} }
@@ -144,7 +144,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
* Reset the selected register back to the default register. * Reset the selected register back to the default register.
*/ */
public void resetRegister() { public void resetRegister() {
lastRegister = DEFAULT_REGISTER; lastRegister = defaultRegister;
logger.debug("Last register reset to default register"); logger.debug("Last register reset to default register");
} }
@@ -228,7 +228,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
editor.offsetToLogicalPosition(start).line == editor.offsetToLogicalPosition(end).line; editor.offsetToLogicalPosition(start).line == editor.offsetToLogicalPosition(end).line;
// Deletes go into numbered registers only if text is smaller than a line, register is used or it's a special case // Deletes go into numbered registers only if text is smaller than a line, register is used or it's a special case
if (!smallInlineDeletion || register != DEFAULT_REGISTER || isSmallDeletionSpecialCase(editor)) { if (!smallInlineDeletion || register != defaultRegister || isSmallDeletionSpecialCase(editor)) {
// Old 1 goes to 2, etc. Old 8 to 9, old 9 is lost // Old 1 goes to 2, etc. Old 8 to 9, old 9 is lost
for (char d = '8'; d >= '1'; d--) { for (char d = '8'; d >= '1'; d--) {
Register t = registers.get(d); Register t = registers.get(d);
@@ -241,12 +241,12 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
} }
// Deletes smaller than one line and without specified register go the the "-" register // Deletes smaller than one line and without specified register go the the "-" register
if (smallInlineDeletion && register == DEFAULT_REGISTER) { if (smallInlineDeletion && register == defaultRegister) {
registers.put('-', new Register('-', type, processedText, new ArrayList<>(transferableData))); registers.put('-', new Register('-', type, processedText, new ArrayList<>(transferableData)));
} }
} }
// Yanks also go to register 0 if the default register was used // Yanks also go to register 0 if the default register was used
else if (register == DEFAULT_REGISTER) { else if (register == defaultRegister) {
registers.put('0', new Register('0', type, processedText, new ArrayList<>(transferableData))); registers.put('0', new Register('0', type, processedText, new ArrayList<>(transferableData)));
if (logger.isDebugEnabled()) logger.debug("register '" + '0' + "' contains: \"" + processedText + "\""); if (logger.isDebugEnabled()) logger.debug("register '" + '0' + "' contains: \"" + processedText + "\"");
} }
@@ -372,7 +372,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
* The register key for the default register. * The register key for the default register.
*/ */
public char getDefaultRegister() { public char getDefaultRegister() {
return DEFAULT_REGISTER; return defaultRegister;
} }
public @NotNull List<Register> getRegisters() { public @NotNull List<Register> getRegisters() {

View File

@@ -874,7 +874,7 @@ public class SearchGroup implements PersistentStateComponent<Element> {
private int findItOffset(@NotNull Editor editor, int startOffset, int count, int dir) { private int findItOffset(@NotNull Editor editor, int startOffset, int count, int dir) {
boolean wrap = OptionsManager.INSTANCE.getWrapscan().isSet(); boolean wrap = OptionsManager.INSTANCE.getWrapscan().isSet();
logger.info("Perform search. Direction: " + dir + " wrap: " + wrap); logger.debug("Perform search. Direction: " + dir + " wrap: " + wrap);
int offset = 0; int offset = 0;
boolean offsetIsLineOffset = false; boolean offsetIsLineOffset = false;
@@ -977,12 +977,9 @@ public class SearchGroup implements PersistentStateComponent<Element> {
res = search(editor, lastOffset.substring(ppos + 1), res, 1, flags); res = search(editor, lastOffset.substring(ppos + 1), res, 1, flags);
return res;
} }
else {
return res; return res;
} }
}
@RWLockLabel.SelfSynchronized @RWLockLabel.SelfSynchronized
public boolean searchAndReplace(@NotNull Editor editor, @NotNull Caret caret, @NotNull LineRange range, public boolean searchAndReplace(@NotNull Editor editor, @NotNull Caret caret, @NotNull LineRange range,

View File

@@ -182,7 +182,7 @@ class YankGroup {
private fun yankRange(editor: Editor, range: TextRange, type: SelectionType, private fun yankRange(editor: Editor, range: TextRange, type: SelectionType,
startOffsets: Map<Caret, Int>?): Boolean { startOffsets: Map<Caret, Int>?): Boolean {
startOffsets?.forEach { caret, offset -> MotionGroup.moveCaret(editor, caret, offset) } startOffsets?.forEach { (caret, offset) -> MotionGroup.moveCaret(editor, caret, offset) }
notifyListeners(editor, range) notifyListeners(editor, range)

View File

@@ -55,7 +55,7 @@ object IdeaSelectionControl {
if (editor.isIdeaVimDisabledHere) return@singleTask if (editor.isIdeaVimDisabledHere) return@singleTask
logger.info("Adjust non-vim selection. Source: $selectionSource") logger.debug("Adjust non-vim selection. Source: $selectionSource")
// Perform logic in one of the next cases: // Perform logic in one of the next cases:
// - There was no selection and now it is // - There was no selection and now it is
@@ -69,13 +69,13 @@ object IdeaSelectionControl {
return@singleTask return@singleTask
} }
logger.info("Some carets have selection. State before adjustment: ${editor.commandState.toSimpleString()}") logger.debug("Some carets have selection. State before adjustment: ${editor.commandState.toSimpleString()}")
editor.popAllModes() editor.popAllModes()
activateMode(editor, chooseSelectionMode(editor, selectionSource, true)) activateMode(editor, chooseSelectionMode(editor, selectionSource, true))
} else { } else {
logger.info("None of carets have selection. State before adjustment: ${editor.commandState.toSimpleString()}") logger.debug("None of carets have selection. State before adjustment: ${editor.commandState.toSimpleString()}")
if (editor.inVisualMode) editor.exitVisualMode() if (editor.inVisualMode) editor.exitVisualMode()
if (editor.inSelectMode) editor.exitSelectMode(false) if (editor.inSelectMode) editor.exitSelectMode(false)
@@ -86,7 +86,7 @@ object IdeaSelectionControl {
KeyHandler.getInstance().reset(editor) KeyHandler.getInstance().reset(editor)
updateCaretState(editor) updateCaretState(editor)
logger.info("${editor.mode} is enabled") logger.debug("${editor.mode} is enabled")
} }
} }
@@ -132,23 +132,23 @@ object IdeaSelectionControl {
private fun chooseSelectionMode(editor: Editor, selectionSource: VimListenerManager.SelectionSource, logReason: Boolean): CommandState.Mode { private fun chooseSelectionMode(editor: Editor, selectionSource: VimListenerManager.SelectionSource, logReason: Boolean): CommandState.Mode {
return when { return when {
editor.isOneLineMode -> { editor.isOneLineMode -> {
if (logReason) logger.info("Enter select mode. Reason: one line mode") if (logReason) logger.debug("Enter select mode. Reason: one line mode")
CommandState.Mode.SELECT CommandState.Mode.SELECT
} }
selectionSource == VimListenerManager.SelectionSource.MOUSE && SelectModeOptionData.mouse in OptionsManager.selectmode -> { selectionSource == VimListenerManager.SelectionSource.MOUSE && SelectModeOptionData.mouse in OptionsManager.selectmode -> {
if (logReason) logger.info("Enter select mode. Selection source is mouse and selectMode option has mouse") if (logReason) logger.debug("Enter select mode. Selection source is mouse and selectMode option has mouse")
CommandState.Mode.SELECT CommandState.Mode.SELECT
} }
editor.isTemplateActive() && IdeaRefactorMode.selectMode() -> { editor.isTemplateActive() && IdeaRefactorMode.selectMode() -> {
if (logReason) logger.info("Enter select mode. Template is active and selectMode has template") if (logReason) logger.debug("Enter select mode. Template is active and selectMode has template")
CommandState.Mode.SELECT CommandState.Mode.SELECT
} }
selectionSource == VimListenerManager.SelectionSource.OTHER && SelectModeOptionData.ideaselectionEnabled() -> { selectionSource == VimListenerManager.SelectionSource.OTHER && SelectModeOptionData.ideaselectionEnabled() -> {
if (logReason) logger.info("Enter select mode. Selection source is OTHER and selectMode has refactoring") if (logReason) logger.debug("Enter select mode. Selection source is OTHER and selectMode has refactoring")
CommandState.Mode.SELECT CommandState.Mode.SELECT
} }
else -> { else -> {
if (logReason) logger.info("Enter visual mode") if (logReason) logger.debug("Enter visual mode")
CommandState.Mode.VISUAL CommandState.Mode.VISUAL
} }
} }

View File

@@ -152,7 +152,7 @@ class VimBlockSelection(
override val vimStart: Int, override val vimStart: Int,
override val vimEnd: Int, override val vimEnd: Int,
override val editor: Editor, override val editor: Editor,
val toLineEnd: Boolean private val toLineEnd: Boolean
) : VimSelection() { ) : VimSelection() {
override fun getNativeStartAndEnd() = blockToNativeSelection(editor, vimStart, vimEnd, CommandState.Mode.VISUAL).let { override fun getNativeStartAndEnd() = blockToNativeSelection(editor, vimStart, vimEnd, CommandState.Mode.VISUAL).let {
editor.logicalPositionToOffset(it.first) to editor.logicalPositionToOffset(it.second) editor.logicalPositionToOffset(it.first) to editor.logicalPositionToOffset(it.second)

View File

@@ -20,14 +20,15 @@
package com.maddyhome.idea.vim.helper package com.maddyhome.idea.vim.helper
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.VisualPosition
import com.intellij.openapi.editor.ex.util.EditorUtil import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.util.ui.table.JBTableRowEditor
import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.option.OptionsManager
import java.awt.Component
import javax.swing.JComponent
import javax.swing.JTable
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
val Editor.fileSize: Int val Editor.fileSize: Int
@@ -41,23 +42,30 @@ val Editor.isIdeaVimDisabledHere: Boolean
get() { get() {
var res = true var res = true
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val times = mutableListOf<Long>() val times = mutableListOf<Pair<Long, String>>()
val timeForCalculation = measureTimeMillis { val timeForCalculation = measureTimeMillis {
res = (disabledInDialog.apply { times += System.currentTimeMillis() } res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|| (!OptionsManager.ideaenabledbufs.contains("singleline") && isDatabaseCell).apply { times += System.currentTimeMillis() }
|| (!OptionsManager.ideaenabledbufs.contains("singleline") && isOneLineMode).apply { times += System.currentTimeMillis() } || (!OptionsManager.ideaenabledbufs.contains("singleline")
.apply { times += System.currentTimeMillis() to "first single line check" }
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
.apply { times += System.currentTimeMillis() to "second single line check" }
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
) )
} }
if (timeForCalculation > 10) { if (timeForCalculation > 10) {
val timeDiffs = times.map { it - start } val timeDiffs = times.map { it.second + ": " + (it.first - start) }
val message = "Time for calculation of 'isIdeaVimDisabledHere' took $timeForCalculation ms. Time diff: $timeDiffs" val message = "Time for calculation of 'isIdeaVimDisabledHere' took $timeForCalculation ms. Time diff: $timeDiffs"
logger<Editor>().error(message) logger<Editor>().error(message)
} }
return res return res
} }
private val Editor.isDatabaseCell: Boolean private fun Editor.isDatabaseCell(times: MutableList<Pair<Long, String>>): Boolean {
get() = DarculaUIUtil.isTableCellEditor(this.component) return isTableCellEditor(this.component, times)
}
private val Editor.disabledInDialog: Boolean private val Editor.disabledInDialog: Boolean
get() = (!OptionsManager.ideaenabledbufs.contains("dialog") && !OptionsManager.ideaenabledbufs.contains("dialoglegacy")) get() = (!OptionsManager.ideaenabledbufs.contains("dialog") && !OptionsManager.ideaenabledbufs.contains("dialoglegacy"))
@@ -72,3 +80,26 @@ fun Editor.isPrimaryEditor(): Boolean {
return fileEditorManager.allEditors.any { fileEditor -> this == EditorUtil.getEditorEx(fileEditor) } return fileEditorManager.allEditors.any { fileEditor -> this == EditorUtil.getEditorEx(fileEditor) }
} }
// Optimized clone of com.intellij.ide.ui.laf.darcula.DarculaUIUtil.isTableCellEditor
private fun isTableCellEditor(c: Component, times: MutableList<Pair<Long, String>>): Boolean {
return (java.lang.Boolean.TRUE == (c as JComponent).getClientProperty("JComboBox.isTableCellEditor"))
.apply { times += System.currentTimeMillis() to "is property tru" } ||
(findParentByCondition(c) { it is JTable } != null)
.apply { times += System.currentTimeMillis() to "is not null" } &&
(findParentByCondition(c) { it is JBTableRowEditor } == null)
.apply { times += System.currentTimeMillis() to "is null" }
}
private const val PARENT_BY_CONDITION_DEPTH = 10
private inline fun findParentByCondition(c: Component?, condition: (Component?) -> Boolean): Component? {
var eachParent = c
var goDeep = PARENT_BY_CONDITION_DEPTH
while (eachParent != null && --goDeep > 0) {
if (condition(eachParent)) return eachParent
eachParent = eachParent.parent
}
return null
}

View File

@@ -138,7 +138,7 @@ public class SearchHelper {
type == chars.charAt(start - 1) && type == chars.charAt(start - 1) &&
end < chars.length() && end < chars.length() &&
close == chars.charAt(end)) { close == chars.charAt(end)) {
start = start - 1; start -= 1;
pos = start; pos = start;
rangeSelection = true; rangeSelection = true;
} }
@@ -608,7 +608,7 @@ public class SearchHelper {
final Pattern tagPattern = Pattern.compile(String.format("(?:%s)|(?:%s)", openingTagPattern, closingTagPattern)); final Pattern tagPattern = Pattern.compile(String.format("(?:%s)|(?:%s)", openingTagPattern, closingTagPattern));
final Matcher matcher = tagPattern.matcher(sequence.subSequence(position, sequence.length())); final Matcher matcher = tagPattern.matcher(sequence.subSequence(position, sequence.length()));
final Stack<String> openTags = new Stack<>(); final Deque<String> openTags = new ArrayDeque<>();
while (matcher.find()) { while (matcher.find()) {
boolean isClosingTag = matcher.group(1) == null; boolean isClosingTag = matcher.group(1) == null;
@@ -655,7 +655,7 @@ public class SearchHelper {
final Pattern tagPattern = final Pattern tagPattern =
Pattern.compile(String.format(patternString, quotedTagName, quotedTagName), Pattern.CASE_INSENSITIVE); Pattern.compile(String.format(patternString, quotedTagName, quotedTagName), Pattern.CASE_INSENSITIVE);
final Matcher matcher = tagPattern.matcher(sequence.subSequence(0, position + 1)); final Matcher matcher = tagPattern.matcher(sequence.subSequence(0, position + 1));
final Stack<TextRange> openTags = new Stack<>(); final Deque<TextRange> openTags = new ArrayDeque<>();
while (matcher.find()) { while (matcher.find()) {
final TextRange match = new TextRange(matcher.start(), matcher.end()); final TextRange match = new TextRange(matcher.start(), matcher.end());

View File

@@ -115,13 +115,10 @@ public class StringHelper {
break; break;
case ESCAPE: case ESCAPE:
state = KeyParserState.INIT; state = KeyParserState.INIT;
if (c == '\\' || c == '<') { if (c != '\\' && c != '<') {
result.add(getKeyStroke(c));
}
else {
result.add(getKeyStroke('\\')); result.add(getKeyStroke('\\'));
result.add(getKeyStroke(c));
} }
result.add(getKeyStroke(c));
break; break;
case SPECIAL: case SPECIAL:
if (c == '>' || c == '»') { if (c == '>' || c == '»') {
@@ -168,7 +165,7 @@ public class StringHelper {
} }
private static @Nullable List<KeyStroke> parseMapLeader(@NotNull String s) { private static @Nullable List<KeyStroke> parseMapLeader(@NotNull String s) {
if ("leader".equals(s.toLowerCase())) { if ("leader".equalsIgnoreCase(s)) {
final Object mapLeader = VimScriptGlobalEnvironment.getInstance().getVariables().get("mapleader"); final Object mapLeader = VimScriptGlobalEnvironment.getInstance().getVariables().get("mapleader");
if (mapLeader instanceof String) { if (mapLeader instanceof String) {
return stringToKeys((String)mapLeader); return stringToKeys((String)mapLeader);
@@ -292,7 +289,7 @@ public class StringHelper {
} else if (CharacterHelper.isInvisibleControlCharacter(c) || CharacterHelper.isZeroWidthCharacter(c)) { } else if (CharacterHelper.isInvisibleControlCharacter(c) || CharacterHelper.isZeroWidthCharacter(c)) {
return String.format("<%04x>", (int) c); return String.format("<%04x>", (int) c);
} }
return "" + c; return String.valueOf(c);
} }
public static boolean containsUpperCase(@NotNull String text) { public static boolean containsUpperCase(@NotNull String text) {
@@ -430,7 +427,6 @@ public class StringHelper {
case "esc": case "esc":
return VK_ESCAPE; return VK_ESCAPE;
case "bs": case "bs":
return VK_BACK_SPACE;
case "backspace": case "backspace":
return VK_BACK_SPACE; return VK_BACK_SPACE;
case "tab": case "tab":

View File

@@ -101,7 +101,7 @@ class ToKeysMappingInfo(
} }
class ToHandlerMappingInfo( class ToHandlerMappingInfo(
val extensionHandler: VimExtensionHandler, private val extensionHandler: VimExtensionHandler,
fromKeys: List<KeyStroke>, fromKeys: List<KeyStroke>,
isRecursive: Boolean, isRecursive: Boolean,
owner: MappingOwner owner: MappingOwner

View File

@@ -212,7 +212,7 @@ object VimListenerManager {
val document = editor.document val document = editor.document
if (SelectionVimListenerSuppressor.isNotLocked) { if (SelectionVimListenerSuppressor.isNotLocked) {
logger.info("Adjust non vim selection change") logger.debug("Adjust non vim selection change")
IdeaSelectionControl.controlNonVimSelectionChange(editor) IdeaSelectionControl.controlNonVimSelectionChange(editor)
} }

View File

@@ -213,7 +213,7 @@ public final class KeywordOption extends ListOption {
} else if (spec.isRange) { } else if (spec.isRange) {
return "[" + (char)spec.rangeLow.intValue() + "-" + (char)spec.rangeHigh.intValue() + "]"; return "[" + (char)spec.rangeLow.intValue() + "-" + (char)spec.rangeHigh.intValue() + "]";
} else { } else {
return (char)spec.rangeLow.intValue() + ""; return String.valueOf((char)spec.rangeLow.intValue());
} }
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.option; package com.maddyhome.idea.vim.option;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -30,7 +31,7 @@ import java.util.StringTokenizer;
* This is an option that accepts an arbitrary list of values * This is an option that accepts an arbitrary list of values
*/ */
public class ListOption extends TextOption { public class ListOption extends TextOption {
public static final @NotNull ListOption empty = new ListOption("", "", new String[0], ""); public static final @NotNull ListOption empty = new ListOption("", "", ArrayUtil.EMPTY_STRING_ARRAY, "");
/** /**
* Gets the value of the option as a comma separated list of values * Gets the value of the option as a comma separated list of values

View File

@@ -368,7 +368,7 @@ object OptionsManager {
object KeyModelOptionData { object KeyModelOptionData {
const val name = "keymodel" const val name = "keymodel"
const val abbr = "km" private const val abbr = "km"
const val startsel = "startsel" const val startsel = "startsel"
const val stopsel = "stopsel" const val stopsel = "stopsel"
@@ -384,7 +384,7 @@ object KeyModelOptionData {
object SelectModeOptionData { object SelectModeOptionData {
const val name = "selectmode" const val name = "selectmode"
const val abbr = "slm" private const val abbr = "slm"
const val mouse = "mouse" const val mouse = "mouse"
const val key = "key" const val key = "key"
@@ -433,14 +433,14 @@ object ClipboardOptionsData {
object IdeaJoinOptionsData { object IdeaJoinOptionsData {
const val name = "ideajoin" const val name = "ideajoin"
const val defaultValue = false private const val defaultValue = false
val option = ToggleOption(name, name, defaultValue) val option = ToggleOption(name, name, defaultValue)
} }
object IdeaMarkskOptionsData { object IdeaMarkskOptionsData {
const val name = "ideamarks" const val name = "ideamarks"
const val defaultValue = true private const val defaultValue = true
val option = ToggleOption(name, name, defaultValue) val option = ToggleOption(name, name, defaultValue)
} }

View File

@@ -4726,11 +4726,11 @@ public class RegExp {
private int regnzpar; /* \z() count. */ private int regnzpar; /* \z() count. */
private char re_has_z; /* \z item detected */ private char re_has_z; /* \z item detected */
private CharPointer regcode; /* Code-emit pointer */ private CharPointer regcode; /* Code-emit pointer */
private @NotNull boolean[] had_endbrace = new boolean[NSUBEXP]; /* flags, true if end of () found */ private boolean[] had_endbrace = new boolean[NSUBEXP]; /* flags, true if end of () found */
private int regflags; /* RF_ flags for prog */ private int regflags; /* RF_ flags for prog */
private @NotNull int[] brace_min = new int[10]; /* Minimums for complex brace repeats */ private int[] brace_min = new int[10]; /* Minimums for complex brace repeats */
private @NotNull int[] brace_max = new int[10]; /* Maximums for complex brace repeats */ private int[] brace_max = new int[10]; /* Maximums for complex brace repeats */
private @NotNull int[] brace_count = new int[10]; /* Current counts for complex brace repeats */ private int[] brace_count = new int[10]; /* Current counts for complex brace repeats */
private boolean had_eol; /* true when EOL found by vim_regcomp() */ private boolean had_eol; /* true when EOL found by vim_regcomp() */
private boolean one_exactly = false; /* only do one char for EXACTLY */ private boolean one_exactly = false; /* only do one char for EXACTLY */

View File

@@ -142,7 +142,7 @@ public class ExEditorKit extends DefaultEditorKit {
if (key != null) { if (key != null) {
final char c = key.getKeyChar(); final char c = key.getKeyChar();
if (c > 0) { if (c > 0) {
ActionEvent event = new ActionEvent(e.getSource(), e.getID(), "" + c, e.getWhen(), e.getModifiers()); ActionEvent event = new ActionEvent(e.getSource(), e.getID(), String.valueOf(c), e.getWhen(), e.getModifiers());
super.actionPerformed(event); super.actionPerformed(event);
target.saveLastEntry(); target.saveLastEntry();
} }

View File

@@ -331,14 +331,12 @@ public class ExOutputPanel extends JPanel {
myExOutputPanel.scrollHalfPage(); myExOutputPanel.scrollHalfPage();
break; break;
case 'q': case 'q':
case '\u001b':
myExOutputPanel.close(); myExOutputPanel.close();
break; break;
case '\n': case '\n':
myExOutputPanel.handleEnter(); myExOutputPanel.handleEnter();
break; break;
case '\u001b':
myExOutputPanel.close();
break;
case KeyEvent.CHAR_UNDEFINED: { case KeyEvent.CHAR_UNDEFINED: {
switch (e.getKeyCode()) { switch (e.getKeyCode()) {
case KeyEvent.VK_ENTER: case KeyEvent.VK_ENTER:

View File

@@ -49,7 +49,7 @@ import static java.lang.Math.min;
*/ */
public class ExTextField extends JTextField { public class ExTextField extends JTextField {
public final static String KEYMAP_NAME = "ex"; public static final String KEYMAP_NAME = "ex";
ExTextField() { ExTextField() {
// We need to store this in a field, because we can't trust getCaret(), as it will return an instance of // We need to store this in a field, because we can't trust getCaret(), as it will return an instance of
@@ -178,7 +178,7 @@ public class ExTextField extends JTextField {
VimPlugin.indicateError(); VimPlugin.indicateError();
} }
else { else {
histIndex = histIndex + dir; histIndex += dir;
String txt; String txt;
if (histIndex == history.size()) { if (histIndex == history.size()) {
txt = lastEntry; txt = lastEntry;
@@ -274,7 +274,7 @@ public class ExTextField extends JTextField {
// dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField, // dispatcher that checks that the plugin is enabled, checks that the component with the focus is ExTextField,
// dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed. // dispatch to ExEntryPanel#handleKey and if it's processed, mark the event as consumed.
if (currentAction != null) { if (currentAction != null) {
currentAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "" + c, modifiers)); currentAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, String.valueOf(c), modifiers));
} }
else { else {
KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED : KeyEvent event = new KeyEvent(this, keyChar != KeyEvent.CHAR_UNDEFINED ? KeyEvent.KEY_TYPED :

View File

@@ -94,13 +94,13 @@ class Widget(project: Project) : EditorBasedWidget(project), StatusBarWidget.Mul
override fun ID() = ShowCmd.ID override fun ID() = ShowCmd.ID
override fun getPresentation(): StatusBarWidget.WidgetPresentation? = this override fun getPresentation(): StatusBarWidget.WidgetPresentation = this
override fun getClickConsumer(): Consumer<MouseEvent>? = null override fun getClickConsumer(): Consumer<MouseEvent>? = null
override fun getTooltipText(): String { override fun getTooltipText(): String {
var count = ShowCmd.getFullText(this.editor) var count = ShowCmd.getFullText(this.editor)
if (!count.isBlank()) count = ": $count" if (count.isNotBlank()) count = ": $count"
return "${ShowCmd.displayName}$count" return "${ShowCmd.displayName}$count"
} }

View File

@@ -126,7 +126,7 @@ class VimStatusBar : StatusBarWidget, StatusBarWidget.IconPresentation {
popup.show(RelativePoint(component, at)) popup.show(RelativePoint(component, at))
} }
override fun getPresentation(): StatusBarWidget.WidgetPresentation? = this override fun getPresentation(): StatusBarWidget.WidgetPresentation = this
} }
class VimActions : DumbAwareAction() { class VimActions : DumbAwareAction() {

View File

@@ -86,12 +86,11 @@ public class VimEmulationConfigurable implements Configurable {
} }
private static final class VimSettingsPanel extends JPanel { private static final class VimSettingsPanel extends JPanel {
private final @NotNull VimShortcutConflictsTable myShortcutConflictsTable;
public VimSettingsPanel(@NotNull VimShortcutConflictsTable.Model model) { public VimSettingsPanel(@NotNull VimShortcutConflictsTable.Model model) {
myShortcutConflictsTable = new VimShortcutConflictsTable(model); VimShortcutConflictsTable shortcutConflictsTable = new VimShortcutConflictsTable(model);
setLayout(new BorderLayout()); setLayout(new BorderLayout());
final JScrollPane scrollPane = new JBScrollPane(myShortcutConflictsTable); final JScrollPane scrollPane = new JBScrollPane(shortcutConflictsTable);
scrollPane.setBorder(new LineBorder(JBColor.border())); scrollPane.setBorder(new LineBorder(JBColor.border()));
final JPanel conflictsPanel = new JPanel(new BorderLayout()); final JPanel conflictsPanel = new JPanel(new BorderLayout());
final String title = "Shortcut Conflicts for Active Keymap"; final String title = "Shortcut Conflicts for Active Keymap";

View File

@@ -31,12 +31,13 @@ import junit.framework.Assert
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal object NeovimTesting { internal object NeovimTesting {
lateinit var neovimApi: NeovimApi private lateinit var neovimApi: NeovimApi
lateinit var neovim: Process private lateinit var neovim: Process
fun setUp(test: VimTestCase) { fun setUp(test: VimTestCase) {
if (!neovimEnabled(test)) return if (!neovimEnabled(test)) return
val pb = ProcessBuilder("nvim", "-u", "NONE", "--embed", "--headless") val nvimPath = System.getenv("ideavim.nvim.path") ?: "nvim"
val pb = ProcessBuilder(nvimPath, "-u", "NONE", "--embed", "--headless")
neovim = pb.start() neovim = pb.start()
val neovimConnection = ProcessRPCConnection(neovim, true) val neovimConnection = ProcessRPCConnection(neovim, true)
neovimApi = NeovimApis.getApiForConnection(neovimConnection) neovimApi = NeovimApis.getApiForConnection(neovimConnection)
@@ -47,11 +48,11 @@ internal object NeovimTesting {
neovim.destroy() neovim.destroy()
} }
fun neovimEnabled(test: VimTestCase): Boolean { private fun neovimEnabled(test: VimTestCase): Boolean {
val method = test.javaClass.getMethod(test.name) val method = test.javaClass.getMethod(test.name)
return !method.isAnnotationPresent(VimBehaviorDiffers::class.java) return !method.isAnnotationPresent(VimBehaviorDiffers::class.java)
&& !method.isAnnotationPresent(TestWithoutNeovim::class.java) && !method.isAnnotationPresent(TestWithoutNeovim::class.java)
&& System.getProperty("ideavim.neovim.test", "false")!!.toBoolean() && System.getProperty("ideavim.nvim.test", "false")!!.toBoolean()
} }
fun setupEditor(editor: Editor, test: VimTestCase) { fun setupEditor(editor: Editor, test: VimTestCase) {

View File

@@ -94,7 +94,7 @@ abstract class VimTestCase : UsefulTestCase() {
NeovimTesting.setUp(this) NeovimTesting.setUp(this)
} }
protected val testDataPath: String private val testDataPath: String
get() = PathManager.getHomePath() + "/community/plugins/ideavim/testData" get() = PathManager.getHomePath() + "/community/plugins/ideavim/testData"
@Throws(Exception::class) @Throws(Exception::class)

View File

@@ -90,7 +90,7 @@ private class UselessMigration(from: Int) : ConfigMigrator {
} }
private class ConstantVersionDetector(private val version: Int) : VersionDetector { private class ConstantVersionDetector(private val version: Int) : VersionDetector {
override fun extractVersion(): Int? = version override fun extractVersion(): Int = version
companion object { companion object {
fun of(vararg versions: Int) = versions.map { ConstantVersionDetector(it) } fun of(vararg versions: Int) = versions.map { ConstantVersionDetector(it) }

View File

@@ -19,6 +19,7 @@
package org.jetbrains.plugins.ideavim.ex.handler; package org.jetbrains.plugins.ideavim.ex.handler;
import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.util.ArrayUtil;
import com.maddyhome.idea.vim.ex.ExOutputModel; import com.maddyhome.idea.vim.ex.ExOutputModel;
import org.jetbrains.plugins.ideavim.VimTestCase; import org.jetbrains.plugins.ideavim.VimTestCase;
@@ -75,6 +76,6 @@ public class ActionListCommandTest extends VimTestCase {
private String[] parseActionListOutput() { private String[] parseActionListOutput() {
String output = ExOutputModel.getInstance(myFixture.getEditor()).getText(); String output = ExOutputModel.getInstance(myFixture.getEditor()).getText();
return output == null ? new String[]{} : output.split("\n"); return output == null ? ArrayUtil.EMPTY_STRING_ARRAY : output.split("\n");
} }
} }

View File

@@ -23,6 +23,9 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser
import com.maddyhome.idea.vim.extension.Alias
import com.maddyhome.idea.vim.extension.ExtensionBeanClass
import com.maddyhome.idea.vim.extension.VimExtension 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
@@ -38,48 +41,64 @@ import org.jetbrains.plugins.ideavim.VimTestCase
class OpMappingTest : VimTestCase() { class OpMappingTest : VimTestCase() {
private var initialized = false private var initialized = false
private val extension = TestExtension() private lateinit var extension: ExtensionBeanClass
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
if (!initialized) { if (!initialized) {
initialized = true initialized = true
extension = TestExtension.createBean()
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).registerExtension(extension) VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
enableExtensions("TestExtension") enableExtensions("TestExtension")
} }
} }
override fun tearDown() {
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
super.tearDown()
}
@TestWithoutNeovim(SkipNeovimReason.PLUGIN) @TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test simple delete`() { fun `test simple delete`() {
doTest("dI", doTest(
"dI",
"${c}I found it in a legendary land", "${c}I found it in a legendary land",
"${c}nd it in a legendary land", "${c}nd it in a legendary land",
CommandState.Mode.COMMAND, CommandState.Mode.COMMAND,
CommandState.SubMode.NONE) CommandState.SubMode.NONE
)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN) @TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test simple delete backwards`() { fun `test simple delete backwards`() {
doTest("dP", doTest(
"dP",
"I found ${c}it in a legendary land", "I found ${c}it in a legendary land",
"I f${c}it in a legendary land", "I f${c}it in a legendary land",
CommandState.Mode.COMMAND, CommandState.Mode.COMMAND,
CommandState.SubMode.NONE) CommandState.SubMode.NONE
)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN) @TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test delete emulate inclusive`() { fun `test delete emulate inclusive`() {
doTest("dU", doTest(
"dU",
"${c}I found it in a legendary land", "${c}I found it in a legendary land",
"${c}d it in a legendary land", "${c}d it in a legendary land",
CommandState.Mode.COMMAND, CommandState.Mode.COMMAND,
CommandState.SubMode.NONE) CommandState.SubMode.NONE
)
} }
@TestWithoutNeovim(SkipNeovimReason.PLUGIN) @TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test linewise delete`() { fun `test linewise delete`() {
doTest("dO", doTest(
"dO",
""" """
A Discovery A Discovery
@@ -95,7 +114,8 @@ class OpMappingTest : VimTestCase() {
hard by the torrent of a mountain pass. hard by the torrent of a mountain pass.
""".trimIndent(), """.trimIndent(),
CommandState.Mode.COMMAND, CommandState.Mode.COMMAND,
CommandState.SubMode.NONE) CommandState.SubMode.NONE
)
} }
fun `test disable extension via set`() { fun `test disable extension via set`() {
@@ -118,14 +138,14 @@ class OpMappingTest : VimTestCase() {
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).unregisterExtension(TestExtension::class.java) VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.owner)) assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner))
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).registerExtension(extension) VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.owner)) assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner))
enableExtensions("TestExtension") enableExtensions("TestExtension")
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I ${c}found it in a legendary land") myFixture.checkResult("I ${c}found it in a legendary land")
@@ -138,7 +158,7 @@ class OpMappingTest : VimTestCase() {
enterCommand("set noTestExtension") enterCommand("set noTestExtension")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).unregisterExtension(TestExtension::class.java) VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@@ -150,12 +170,73 @@ class OpMappingTest : VimTestCase() {
} }
} }
class PlugExtensionsTest : VimTestCase() {
private lateinit var extension: ExtensionBeanClass
override fun setUp() {
super.setUp()
extension = TestExtension.createBean()
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
}
override fun tearDown() {
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
super.tearDown()
}
fun `test enable via plug`() {
VimScriptParser.executeText("Plug 'MyTest'")
assertTrue(extension.ext.initialized)
}
fun `test enable via plugin`() {
VimScriptParser.executeText("Plugin 'MyTest'")
assertTrue(extension.ext.initialized)
}
fun `test enable via plug and disable via set`() {
VimScriptParser.executeText(
"Plug 'MyTest'",
"set noTestExtension"
)
assertTrue(extension.ext.initialized)
assertTrue(extension.ext.disposed)
}
}
private val ExtensionBeanClass.ext: TestExtension
get() = this.handler as TestExtension
private class TestExtension : VimExtension { private class TestExtension : VimExtension {
var initialized = false
var disposed = false
override fun getName(): String = "TestExtension" override fun getName(): String = "TestExtension"
override fun init() { override fun init() {
putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionEmulateInclusive"), owner, MoveEmulateInclusive(), false) initialized = true
putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionBackwardsCharacter"), owner, MoveBackwards(), false) putExtensionHandlerMapping(
MappingMode.O,
parseKeys("<Plug>TestExtensionEmulateInclusive"),
owner,
MoveEmulateInclusive(),
false
)
putExtensionHandlerMapping(
MappingMode.O,
parseKeys("<Plug>TestExtensionBackwardsCharacter"),
owner,
MoveBackwards(),
false
)
putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionCharacter"), owner, Move(), false) putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionCharacter"), owner, Move(), false)
putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionLinewise"), owner, MoveLinewise(), false) putExtensionHandlerMapping(MappingMode.O, parseKeys("<Plug>TestExtensionLinewise"), owner, MoveLinewise(), false)
putExtensionHandlerMapping(MappingMode.N, parseKeys("<Plug>TestMotion"), owner, MoveLinewiseInNormal(), false) putExtensionHandlerMapping(MappingMode.N, parseKeys("<Plug>TestMotion"), owner, MoveLinewiseInNormal(), false)
@@ -167,6 +248,11 @@ private class TestExtension : VimExtension {
putKeyMapping(MappingMode.N, parseKeys("Q"), owner, parseKeys("<Plug>TestMotion"), true) putKeyMapping(MappingMode.N, parseKeys("Q"), owner, parseKeys("<Plug>TestMotion"), true)
} }
override fun dispose() {
disposed = true
super.dispose()
}
private class MoveEmulateInclusive : VimExtensionHandler { private class MoveEmulateInclusive : VimExtensionHandler {
override fun execute(editor: Editor, context: DataContext) { override fun execute(editor: Editor, context: DataContext) {
VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER) VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER)
@@ -204,4 +290,13 @@ private class TestExtension : VimExtension {
MotionGroup.moveCaret(editor, caret, newOffset) MotionGroup.moveCaret(editor, caret, newOffset)
} }
} }
companion object {
fun createBean(): ExtensionBeanClass {
val beanClass = ExtensionBeanClass()
beanClass.implementation = TestExtension::class.java.canonicalName
beanClass.aliases = listOf(Alias().also { it.name = "MyTest" })
return beanClass
}
}
} }

View File

@@ -114,7 +114,7 @@ class VimTextObjEntireExtensionTest : JavaVimTestCase() {
assertSelection(null) assertSelection(null)
} }
val poem: String = """Two roads diverged in a yellow wood, private val poem: String = """Two roads diverged in a yellow wood,
And sorry I could not travel both And sorry I could not travel both
And be one traveler, long I stood And be one traveler, long I stood
And looked down one as far as I could And looked down one as far as I could
@@ -138,7 +138,7 @@ Two roads diverged in a wood, and I—
I took the one less traveled by, I took the one less traveled by,
And that has made all the difference. And that has made all the difference.
""" """
val poemNoCaret = poem.replace("<caret>", "") private val poemNoCaret = poem.replace("<caret>", "")
val poemUC = poemNoCaret.toUpperCase() private val poemUC = poemNoCaret.toUpperCase()
val poemLC = poemNoCaret.toLowerCase() private val poemLC = poemNoCaret.toLowerCase()
} }

View File

@@ -142,13 +142,13 @@ class VimHighlightedYankTest : VimTestCase() {
} }
} }
val code = """ private val code = """
fun ${c}sum(x: Int, y: Int, z: Int): Int { fun ${c}sum(x: Int, y: Int, z: Int): Int {
return x + y + z return x + y + z
} }
""" """
val codeWithMultipleCurors = """ private val codeWithMultipleCurors = """
fun sum(x: ${c}Int, y: ${c}Int, z: ${c}Int): Int { fun sum(x: ${c}Int, y: ${c}Int, z: ${c}Int): Int {
return x + y + z return x + y + z
} }

View File

@@ -94,7 +94,6 @@ public class KeywordOptionTest extends VimTestCase {
public void testTwoAdjacentLettersAreInvalid() { public void testTwoAdjacentLettersAreInvalid() {
option.set("ab"); option.set("ab");
List<String> v = option.values();
assertDoesntContain(option.values(), new ArrayList<String>(){{add("ab");}}); assertDoesntContain(option.values(), new ArrayList<String>(){{add("ab");}});
} }