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

Compare commits

...

71 Commits

Author SHA1 Message Date
Alex Plate
3881b905be Update CHANGES.md 2020-11-12 10:51:57 +03:00
Alex Plate
073c62f868 Update version on TeamCity 2020-11-12 10:50:25 +03:00
Alex Plate
d8e0f26bea Revert "Unmute falling tests"
This reverts commit 0296cae7
2020-11-12 10:48:54 +03:00
Alex Plate
04c24ab5d0 Run manual tests 2020-11-12 10:38:02 +03:00
Alex Plate
bfb0ba1ab9 Update emulated plugins 2020-11-12 10:31:11 +03:00
Alex Plate
fb7d48af1f Update IDE actions section in README 2020-11-12 10:11:33 +03:00
Alex Plate
559989ce4b Remove all To Be Released labels 2020-11-12 10:03:56 +03:00
Alex Plate
81f59e3c18 Update plugin.xml 2020-11-12 10:03:04 +03:00
Alex Plate
b6adf9f7a9 Rename ideaenabledbufs to ideavimsupport 2020-11-12 09:45:29 +03:00
Alex Plate
b972a01cf0 Add merged PR to changes 2020-11-12 09:41:57 +03:00
Alex Plate
0296cae712 Unmute falling tests 2020-11-12 09:39:09 +03:00
Matt Ellis
c38b18e16b Prevent inlays causing scrolling to stick 2020-11-12 09:37:55 +03:00
Matt Ellis
8d65c3ed26 Limit how much of an inlay is shown when scrolling 2020-11-12 09:37:55 +03:00
Matt Ellis
995bb966ad Reposition cursor when scrolloff changes 2020-11-12 09:37:55 +03:00
Matt Ellis
dbda1a76ca [VIM-2158] Fix scrolling when scrolloff is greater than half screen height, but less than full screen height 2020-11-12 09:37:55 +03:00
Alex Plate
ed6f990d9a Remove some qodana inspections 2020-11-06 21:39:37 +03:00
Alex Plate
4f86d9cc77 Correct visual mode exiting when after line end 2020-11-06 20:26:26 +03:00
Alex Plate
d55774abab Use vimForEachCaret 2020-11-06 20:21:05 +03:00
Alex Plate
d5591ba08d Update qodana profile 2020-11-06 20:00:21 +03:00
Alex Plate
f67d483c4e Exclude next method from property based testing 2020-11-06 19:48:33 +03:00
Alex Plate
f26ddd4a27 Fix exception in aW 2020-11-06 19:12:40 +03:00
Alex Plate
dbbea642bc Add inspection profiles to the repository 2020-11-06 18:40:02 +03:00
Alex Plate
0539e39977 Fix <C-\><C-N> 2020-11-06 11:16:13 +03:00
Alex Plate
65235d32a1 Fix exception for ]b command 2020-11-06 10:36:03 +03:00
Alex Plate
ecfcdf5a8c Update intellij gradle plugin 2020-11-06 10:06:25 +03:00
Alex Plate
cf127ba7f9 Update plugin description 2020-11-06 09:37:01 +03:00
Alex Plate
1fba77d925 Update getName description 2020-11-05 11:31:41 +03:00
Alex Plate
5752b116f6 Fix plugin.xml 2020-11-04 13:04:36 +03:00
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
113 changed files with 1824 additions and 818 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

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
!/.idea/scopes !/.idea/scopes
!/.idea/copyright !/.idea/copyright
!/.idea/icon.png !/.idea/icon.png
!/.idea/inspectionProfiles
/build/ /build/
/out/ /out/

View File

@@ -0,0 +1,9 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool>
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

23
.idea/inspectionProfiles/Qodana.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<description>Inspections profile for Qodana</description>
<option name="myName" value="Qodana" />
<inspection_tool class="CanBeFinal" enabled="false" level="WARNING" enabled_by_default="false">
<option name="REPORT_CLASSES" value="false" />
<option name="REPORT_METHODS" value="false" />
<option name="REPORT_FIELDS" value="true" />
</inspection_tool>
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool>
<inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

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,70 +1,86 @@
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({
description = "Vim emulation plugin for the IntelliJ platform products" description = "Vim emulation plugin for the IntelliJ platform products"
vcsRoot(Branch_183) vcsRoot(Branch_183)
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)
buildType(TestsForIntelliJ20201) buildType(TestsForIntelliJ20201)
buildType(TestsForIntelliJ20191) buildType(TestsForIntelliJ20191)
buildType(TestsForIntelliJ20181) buildType(TestsForIntelliJ20181)
buildType(TestsForIntelliJ20192) buildType(TestsForIntelliJ20192)
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 {
id = "PROJECT_EXT_768" id = "PROJECT_EXT_768"
type = "CloudImage" type = "CloudImage"
param("use-spot-instances", "true") param("use-spot-instances", "true")
param("user-tags", "project=idea-vim") param("user-tags", "project=idea-vim")
param("agent_pool_id", "41") param("agent_pool_id", "41")
param("image-instances-limit", "") param("image-instances-limit", "")
param("subnet-id", "subnet-58839511") param("subnet-id", "subnet-58839511")
param("ebs-optimized", "false") param("ebs-optimized", "false")
param("instance-type", "c5d.large") param("instance-type", "c5d.large")
param("amazon-id", "ami-0d1a6a32faa92923e") param("amazon-id", "ami-0d1a6a32faa92923e")
param("spot-instance-price", "0.1") param("spot-instance-price", "0.1")
param("source-id", "BuildAgentsIdeaVim") param("source-id", "BuildAgentsIdeaVim")
param("image-name-prefix", "BuildAgentsIdeaVim") param("image-name-prefix", "BuildAgentsIdeaVim")
param("key-pair-name", "teamcity-prod-pub") param("key-pair-name", "teamcity-prod-pub")
param("security-group-ids", "sg-eda08696,sg-7332cf0f,") param("security-group-ids", "sg-eda08696,sg-7332cf0f,")
param("profileId", "amazon-48") param("profileId", "amazon-48")
}
feature {
id = "amazon-48"
type = "CloudProfile"
param("profileServerUrl", "")
param("secure:access-id", "credentialsJSON:dbcdb2a2-de5f-4bc9-9421-292b19e83947")
param("system.cloud.profile_id", "amazon-48")
param("total-work-time", "")
param("description", "")
param("cloud-code", "amazon")
param("enabled", "true")
param("max-running-instances", "10")
param("agentPushPreset", "")
param("profileId", "amazon-48")
param("name", "Cloud Agents")
param("next-hour", "")
param("secure:secret-key", "credentialsJSON:65a87fe7-0977-4af9-96f1-344f2b82d269")
param("region", "eu-west-1")
param("terminate-idle-time", "15")
param("not-checked", "")
}
} }
feature {
id = "amazon-48"
type = "CloudProfile"
param("profileServerUrl", "")
param("secure:access-id", "credentialsJSON:dbcdb2a2-de5f-4bc9-9421-292b19e83947")
param("system.cloud.profile_id", "amazon-48")
param("total-work-time", "")
param("description", "")
param("cloud-code", "amazon")
param("enabled", "true")
param("max-running-instances", "10")
param("agentPushPreset", "")
param("profileId", "amazon-48")
param("name", "Cloud Agents")
param("next-hour", "")
param("secure:secret-key", "credentialsJSON:65a87fe7-0977-4af9-96f1-344f2b82d269")
param("region", "eu-west-1")
param("terminate-idle-time", "15")
param("not-checked", "")
}
}
}) })

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
@@ -10,64 +11,64 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
object GitHubPullRequests : BuildType({ object GitHubPullRequests : BuildType({
name = "GitHub Pull Requests" name = "GitHub Pull Requests"
description = "Test GitHub pull requests" description = "Test GitHub pull requests"
params { params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.1") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.1")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
} }
vcs { vcs {
root(_Self.vcsRoots.GitHubPullRequest) root(_Self.vcsRoots.GitHubPullRequest)
checkoutMode = CheckoutMode.ON_SERVER checkoutMode = CheckoutMode.ON_SERVER
branchFilter = """ branchFilter = """
+:* +:*
-:<default> -:<default>
""".trimIndent() """.trimIndent()
} }
steps { steps {
gradle { gradle {
tasks = "clean test" tasks = "clean test"
buildFile = "" buildFile = ""
enableStacktrace = true enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
} }
}
triggers { triggers {
vcs { vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
branchFilter = "" branchFilter = ""
}
} }
}
features { features {
pullRequests { pullRequests {
provider = github { provider = github {
authType = token { authType = token {
token = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f" token = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f"
}
filterTargetBranch = "refs/heads/master"
filterAuthorRole = PullRequests.GitHubRoleFilter.EVERYBODY
}
}
commitStatusPublisher {
vcsRootExtId = "${GitHubPullRequest.id}"
publisher = github {
githubUrl = "https://api.github.com"
authType = personalToken {
token = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f"
}
}
param("github_oauth_user", "AlexPl292")
} }
filterTargetBranch = "refs/heads/master"
filterAuthorRole = PullRequests.GitHubRoleFilter.EVERYBODY
}
} }
commitStatusPublisher {
vcsRootExtId = "${GitHubPullRequest.id}"
publisher = github {
githubUrl = "https://api.github.com"
authType = personalToken {
token = "credentialsJSON:43afd6e5-6ad5-4d12-a218-cf1547717a7f"
}
}
param("github_oauth_user", "AlexPl292")
}
}
requirements { requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8") noLessThanVer("teamcity.agent.jvm.version", "1.8")
} }
}) })

View File

@@ -2,49 +2,53 @@ 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 {
root(DslContext.settingsRoot)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
script {
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 {
tasks = "clean testWithNeovim"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs { vcs {
root(_Self.vcsRoots.Branch_Nvim) branchFilter = ""
checkoutMode = CheckoutMode.ON_SERVER
} }
}
steps { requirements {
script { noLessThanVer("teamcity.agent.jvm.version", "1.8")
scriptContent = "apt-get install neovim" }
}
gradle {
tasks = "--version"
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
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,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,36 +1,42 @@
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({
name = "Publish Release" name = "Publish Release"
description = "Build and publish IdeaVim plugin" description = "Build and publish IdeaVim plugin"
artifactRules = "build/distributions/*" artifactRules = "build/distributions/*"
buildNumberPattern = "0.60" buildNumberPattern = "0.61"
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(
param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan") "env.ORG_GRADLE_PROJECT_publishToken",
param("env.ORG_GRADLE_PROJECT_version", "%build.number%") "credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4",
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") label = "Password"
param("env.ORG_GRADLE_PROJECT_publishChannels", "default,eap") )
} param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan")
param("env.ORG_GRADLE_PROJECT_version", "%build.number%")
vcs { param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
root(DslContext.settingsRoot) param("env.ORG_GRADLE_PROJECT_publishChannels", "default,eap")
}
checkoutMode = CheckoutMode.ON_SERVER
} vcs {
root(DslContext.settingsRoot)
steps {
gradle { checkoutMode = CheckoutMode.ON_SERVER
tasks = "clean publishPlugin" }
buildFile = ""
enableStacktrace = true steps {
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") gradle {
} tasks = "clean publishPlugin"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
} }
}
}) })

View File

@@ -9,59 +9,67 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.ScheduleTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
object ReleaseEap : BuildType({ object ReleaseEap : BuildType({
name = "Publish EAP Build" name = "Publish EAP Build"
description = "Build and publish EAP of IdeaVim plugin" description = "Build and publish EAP of IdeaVim plugin"
artifactRules = "build/distributions/*" artifactRules = "build/distributions/*"
buildNumberPattern = "0.60.%build.counter%" buildNumberPattern = "0.61.%build.counter%"
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(
param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan") "env.ORG_GRADLE_PROJECT_publishToken",
param("env.ORG_GRADLE_PROJECT_version", "%build.number%") "credentialsJSON:ec1dc748-e289-47e1-88b6-f193d7999bf4",
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") label = "Token"
param("env.ORG_GRADLE_PROJECT_publishChannels", "eap") )
password("env.ORG_GRADLE_PROJECT_slackUrl", "credentialsJSON:a8ab8150-e6f8-4eaf-987c-bcd65eac50b5", label = "Slack Token") param("env.ORG_GRADLE_PROJECT_publishUsername", "vlan")
param("env.ORG_GRADLE_PROJECT_version", "%build.number%")
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_publishChannels", "eap")
password(
"env.ORG_GRADLE_PROJECT_slackUrl",
"credentialsJSON:a8ab8150-e6f8-4eaf-987c-bcd65eac50b5",
label = "Slack Token"
)
}
vcs {
root(DslContext.settingsRoot)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean publishPlugin slackEapNotification"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
} }
}
vcs { triggers {
root(DslContext.settingsRoot) schedule {
enabled = false
checkoutMode = CheckoutMode.ON_SERVER schedulingPolicy = daily {
hour = 22
}
branchFilter = ""
triggerBuild = onWatchedBuildChange {
buildType = "IdeaVim_TestsForIntelliJBranch146"
watchedBuildRule = ScheduleTrigger.WatchedBuildRule.LAST_SUCCESSFUL
watchedBuildBranchFilter = "<default>"
promoteWatchedBuild = false
}
} }
}
steps { features {
gradle { vcsLabeling {
tasks = "clean publishPlugin slackEapNotification" vcsRootId = "${DslContext.settingsRoot.id}"
buildFile = "" labelingPattern = "%system.build.number%-EAP"
enableStacktrace = true successfulOnly = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL") branchFilter = ""
}
}
triggers {
schedule {
enabled = false
schedulingPolicy = daily {
hour = 22
}
branchFilter = ""
triggerBuild = onWatchedBuildChange {
buildType = "IdeaVim_TestsForIntelliJBranch146"
watchedBuildRule = ScheduleTrigger.WatchedBuildRule.LAST_SUCCESSFUL
watchedBuildBranchFilter = "<default>"
promoteWatchedBuild = false
}
}
}
features {
vcsLabeling {
vcsRootId = "${DslContext.settingsRoot.id}"
labelingPattern = "%system.build.number%-EAP"
successfulOnly = true
branchFilter = ""
}
} }
}
}) })

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,43 +1,44 @@
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
object TestsForIntelliJ20183 : BuildType({ object TestsForIntelliJ20183 : BuildType({
name = "Tests for IntelliJ 2018.3" name = "Tests for IntelliJ 2018.3"
description = "branch 183" description = "branch 183"
params { params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true") param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2018.3") param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-2018.3")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8") param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_183)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
} }
}
triggers {
vcs { vcs {
root(_Self.vcsRoots.Branch_183) branchFilter = ""
checkoutMode = CheckoutMode.ON_SERVER
} }
}
steps { requirements {
gradle { noLessThanVer("teamcity.agent.jvm.version", "1.8")
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 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

@@ -5,8 +5,8 @@ package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_181 : GitVcsRoot({ object Branch_181 : GitVcsRoot({
name = "https://github.com/JetBrains/ideavim (branch 181)" name = "https://github.com/JetBrains/ideavim (branch 181)"
url = "https://github.com/JetBrains/ideavim.git" url = "https://github.com/JetBrains/ideavim.git"
branch = "181" branch = "181"
useMirrors = false useMirrors = false
}) })

View File

@@ -5,8 +5,8 @@ package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_183 : GitVcsRoot({ object Branch_183 : GitVcsRoot({
name = "https://github.com/JetBrains/ideavim (branch 183)" name = "https://github.com/JetBrains/ideavim (branch 183)"
url = "https://github.com/JetBrains/ideavim.git" url = "https://github.com/JetBrains/ideavim.git"
branch = "183" branch = "183"
useMirrors = false useMirrors = false
}) })

View File

@@ -5,8 +5,8 @@ package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_191_193 : GitVcsRoot({ object Branch_191_193 : GitVcsRoot({
name = "https://github.com/JetBrains/ideavim (branch 191-193)" name = "https://github.com/JetBrains/ideavim (branch 191-193)"
url = "https://github.com/JetBrains/ideavim.git" url = "https://github.com/JetBrains/ideavim.git"
branch = "191-193" branch = "191-193"
useMirrors = false useMirrors = false
}) })

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

@@ -3,10 +3,10 @@ package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object GitHubPullRequest : GitVcsRoot({ object GitHubPullRequest : GitVcsRoot({
name = "IdeaVim Pull Requests" name = "IdeaVim Pull Requests"
url = "git@github.com:JetBrains/ideavim.git" url = "git@github.com:JetBrains/ideavim.git"
branchSpec = "+:refs/(pull/*)/head" branchSpec = "+:refs/(pull/*)/head"
authMethod = uploadedKey { authMethod = uploadedKey {
uploadedKey = "Alex Plate TeamCity key" uploadedKey = "Alex Plate TeamCity key"
} }
}) })

View File

@@ -24,24 +24,42 @@ usual beta standards.
## To Be Released ## To Be Released
...
## 0.61, 2020-11-12
### Features: ### Features:
* Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`. * Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`.
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 ideavimsupport=` to disable IdeaVim in dialog editors.
Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors. * Reposition cursor when `scrolloff` changes
_Note for EAP users: the option name can be changed for the stable release_
### Fixes: ### Fixes:
* [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line * [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line
* [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template * [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template
* [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays * [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays
* [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays * [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays
* [VIM-2158](https://youtrack.jetbrains.com/issue/VIM-2158) Fix scrolling when `scrolloff` is over half screen height, but less than full height
### Merged PRs:
* [255](https://github.com/JetBrains/ideavim/pull/255) by [Matt Ellis](https://github.com/citizenmatt): Fix various scrolling issues
## 0.60, 2020-10-09 ## 0.60, 2020-10-09

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

@@ -11,7 +11,7 @@ IdeaVim
[![Gitter][gitter-svg]][gitter] [![Gitter][gitter-svg]][gitter]
[![Twitter][twitter-svg]][twitter] [![Twitter][twitter-svg]][twitter]
IdeaVim is a Vim emulation plugin for IDEs based on the IntelliJ Platform. IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
##### Contact maintainers: ##### Contact maintainers:
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM) * [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
@@ -188,42 +188,38 @@ Changes to the IDE
### Executing IDE Actions ### Executing IDE Actions
IdeaVim adds two commands for listing and executing arbitrary IDE actions as IdeaVim adds various commands for listing and executing arbitrary IDE actions as
Ex commands or via `:map` command mappings: Ex commands or via `:map` command mappings:
**Executing actions:**
* `:action {action_id}`
* Execute an action by id. Works from Ex command line.
* `<Action>(*action_id*)`
* For the mappings you can use a special `<Action>` keyword. Don't forget the parentheses.
**Finding actions:**
* `:actionlist [pattern]` * `:actionlist [pattern]`
* Find IDE actions by name or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`) * Find IDE actions by id or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
* `:action {name}`
* Execute an action named `NAME`
In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to * In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`). **[To Be Released]** extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`).
<details> <details>
<summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary> <summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary>
<img src="resources/readme/track_action_id.gif" alt="track actioin ids"/> <img src="resources/readme/track_action_id.gif" alt="track action ids"/>
</details> </details>
For the mappings you can use a special `<Action>` keyword. Use `<Action>(*action_id*)` to map keys to some action. Don't
forget the parentheses. This keyword works for insert mode as well. **[To Be Released]**
Examples: Examples:
```vim ```vim
" Map \r to the Reformat Code action " Map \r to the Reformat Code action
:map \r :action ReformatCode<CR> :map \r <Action>(ReformatCode)
" or
:map \r <Action>(ReformatCode) " [To Be Released]
" Map <leader>d to start debug " Map <leader>d to start debug
:map <leader>d :action Debug<CR> :map <leader>d <Action>(Debug)
" or
:map <leader>d <Action>(Debug) " [To Be Released]
" Map \b to toggle the breakpoint on the current line " Map \b to toggle the breakpoint on the current line
:map \b :action ToggleLineBreakpoint<CR> :map \b <Action>(ToggleLineBreakpoint)
" or
:map \b <Action>(ToggleLineBreakpoint) " [To Be Released]
``` ```
### Undo/Redo ### Undo/Redo

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.2'
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

@@ -4,7 +4,15 @@ Emulated Vim Plugins
IdeaVim extensions emulate plugins of the original Vim. In order to use IdeaVim extensions emulate plugins of the original Vim. In order to use
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`: IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
set <extension-name> ```
set <extension-name>
```
If you reuse your existing `.vimrc` file using `source ~/.vimrc`, IdeaVim can parse and enable plugins that are defined
using [vim-plug](https://github.com/junegunn/vim-plug) or [vundle](https://github.com/VundleVim/Vundle.vim).
No additional set commands in `~/.ideavimrc` are required.
If you'd like to disable some plugin that's enabled in `.vimrc`, you can use `set no<extension-name>`
in `~/.ideavimrc`.
Available extensions: Available extensions:
@@ -20,18 +28,52 @@ Available extensions:
## surround ## surround
* Setup: `set surround` * Setup: `set surround`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tpope/vim-surround'</code>
<br/>
<code>Plug 'tpope/vim-surround'</code>
<br/>
<code>Plug 'vim-surround'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1697'</code>
</details>
* Emulates [vim-surround](https://github.com/tpope/vim-surround) * Emulates [vim-surround](https://github.com/tpope/vim-surround)
* Commands: `ys`, `cs`, `ds`, `S` * Commands: `ys`, `cs`, `ds`, `S`
## multiple-cursors ## multiple-cursors
* Setup: `set multiple-cursors` * Setup: `set multiple-cursors`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/terryma/vim-multiple-cursors'</code>
<br/>
<code>Plug 'terryma/vim-multiple-cursors'</code>
<br/>
<code>Plug 'vim-multiple-cursors'</code>
</details>
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors) * Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>` * Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
## commentary ## commentary
* Setup: `set commentary` * Setup: `set commentary`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tpope/vim-commentary'</code>
<br/>
<code>Plug 'tpope/vim-commentary'</code>
<br/>
<code>Plug 'vim-commentary'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=3695'</code>
<br/>
<code>Plug 'tomtom/tcomment_vim'</code>
<br/>
<code>Plug 'tcomment_vim'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1173'</code>
</details>
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary) * Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
* Commands: `gcc`, `gc + motion`, `v_gc` * Commands: `gcc`, `gc + motion`, `v_gc`
* By [Daniel Leong](https://github.com/dhleong) * By [Daniel Leong](https://github.com/dhleong)
@@ -39,6 +81,22 @@ Available extensions:
## ReplaceWithRegister ## ReplaceWithRegister
* Setup: `set ReplaceWithRegister` * Setup: `set ReplaceWithRegister`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/vim-scripts/ReplaceWithRegister'</code>
<br/>
<code>Plug 'vim-scripts/ReplaceWithRegister'</code>
<br/>
<code>Plug 'ReplaceWithRegister'</code>
<br/>
<code>Plug 'https://github.com/inkarkat/vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'inkarkat/vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'vim-ReplaceWithRegister'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2703'</code>
</details>
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister) * Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
* Commands: `gr`, `grr` * Commands: `gr`, `grr`
* By [igrekster](https://github.com/igrekster) * By [igrekster](https://github.com/igrekster)
@@ -47,6 +105,16 @@ Available extensions:
* Setup: * Setup:
* `set argtextobj` * `set argtextobj`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/vim-scripts/argtextobj.vim'</code>
<br/>
<code>Plug 'vim-scripts/argtextobj.vim'</code>
<br/>
<code>Plug 'argtextobj.vim'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2699'</code>
</details>
* By default, only the arguments inside parenthesis are considered. To extend the functionality * By default, only the arguments inside parenthesis are considered. To extend the functionality
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
list of colon-separated pairs (same as VIM's `matchpairs` option), like list of colon-separated pairs (same as VIM's `matchpairs` option), like
@@ -59,6 +127,14 @@ Available extensions:
## exchange ## exchange
* Setup: `set exchange` * Setup: `set exchange`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/tommcdo/vim-exchange'</code>
<br/>
<code>Plug 'tommcdo/vim-exchange'</code>
<br/>
<code>Plug 'vim-exchange'</code>
</details>
* Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange) * Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange)
* Commands: `cx`, `cxx`, `X`, `cxc` * Commands: `cx`, `cxx`, `X`, `cxc`
* By [fan-tom](https://github.com/fan-tom) * By [fan-tom](https://github.com/fan-tom)
@@ -66,6 +142,16 @@ Available extensions:
## textobj-entire ## textobj-entire
* Setup: `set textobj-entire` * Setup: `set textobj-entire`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/kana/vim-textobj-entire'</code>
<br/>
<code>Plug 'kana/vim-textobj-entire'</code>
<br/>
<code>Plug 'vim-textobj-entire'</code>
<br/>
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2610'</code>
</details>
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire) * Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
* Additional text objects: `ae`, `ie` * Additional text objects: `ae`, `ie`
* By [Alexandre Grison](https://github.com/agrison) * By [Alexandre Grison](https://github.com/agrison)
@@ -74,6 +160,14 @@ Available extensions:
* Setup: * Setup:
* `set highlightedyank` * `set highlightedyank`
* <details>
<summary>Alternative vim-plug / vundle syntax</summary>
<code>Plug 'https://github.com/machakann/vim-highlightedyank'</code>
<br/>
<code>Plug 'machakann/vim-highlightedyank'</code>
<br/>
<code>Plug 'vim-highlightedyank'</code>
</details>
* if you want to optimize highlight duration, assign a time in milliseconds: * if you want to optimize highlight duration, assign a time in milliseconds:
`let g:highlightedyank_highlight_duration = "1000"` `let g:highlightedyank_highlight_duration = "1000"`
A negative number makes the highlight persistent. A negative number makes the highlight persistent.

View File

@@ -125,7 +125,7 @@ The following `:set` commands can appear in `~/.ideavimrc` or be set manually in
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>", "<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
"<C-J>", "<C-Q>" "<C-J>", "<C-Q>"
`ideaenabledbufs` `ideaenabledbufs` List of strings (default "dialog") [To Be Released] `ideavimsupport` `ideavimsupport` List of strings (default "dialog")
Define the list of additional buffers where IdeaVim is enabled. Define the list of additional buffers where IdeaVim is enabled.

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

@@ -1,19 +1,54 @@
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude"> <idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
<name>IdeaVim</name> <name>IdeaVim</name>
<id>IdeaVIM</id> <id>IdeaVIM</id>
<change-notes><![CDATA[ <change-notes>
<ul> &lt;h3&gt;Features:&lt;/h3&gt;
<li>Fix ESC in dialogs</li> &lt;br/&gt;
<li>Add option to disable IdeaVim in dialogs and single line editors</li> &lt;ul&gt;&lt;li&gt;Ability to map IDE actions via the &lt;code&gt;&amp;lt;Action&amp;gt;&lt;/code&gt; keyword. E.g.
<li>Ability to map IDE actions via the &lt;Action&gt; keyword.</li> &lt;code&gt;map &amp;lt;C-K&amp;gt; &amp;lt;Action&amp;gt;(CommentByLineComment)&lt;/code&gt;.
<li>"IdeaVim: track action Ids" command to find action ids for the :action command. Check out &lt;code&gt;README.md&lt;/code&gt; for the details.&lt;/li&gt;&lt;li&gt;&lt;code&gt;IdeaVim: track action
Enable this option in &quot;Search everywhere&quot; (double shift).</li> Ids&lt;/code&gt; command to find action ids for the &lt;code&gt;:action&lt;/code&gt; command.
</ul> Enable this option in &amp;quot;Search everywhere&amp;quot; (double shift).&lt;/li&gt;&lt;li&gt;Ability to enable
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p> extensions using &lt;code&gt;vim-plug&lt;/code&gt; or &lt;code&gt;vundle&lt;/code&gt; syntax.&lt;br /&gt;
]]></change-notes> E.g. to enable commentary extension you can use one of the following commands:&lt;pre&gt;&lt;code
class="language-vim"&gt;set commentary
Plug 'tpope/vim-commentary'
Plug 'https://github.com/tpope/vim-commentary'
Plugin 'tpope/vim-commentary'
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This approach is especially handy if you have &lt;code&gt;.vimrc&lt;/code&gt; with
plugins registered via &lt;code&gt;vim-plug&lt;/code&gt; or &lt;code&gt;vundle&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;
&lt;h3&gt;Changes:&lt;/h3&gt;
&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;Fix &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; for dialogs. Now &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;
will exit insert / visual mode and close the dialog from normal mode.&lt;/li&gt;&lt;li&gt;Add option to disable
IdeaVim in dialogs / single line editors. &lt;a href="https://youtrack.jetbrains.com/issue/VIM-765"&gt;VIM-765&lt;/a&gt;&lt;br
/&gt;
Use &lt;code&gt;set ideavimsupport=&lt;/code&gt; to disable IdeaVim in dialog editors. &lt;/li&gt;&lt;li&gt;Reposition
cursor when &lt;code&gt;scrolloff&lt;/code&gt; changes&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;
&lt;h3&gt;Fixes:&lt;/h3&gt;
&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2150"&gt;VIM-2150&lt;/a&gt; &lt;code&gt;Shift-D&lt;/code&gt;
should not delete an empty line&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2157"&gt;VIM-2157&lt;/a&gt;
Fix tab with an active template&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2156"&gt;VIM-2156&lt;/a&gt;
Correct up/down motions with inlays&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtrack.jetbrains.com/issue/VIM-2144"&gt;VIM-2144&lt;/a&gt;
Correct text position after block insert with inlays&lt;/li&gt;&lt;li&gt;&lt;a
href="https://youtrack.jetbrains.com/issue/VIM-2158"&gt;VIM-2158&lt;/a&gt; Fix scrolling when &lt;code&gt;scrolloff&lt;/code&gt;
is over half screen height, but less than full height&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;
&lt;p&gt;See also the complete &lt;a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md"&gt;changelog&lt;/a&gt;.&lt;/p&gt;
</change-notes>
<description><![CDATA[ <description><![CDATA[
<p>Vim emulation plug-in for IDEs based on the IntelliJ platform.</p> <p>Vim emulation plugin for IntelliJ Platform-based IDEs.</p>
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing, marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, window commands, etc.</p> <br/>
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing,
marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, Vim plugins, etc.</p>
<br/>
<p>See also:</p> <p>See also:</p>
<ul> <ul>
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li> <li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li>
@@ -38,7 +73,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

@@ -20,15 +20,29 @@ package com.maddyhome.idea.vim.action
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.getTopLevelEditor import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.vimForEachCaret
class ResetModeAction : VimActionHandler.SingleExecution() { class ResetModeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_WRITABLE override val type: Command.Type = Command.Type.OTHER_WRITABLE
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean { override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
val modeBeforeReset = editor.mode
KeyHandler.getInstance().fullReset(editor.getTopLevelEditor()) KeyHandler.getInstance().fullReset(editor.getTopLevelEditor())
if (modeBeforeReset == CommandState.Mode.INSERT) {
editor.vimForEachCaret { caret ->
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
MotionGroup.moveCaret(editor, caret, position)
}
}
return true return true
} }
} }

View File

@@ -128,7 +128,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
private fun isEnabledForEscape(editor: Editor): Boolean { private fun isEnabledForEscape(editor: Editor): Boolean {
return editor.isPrimaryEditor() return editor.isPrimaryEditor()
|| EditorHelper.isFileEditor(editor) && !editor.inNormalMode || EditorHelper.isFileEditor(editor) && !editor.inNormalMode
|| OptionsManager.ideaenabledbufs.contains("dialog") && !editor.inNormalMode || OptionsManager.ideavimsupport.contains("dialog") && !editor.inNormalMode
} }
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean { private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {

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

@@ -19,10 +19,14 @@ package com.maddyhome.idea.vim.action.motion.visual
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.exitVisualMode import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.getTopLevelEditor import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.vimForEachCaret
/** /**
* @author vlan * @author vlan
@@ -32,6 +36,16 @@ class VisualExitModeAction : VimActionHandler.SingleExecution() {
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean { override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
editor.getTopLevelEditor().exitVisualMode() editor.getTopLevelEditor().exitVisualMode()
// Should it be in [exitVisualMode]?
editor.vimForEachCaret { caret ->
val lineEnd = EditorHelper.getLineEndForOffset(editor, caret.offset)
if (lineEnd == caret.offset) {
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
MotionGroup.moveCaret(editor, caret, position)
}
}
return true return true
} }
} }

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()}" }
} }
@@ -178,7 +178,7 @@ class CommandState private constructor() {
executingCommand = null executingCommand = null
resetModes() resetModes()
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode)) commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
startDigraphSequence() digraphSequence.reset()
updateStatus() updateStatus()
} }

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,22 @@ 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 This property is not used anymore, but we'll remove it much later to keep the compatibility of IdeaVim
* extensions with previous versions of IdeaVim.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "0.65")
@NotNull String getName();
default MappingOwner getOwner() { default MappingOwner getOwner() {
return MappingOwner.Plugin.Companion.get(getName()); return MappingOwner.Plugin.Companion.get(getName());
@@ -40,5 +46,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 (isSet(name)) {
if (name != extensionInListener.name) continue extensionBean.handler.init()
if (isSet(name)) { logger.info("IdeaVim extension '$name' initialized")
extensionInListener.init() } else {
logger.info("IdeaVim extension '$name' initialized") extensionBean.handler.dispose()
} else {
extensionInListener.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

@@ -42,10 +42,12 @@ import com.maddyhome.idea.vim.handler.MotionActionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler; import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.option.NumberOption; import com.maddyhome.idea.vim.option.NumberOption;
import com.maddyhome.idea.vim.option.OptionChangeListener;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ExEntryPanel; import com.maddyhome.idea.vim.ui.ExEntryPanel;
import kotlin.Pair; import kotlin.Pair;
import kotlin.ranges.IntProgression; import kotlin.ranges.IntProgression;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -184,7 +186,7 @@ public class MotionGroup {
if (caretVisualLine < topVisualLine + scrollOffset) { if (caretVisualLine < topVisualLine + scrollOffset) {
newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset); newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset);
} }
else if (caretVisualLine >= bottomVisualLine - scrollOffset) { else if (caretVisualLine > bottomVisualLine - scrollOffset) {
newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset); newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
} }
else { else {
@@ -631,10 +633,10 @@ public class MotionGroup {
private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) { private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) {
// TODO: Make this work with soft wraps // TODO: Make this work with soft wraps
// Vim's algorithm works counts line heights for wrapped lines. We're using visual lines, which handles collapsed // Vim's algorithm works by counting line heights for wrapped lines. We're using visual lines, which handles
// folds, but treats soft wrapped lines as individual lines. // collapsed folds, but treats soft wrapped lines as individual lines.
// Ironically, after figuring out how Vim's algorithm works (although not *why*), it looks likely to be rewritten as // Ironically, after figuring out how Vim's algorithm works (although not *why*) and reimplementing, it looks likely
// a dumb line for line reimplementation. // that this needs to be replaced as a more or less dumb line for line rewrite.
final int topLine = getVisualLineAtTopOfScreen(editor); final int topLine = getVisualLineAtTopOfScreen(editor);
final int bottomLine = getVisualLineAtBottomOfScreen(editor); final int bottomLine = getVisualLineAtBottomOfScreen(editor);
@@ -642,7 +644,7 @@ public class MotionGroup {
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred // We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value(); final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
final int topBound = topLine + scrollOffset; final int topBound = topLine + scrollOffset;
final int bottomBound = Math.max(topBound + 1, bottomLine - scrollOffset); final int bottomBound = Math.max(topBound, bottomLine - scrollOffset);
// If we need to scroll the current line more than half a screen worth of lines then we just centre the new // If we need to scroll the current line more than half a screen worth of lines then we just centre the new
// current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line // current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line
@@ -650,7 +652,6 @@ public class MotionGroup {
// Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if // Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if
// the number of lines is less. I'm not sure what impact this has. // the number of lines is less. I'm not sure what impact this has.
final int height = bottomLine - topLine + 1; final int height = bottomLine - topLine + 1;
final int halfHeight = Math.max(2, (height / 2) - 1);
// Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean // Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean
// newLine = caretLine +/- MAX(sj, so) // newLine = caretLine +/- MAX(sj, so)
@@ -663,7 +664,7 @@ public class MotionGroup {
// (See move.c:scroll_cursor_top) // (See move.c:scroll_cursor_top)
// //
// When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again // When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again
// expands lines above and below the new bottom line, but calcualtes things a little differently. The total number // expands lines above and below the new bottom line, but calculates things a little differently. The total number
// of lines expanded is at least scrolljump and there must be at least scrolloff lines below. // of lines expanded is at least scrolljump and there must be at least scrolloff lines below.
// Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line. // Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line.
// If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra // If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra
@@ -678,10 +679,26 @@ public class MotionGroup {
// out correct scroll locations // out correct scroll locations
final int scrollJump = getScrollJump(editor, height); final int scrollJump = getScrollJump(editor, height);
if (caretLine < topBound) { // Unavoidable fudge value. Multiline rendered doc comments can mean we have very few actual lines, and scrolling
// can get stuck in a loop as we re-centre the cursor instead of actually moving it. But if we ignore all inlays
// and use the approximate screen height instead of the actual screen height (in lines), we make incorrect
// assumptions about the top/bottom line numbers and can scroll to the wrong location. E.g. if there are enough doc
// comments (String.java) it's possible to get 12 lines of actual code on screen. Given scrolloff=5, it's very easy
// to hit problems, and have (scrolloffset > height / 2) and scroll to the middle of the screen. We'll use this
// fudge value to make sure we're working with sensible values. Note that this problem doesn't affect code without
// block inlays as positioning the cursor in the middle of the screen always positions it in a deterministic manner,
// relative to other text in the file.
final int inlayAwareMinHeightFudge = getApproximateScreenHeight(editor) / 2;
// Note that while these calculations do the same thing that Vim does, it processes them differently. E.g. it
// optionally checks and moves the top line, then optionally checks the bottom line. This gives us the same results
// via the tests.
if (height > inlayAwareMinHeightFudge && scrollOffset > height / 2) {
scrollVisualLineToMiddleOfScreen(editor, caretLine);
} else if (caretLine < topBound) {
// Scrolling up, put the cursor at the top of the window (minus scrolloff) // Scrolling up, put the cursor at the top of the window (minus scrolloff)
// Initial approximation in move.c:update_topline // Initial approximation in move.c:update_topline (including same calculation for halfHeight)
if (topLine + scrollOffset - caretLine >= halfHeight) { if (topLine + scrollOffset - caretLine >= Math.max(2, (height / 2) - 1)) {
scrollVisualLineToMiddleOfScreen(editor, caretLine); scrollVisualLineToMiddleOfScreen(editor, caretLine);
} }
else { else {
@@ -692,9 +709,12 @@ public class MotionGroup {
final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset); final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset);
final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine); final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine);
// Used is set to the line height of caretLine, and then incremented by line height of the lines above and // Used is set to the line height of caretLine (1 or how many lines soft wraps take up), and then incremented by
// below caretLine (up to scrolloff or end of file) // the line heights of the lines above and below caretLine (up to scrolloff or end of file).
final int used = 1 + (newTopLine - topLine) + Math.min(scrollOffset, getVisualLineCount(editor) - topLine); // Our implementation ignores soft wrap line heights. Folds already have a line height of 1.
final int usedAbove = caretLine - newTopLine;
final int usedBelow = Math.min(scrollOffset, getVisualLineCount(editor) - caretLine);
final int used = 1 + usedAbove + usedBelow;
if (used > height) { if (used > height) {
scrollVisualLineToMiddleOfScreen(editor, caretLine); scrollVisualLineToMiddleOfScreen(editor, caretLine);
} }
@@ -1374,4 +1394,21 @@ public class MotionGroup {
return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd); return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd);
} }
} }
public static class ScrollOptionsChangeListener implements OptionChangeListener<String> {
public static ScrollOptionsChangeListener INSTANCE = new ScrollOptionsChangeListener();
@Contract(pure = true)
private ScrollOptionsChangeListener() {
}
@Override
public void valueChange(String oldValue, String newValue) {
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
if (UserDataManager.getVimEditorGroup(editor)) {
MotionGroup.scrollCaretIntoView(editor);
}
}
}
}
} }

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,11 +977,8 @@ 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

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

@@ -43,6 +43,12 @@ import static java.lang.Integer.max;
* This is a set of helper methods for working with editors. All line and column values are zero based. * This is a set of helper methods for working with editors. All line and column values are zero based.
*/ */
public class EditorHelper { public class EditorHelper {
// Set a max height on block inlays to be made visible at the top/bottom of a line when scrolling up/down. This
// mitigates the visible area bouncing around too much and even pushing the cursor line off screen with large
// multiline rendered doc comments, while still providing some visibility of the block inlay (e.g. Rider's single line
// Code Vision)
private static final int BLOCK_INLAY_MAX_LINE_HEIGHT = 3;
public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) { public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) {
return editor.getScrollingModel().getVisibleAreaOnScrollingFinished(); return editor.getScrollingModel().getVisibleAreaOnScrollingFinished();
} }
@@ -201,7 +207,7 @@ public class EditorHelper {
* @param editor The editor * @param editor The editor
* @return The number of screen lines * @return The number of screen lines
*/ */
private static int getApproximateScreenHeight(final @NotNull Editor editor) { public static int getApproximateScreenHeight(final @NotNull Editor editor) {
return getVisibleArea(editor).height / editor.getLineHeight(); return getVisibleArea(editor).height / editor.getLineHeight();
} }
@@ -641,7 +647,10 @@ public class EditorHelper {
* @return Returns true if the window was moved * @return Returns true if the window was moved
*/ */
public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) { public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) {
int y = EditorUtil.getVisualLineAreaStartY(editor, normalizeVisualLine(editor, visualLine));
final int inlayHeight = EditorUtil.getInlaysHeight(editor, visualLine, true);
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * editor.getLineHeight();
int y = editor.visualLineToY(visualLine) - Math.min(inlayHeight, maxInlayHeight);
// Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this, // Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this,
// but when we ask for the target location to move the caret to match, we'll get the incorrect value. // but when we ask for the target location to move the caret to match, we'll get the incorrect value.
@@ -653,7 +662,7 @@ public class EditorHelper {
// Get the max line number that can sit at the top of the screen // Get the max line number that can sit at the top of the screen
final int editorHeight = getVisibleArea(editor).height; final int editorHeight = getVisibleArea(editor).height;
final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight(); final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight();
final int yLastLine = editor.visualLineToY(EditorHelper.getLineCount(editor)); // last line + 1 final int yLastLine = editor.visualLineToY(getLineCount(editor)); // last line + 1
y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight); y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight);
} }
return scrollVertically(editor, y); return scrollVertically(editor, y);
@@ -662,21 +671,25 @@ public class EditorHelper {
/** /**
* Scrolls the editor to place the given visual line in the middle of the current window. * Scrolls the editor to place the given visual line in the middle of the current window.
* *
* <p>Snaps the line to the nearest standard line height grid, which gives a good position for both an odd and even
* number of lines and mimics what Vim does.</p>
*
* @param editor The editor to scroll * @param editor The editor to scroll
* @param visualLine The visual line to place in the middle of the current window * @param visualLine The visual line to place in the middle of the current window
*/ */
public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) { public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) {
int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine)); final int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
int lineHeight = editor.getLineHeight(); final int screenHeight = getVisibleArea(editor).height;
int height = getVisibleArea(editor).height; final int lineHeight = editor.getLineHeight();
scrollVertically(editor, y - ((height - lineHeight) / 2)); scrollVertically(editor, y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight));
} }
/** /**
* Scrolls the editor to place the given visual line at the bottom of the screen. * Scrolls the editor to place the given visual line at the bottom of the screen.
* *
* When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to place a * <p>When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to
* line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll to. * place a line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll
* to.</p>
* *
* @param editor The editor to scroll * @param editor The editor to scroll
* @param visualLine The visual line to place at the bottom of the current window * @param visualLine The visual line to place at the bottom of the current window
@@ -690,7 +703,12 @@ public class EditorHelper {
if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) { if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) {
exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight(); exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight();
} }
final int y = EditorUtil.getVisualLineAreaEndY(editor, normalizeVisualLine(editor, visualLine)) + exPanelHeight;
final int normalizedVisualLine = normalizeVisualLine(editor, visualLine);
final int lineHeight = editor.getLineHeight();
final int inlayHeight = EditorUtil.getInlaysHeight(editor, normalizedVisualLine, false);
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * lineHeight;
final int y = editor.visualLineToY(normalizedVisualLine) + lineHeight + Math.min(inlayHeight, maxInlayHeight) + exPanelHeight;
final Rectangle visibleArea = getVisibleArea(editor); final Rectangle visibleArea = getVisibleArea(editor);
return scrollVertically(editor, max(0, y - visibleArea.height)); return scrollVertically(editor, max(0, y - visibleArea.height));
} }
@@ -714,19 +732,19 @@ public class EditorHelper {
} }
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x; final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
EditorHelper.scrollHorizontally(editor, columnLeftX); scrollHorizontally(editor, columnLeftX);
} }
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) { public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn)); final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
final int screenWidth = EditorHelper.getVisibleArea(editor).width; final int screenWidth = getVisibleArea(editor).width;
// Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number // Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number
// of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is // of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts? // still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor); final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth); final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth);
EditorHelper.scrollHorizontally(editor, x); scrollHorizontally(editor, x);
} }
public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) { public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
@@ -751,8 +769,8 @@ public class EditorHelper {
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays // Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x; final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
final int screenWidth = EditorHelper.getVisibleArea(editor).width; final int screenWidth = getVisibleArea(editor).width;
EditorHelper.scrollHorizontally(editor, targetColumnRightX - screenWidth); scrollHorizontally(editor, targetColumnRightX - screenWidth);
} }
/** /**

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,26 +42,33 @@ 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.ideavimsupport.contains("singleline")
.apply { times += System.currentTimeMillis() to "first single line check" }
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|| (!OptionsManager.ideavimsupport.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.ideavimsupport.contains("dialog") && !OptionsManager.ideavimsupport.contains("dialoglegacy"))
&& (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this)) && (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this))
/** /**
@@ -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());
@@ -786,7 +786,7 @@ public class SearchHelper {
if (pos == size - 1 || if (pos == size - 1 ||
!Character.isLetter(chars.charAt(pos + 1)) || !Character.isLetter(chars.charAt(pos + 1)) ||
(Character.isUpperCase(chars.charAt(pos + 1)) && (Character.isUpperCase(chars.charAt(pos + 1)) &&
pos <= size - 2 && pos < size - 2 &&
Character.isLowerCase(chars.charAt(pos + 2)))) { Character.isLowerCase(chars.charAt(pos + 2)))) {
res = pos; res = pos;
found++; found++;
@@ -1375,7 +1375,7 @@ public class SearchHelper {
} }
if (goForward && anyNonWhitespace(editor, end, 1)) { if (goForward && anyNonWhitespace(editor, end, 1)) {
while (end < max && while (end + 1 < max &&
CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) { CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) {
end++; 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

@@ -106,6 +106,7 @@ object VimListenerManager {
OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE) OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE) OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.scrolloff.addOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener) OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener)
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance()) EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
@@ -116,6 +117,7 @@ object VimListenerManager {
OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE) OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE) OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
OptionsManager.scrolloff.removeOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener) OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener)
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener) EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
@@ -212,7 +214,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

@@ -88,7 +88,7 @@ object OptionsManager {
val ideastatusicon = addOption(BoundStringOption(IdeaStatusIcon.name, IdeaStatusIcon.name, IdeaStatusIcon.enabled, IdeaStatusIcon.allValues)) val ideastatusicon = addOption(BoundStringOption(IdeaStatusIcon.name, IdeaStatusIcon.name, IdeaStatusIcon.enabled, IdeaStatusIcon.allValues))
val ideastrictmode = addOption(ToggleOption("ideastrictmode", "ideastrictmode", false)) val ideastrictmode = addOption(ToggleOption("ideastrictmode", "ideastrictmode", false))
val ideawrite = addOption(BoundStringOption("ideawrite", "ideawrite", IdeaWriteData.all, IdeaWriteData.allValues)) val ideawrite = addOption(BoundStringOption("ideawrite", "ideawrite", IdeaWriteData.all, IdeaWriteData.allValues))
val ideaenabledbufs = addOption(BoundListOption("ideaenabledbufs", "ideaenabledbufs", arrayOf("dialog"), arrayOf("dialog", "singleline", "dialoglegacy"))) val ideavimsupport = addOption(BoundListOption("ideavimsupport", "ideavimsupport", arrayOf("dialog"), arrayOf("dialog", "singleline", "dialoglegacy")))
fun isSet(name: String): Boolean { fun isSet(name: String): Boolean {
val option = getOption(name) val option = getOption(name)
@@ -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

@@ -62,7 +62,7 @@
* |i_CTRL-Z| TO BE IMPLEMENTED * |i_CTRL-Z| TO BE IMPLEMENTED
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction} * |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction} * |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction} * |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED * |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
* |i_CTRL-]} TO BE IMPLEMENTED * |i_CTRL-]} TO BE IMPLEMENTED
* |i_CTRL-^| TO BE IMPLEMENTED * |i_CTRL-^| TO BE IMPLEMENTED

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

@@ -1,6 +1,6 @@
# Manual Tests # Manual Tests
## #1 [Last run: 2020-10-09] ## #1 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -14,7 +14,7 @@ Word is selected, block-caret is placed on the word end (offset = `word end - 1`
![](resources/manualTests/1.png) ![](resources/manualTests/1.png)
## #2 [Last run: 2020-10-09] ## #2 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -26,7 +26,7 @@ Last word is selected, block caret is placed on the word end without bouncing
![](resources/manualTests/2.png) ![](resources/manualTests/2.png)
## #3 [Last run: 2020-10-09] ## #3 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -38,7 +38,7 @@ Line is selected. Caret is placed on the line end
![](resources/manualTests/3.png) ![](resources/manualTests/3.png)
## #4 [Last run: 2020-10-09] ## #4 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -51,7 +51,7 @@ After mouse release, caret moves one character back and becomes block shape
![](resources/manualTests/4.gif) ![](resources/manualTests/4.gif)
## #5 [Last run: 2020-10-09] ## #5 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -65,7 +65,7 @@ After mouse release, caret moves one character back and becomes block shape
![](resources/manualTests/5.gif) ![](resources/manualTests/5.gif)
## #6 [Last run: 2020-10-09] ## #6 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -77,7 +77,7 @@ Line is selected, caret is on the first position
![](resources/manualTests/6.gif) ![](resources/manualTests/6.gif)
## #6 [Last run: 2020-10-09] ## #6 [Last run: 2020-11-12]
_Initial mode:_ NORMAL _Initial mode:_ NORMAL
@@ -94,7 +94,7 @@ Caret stays in _block_ shape with a normal mode
![](resources/manualTests/7.2.gif) ![](resources/manualTests/7.2.gif)
## #7 [Last run: 2020-10-09] ## #7 [Last run: 2020-11-12]
_Action:_ _Action:_
Turn emulation off and on Turn emulation off and on
@@ -102,7 +102,7 @@ Turn emulation off and on
_Result:_ _Result:_
Vim emulator works as expected Vim emulator works as expected
## #8 [Last run: 2020-10-09 ## #8 [Last run: 2020-11-12
_Action:_ _Action:_
Start up IJ with disabled emulator, turn it on Start up IJ with disabled emulator, turn it on
@@ -110,7 +110,7 @@ Start up IJ with disabled emulator, turn it on
_Result:_ _Result:_
Vim emulator works as expected Vim emulator works as expected
## #9 [Last run: 2020-10-09] ## #9 [Last run: 2020-11-12]
_Action:_ _Action:_
Wrap with if Wrap with if

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)
@@ -180,26 +180,30 @@ abstract class VimTestCase : UsefulTestCase() {
@JvmOverloads @JvmOverloads
protected fun setPositionAndScroll(scrollToLogicalLine: Int, caretLogicalLine: Int, caretLogicalColumn: Int = 0) { protected fun setPositionAndScroll(scrollToLogicalLine: Int, caretLogicalLine: Int, caretLogicalColumn: Int = 0) {
val scrolloff = min(OptionsManager.scrolloff.value(), screenHeight / 2)
// Note that it is possible to request a position which would be invalid under normal Vim!
// We disable scrolloff + scrolljump, position as requested, and reset. When resetting scrolloff, Vim will
// recalculate the correct offsets, and that could move the top and/or caret line
val scrolloff = OptionsManager.scrolloff.value()
val scrolljump = OptionsManager.scrolljump.value() val scrolljump = OptionsManager.scrolljump.value()
OptionsManager.scrolloff.set(0)
OptionsManager.scrolljump.set(1) OptionsManager.scrolljump.set(1)
// Convert to visual lines to handle any collapsed folds // Convert to visual lines to handle any collapsed folds
val scrollToVisualLine = EditorHelper.logicalLineToVisualLine(myFixture.editor, scrollToLogicalLine) val scrollToVisualLine = EditorHelper.logicalLineToVisualLine(myFixture.editor, scrollToLogicalLine)
val bottomVisualLine = scrollToVisualLine + screenHeight - 1 val bottomVisualLine = scrollToVisualLine + EditorHelper.getApproximateScreenHeight(myFixture.editor) - 1
val bottomLogicalLine = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine) val bottomLogicalLine = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine)
// Make sure we're not trying to put caret in an invalid location // Make sure we're not trying to put caret in an invalid location
val boundsTop = EditorHelper.visualLineToLogicalLine(myFixture.editor, val boundsTop = EditorHelper.visualLineToLogicalLine(myFixture.editor, scrollToVisualLine)
if (scrollToVisualLine > scrolloff) scrollToVisualLine + scrolloff else scrollToVisualLine) val boundsBottom = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine)
val boundsBottom = EditorHelper.visualLineToLogicalLine(myFixture.editor,
if (bottomVisualLine > EditorHelper.getVisualLineCount(myFixture.editor) - scrolloff - 1) bottomVisualLine - scrolloff else bottomVisualLine)
Assert.assertTrue("Caret line $caretLogicalLine not inside legal screen bounds (${boundsTop} - ${boundsBottom})", Assert.assertTrue("Caret line $caretLogicalLine not inside legal screen bounds (${boundsTop} - ${boundsBottom})",
caretLogicalLine in boundsTop..boundsBottom) caretLogicalLine in boundsTop..boundsBottom)
typeText(parseKeys("${scrollToLogicalLine+scrolloff+1}z<CR>", "${caretLogicalLine+1}G", "${caretLogicalColumn+1}|")) typeText(parseKeys("${scrollToLogicalLine+1}z<CR>", "${caretLogicalLine+1}G", "${caretLogicalColumn+1}|"))
OptionsManager.scrolljump.set(scrolljump) OptionsManager.scrolljump.set(scrolljump)
OptionsManager.scrolloff.set(scrolloff)
// Make sure we're where we want to be // Make sure we're where we want to be
assertVisibleArea(scrollToLogicalLine, bottomLogicalLine) assertVisibleArea(scrollToLogicalLine, bottomLogicalLine)

View File

@@ -25,6 +25,7 @@ import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
public class ReformatCodeTest extends VimTestCase { public class ReformatCodeTest extends VimTestCase {
/* /*
[VERSION UPDATE] 2020.2+
public void testEmpty() { public void testEmpty() {
configureByJavaText("<caret>"); configureByJavaText("<caret>");
typeText(parseKeys("gqq")); typeText(parseKeys("gqq"));

Some files were not shown because too many files have changed in this diff Show More