mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c656da5c75 | ||
![]() |
dcedf6abca | ||
![]() |
849a71bdac | ||
![]() |
534cc1d1fe | ||
![]() |
40ec6c53fa | ||
![]() |
b7cb3c0945 | ||
![]() |
69d3c7b754 | ||
![]() |
542f11804e | ||
![]() |
8526054aa8 | ||
![]() |
93700bddc7 | ||
![]() |
494500041b | ||
![]() |
011a5a3b23 | ||
![]() |
03726858f0 | ||
![]() |
c8c42cc4b2 | ||
![]() |
0b22b454e6 | ||
![]() |
f4fe03c582 | ||
![]() |
964e87fd6a | ||
![]() |
ec4c0a0d0d |
@@ -18,7 +18,7 @@
|
|||||||
<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>
|
||||||
<ID>LongMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
|
<ID>LongMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
|
||||||
<ID>LoopWithTooManyJumpStatements:SearchHighlightsHelper.kt$for (project in projectManager.openProjects) { val current = FileEditorManager.getInstance(project).selectedTextEditor ?: continue // [VERSION UPDATE] 202+ Use editors val editors = EditorFactory.getInstance().getEditors(current.document, project) ?: continue for (editor in editors) { // Try to keep existing highlights if possible. Update if hlsearch has changed or if the pattern has changed. // Force update for the situations where the text is the same, but the ignore case values have changed. // E.g. Use `*` to search for a word (which ignores smartcase), then use `/<Up>` to search for the same pattern, // which will match smartcase. Or changing the smartcase/ignorecase settings if (shouldRemoveSearchHighlights(editor, pattern, showHighlights) || forceUpdate) { removeSearchHighlights(editor) } if (pattern == null) continue if (shouldAddAllSearchHighlights(editor, pattern, showHighlights)) { // hlsearch (+ incsearch/noincsearch) val startLine = searchRange?.startLine ?: 0 val endLine = searchRange?.endLine ?: -1 val results = SearchGroup.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase)) if (results.isNotEmpty()) { currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards) highlightSearchResults(editor, pattern, results, currentMatchOffset) } editor.vimLastSearch = pattern } else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) { // nohlsearch + incsearch val searchOptions = EnumSet.of(SearchOptions.WHOLE_FILE) if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP) if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE) if (!forwards) searchOptions.add(SearchOptions.BACKWARDS) val result = SearchGroup.findIt(editor, pattern, initialOffset, 1, searchOptions) if (result != null) { currentMatchOffset = result.startOffset val results = listOf(result) highlightSearchResults(editor, pattern, results, currentMatchOffset) } } else if (shouldMaintainCurrentMatchOffset(pattern, initialOffset)) { // incsearch. If nothing has changed (e.g. we've edited offset values in `/foo/e+2`) make sure we return the // current match offset so the caret remains at the current incsarch match val offset = editor.vimIncsearchCurrentMatchOffset if (offset != null) { currentMatchOffset = offset } } } }</ID>
|
<ID>LoopWithTooManyJumpStatements:SearchHighlightsHelper.kt$for (project in projectManager.openProjects) { val current = FileEditorManager.getInstance(project).selectedTextEditor ?: continue // [VERSION UPDATE] 202+ Use editors val editors = EditorFactory.getInstance().getEditors(current.document, project) ?: continue for (editor in editors) { // Try to keep existing highlights if possible. Update if hlsearch has changed or if the pattern has changed. // Force update for the situations where the text is the same, but the ignore case values have changed. // E.g. Use `*` to search for a word (which ignores smartcase), then use `/<Up>` to search for the same pattern, // which will match smartcase. Or changing the smartcase/ignorecase settings if (shouldRemoveSearchHighlights(editor, pattern, showHighlights) || forceUpdate) { removeSearchHighlights(editor) } if (pattern == null) continue if (shouldAddAllSearchHighlights(editor, pattern, showHighlights)) { // hlsearch (+ incsearch/noincsearch) val startLine = searchRange?.startLine ?: 0 val endLine = searchRange?.endLine ?: -1 val results = SearchHelper.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase)) if (results.isNotEmpty()) { currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards) highlightSearchResults(editor, pattern, results, currentMatchOffset) } editor.vimLastSearch = pattern } else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) { // nohlsearch + incsearch val searchOptions = EnumSet.of(SearchOptions.WHOLE_FILE) if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP) if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE) if (!forwards) searchOptions.add(SearchOptions.BACKWARDS) val result = SearchHelper.findPattern(editor, pattern, initialOffset, 1, searchOptions) if (result != null) { currentMatchOffset = result.startOffset val results = listOf(result) highlightSearchResults(editor, pattern, results, currentMatchOffset) } } else if (shouldMaintainCurrentMatchOffset(pattern, initialOffset)) { // incsearch. If nothing has changed (e.g. we've edited offset values in `/foo/e+2`) make sure we return the // current match offset so the caret remains at the current incsarch match val offset = editor.vimIncsearchCurrentMatchOffset if (offset != null) { currentMatchOffset = offset } } } }</ID>
|
||||||
<ID>MagicNumber:ActionListHandler.kt$ActionListHandler$50</ID>
|
<ID>MagicNumber:ActionListHandler.kt$ActionListHandler$50</ID>
|
||||||
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$0.9f</ID>
|
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$0.9f</ID>
|
||||||
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$1.75f</ID>
|
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$1.75f</ID>
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
<ID>MagicNumber:CommandBuilder.kt$CommandBuilder$999999999</ID>
|
<ID>MagicNumber:CommandBuilder.kt$CommandBuilder$999999999</ID>
|
||||||
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$6</ID>
|
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$6</ID>
|
||||||
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$7</ID>
|
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$7</ID>
|
||||||
<ID>MagicNumber:EditorHelper.kt$10</ID>
|
|
||||||
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x05</ID>
|
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x05</ID>
|
||||||
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x08</ID>
|
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x08</ID>
|
||||||
<ID>MagicNumber:HistoryHandler.kt$HistoryHandler$7</ID>
|
<ID>MagicNumber:HistoryHandler.kt$HistoryHandler$7</ID>
|
||||||
@@ -65,8 +64,7 @@
|
|||||||
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$3</ID>
|
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$3</ID>
|
||||||
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$4</ID>
|
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$4</ID>
|
||||||
<ID>MatchingDeclarationName:CommandDefinition.kt$CommandName</ID>
|
<ID>MatchingDeclarationName:CommandDefinition.kt$CommandName</ID>
|
||||||
<ID>MatchingDeclarationName:SearchHelperKt.kt$Direction</ID>
|
<ID>MaxLineLength:ExBeanClass.kt$ExBeanClass$logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: ${this.pluginDescriptor.pluginId}")</ID>
|
||||||
<ID>MaxLineLength:ExBeanClass.kt$ExBeanClass$logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: $pluginId")</ID>
|
|
||||||
<ID>MaxLineLength:ExRanges.kt$SearchRange$override</ID>
|
<ID>MaxLineLength:ExRanges.kt$SearchRange$override</ID>
|
||||||
<ID>MaxLineLength:NotificationService.kt$NotificationService$notification.addAction(AppendToIdeaVimRcAction(notification, "set clipboard+=ideaput", "ideaput") { OptionsManager.clipboard.append(ClipboardOptionsData.ideaput) })</ID>
|
<ID>MaxLineLength:NotificationService.kt$NotificationService$notification.addAction(AppendToIdeaVimRcAction(notification, "set clipboard+=ideaput", "ideaput") { OptionsManager.clipboard.append(ClipboardOptionsData.ideaput) })</ID>
|
||||||
<ID>MaxLineLength:NotificationService.kt$NotificationService.AppendToIdeaVimRcAction$private inner</ID>
|
<ID>MaxLineLength:NotificationService.kt$NotificationService.AppendToIdeaVimRcAction$private inner</ID>
|
||||||
|
6
.teamcity/_Self/Project.kt
vendored
6
.teamcity/_Self/Project.kt
vendored
@@ -18,6 +18,7 @@ import _Self.buildTypes.TestsForIntelliJEAP
|
|||||||
import _Self.vcsRoots.Branch_181
|
import _Self.vcsRoots.Branch_181
|
||||||
import _Self.vcsRoots.Branch_183
|
import _Self.vcsRoots.Branch_183
|
||||||
import _Self.vcsRoots.Branch_191_193
|
import _Self.vcsRoots.Branch_191_193
|
||||||
|
import _Self.vcsRoots.Branch_201
|
||||||
import _Self.vcsRoots.GitHubPullRequest
|
import _Self.vcsRoots.GitHubPullRequest
|
||||||
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
|
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
|
||||||
|
|
||||||
@@ -26,15 +27,15 @@ object Project : Project({
|
|||||||
|
|
||||||
vcsRoot(Branch_183)
|
vcsRoot(Branch_183)
|
||||||
vcsRoot(Branch_181)
|
vcsRoot(Branch_181)
|
||||||
vcsRoot(GitHubPullRequest)
|
|
||||||
vcsRoot(Branch_191_193)
|
vcsRoot(Branch_191_193)
|
||||||
|
vcsRoot(Branch_201)
|
||||||
|
vcsRoot(GitHubPullRequest)
|
||||||
|
|
||||||
buildType(GitHubPullRequests)
|
buildType(GitHubPullRequests)
|
||||||
|
|
||||||
buildType(Release)
|
buildType(Release)
|
||||||
buildType(ReleaseEap)
|
buildType(ReleaseEap)
|
||||||
|
|
||||||
buildType(TestsForIntelliJ20201)
|
|
||||||
buildType(TestsForIntelliJ20202)
|
buildType(TestsForIntelliJ20202)
|
||||||
buildType(TestsForIntelliJ20203)
|
buildType(TestsForIntelliJ20203)
|
||||||
buildType(TestsForIntelliJEAP)
|
buildType(TestsForIntelliJEAP)
|
||||||
@@ -42,6 +43,7 @@ object Project : Project({
|
|||||||
buildType(Nvim)
|
buildType(Nvim)
|
||||||
buildType(PluginVerifier)
|
buildType(PluginVerifier)
|
||||||
|
|
||||||
|
buildType(TestsForIntelliJ20201)
|
||||||
buildType(TestsForIntelliJ20191)
|
buildType(TestsForIntelliJ20191)
|
||||||
buildType(TestsForIntelliJ20181)
|
buildType(TestsForIntelliJ20181)
|
||||||
buildType(TestsForIntelliJ20192)
|
buildType(TestsForIntelliJ20192)
|
||||||
|
1
.teamcity/_Self/buildTypes/ActiveTests.kt
vendored
1
.teamcity/_Self/buildTypes/ActiveTests.kt
vendored
@@ -43,4 +43,3 @@ sealed class ActiveTests(buildName: String, ijVersion: String) : BuildType({
|
|||||||
object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT")
|
object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT")
|
||||||
object TestsForIntelliJ20203 : ActiveTests("Tests for IntelliJ 2020.3", "2020.3")
|
object TestsForIntelliJ20203 : ActiveTests("Tests for IntelliJ 2020.3", "2020.3")
|
||||||
object TestsForIntelliJ20202 : ActiveTests("Tests for IntelliJ 2020.2", "2020.2")
|
object TestsForIntelliJ20202 : ActiveTests("Tests for IntelliJ 2020.2", "2020.2")
|
||||||
object TestsForIntelliJ20201 : ActiveTests("Tests for IntelliJ 2020.1", "2020.1")
|
|
||||||
|
2
.teamcity/_Self/buildTypes/Release.kt
vendored
2
.teamcity/_Self/buildTypes/Release.kt
vendored
@@ -10,7 +10,7 @@ object Release : BuildType({
|
|||||||
description = "Build and publish IdeaVim plugin"
|
description = "Build and publish IdeaVim plugin"
|
||||||
|
|
||||||
artifactRules = "build/distributions/*"
|
artifactRules = "build/distributions/*"
|
||||||
buildNumberPattern = "0.62"
|
buildNumberPattern = "0.64"
|
||||||
|
|
||||||
params {
|
params {
|
||||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||||
|
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
@@ -13,7 +13,7 @@ object ReleaseEap : BuildType({
|
|||||||
description = "Build and publish EAP of IdeaVim plugin"
|
description = "Build and publish EAP of IdeaVim plugin"
|
||||||
|
|
||||||
artifactRules = "build/distributions/*"
|
artifactRules = "build/distributions/*"
|
||||||
buildNumberPattern = "0.62.%build.counter%"
|
buildNumberPattern = "0.64.%build.counter%"
|
||||||
|
|
||||||
params {
|
params {
|
||||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||||
|
46
.teamcity/_Self/buildTypes/TestsForIntelliJ_201.kt
vendored
Normal file
46
.teamcity/_Self/buildTypes/TestsForIntelliJ_201.kt
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
@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_201_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_201)
|
||||||
|
|
||||||
|
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 TestsForIntelliJ20201 : TestsForIntelliJ_201_branch("2020.1")
|
12
.teamcity/_Self/vcsRoots/Branch_201.kt
vendored
Normal file
12
.teamcity/_Self/vcsRoots/Branch_201.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
@file:Suppress("ClassName")
|
||||||
|
|
||||||
|
package _Self.vcsRoots
|
||||||
|
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
|
||||||
|
|
||||||
|
object Branch_201 : GitVcsRoot({
|
||||||
|
name = "https://github.com/JetBrains/ideavim (branch 201)"
|
||||||
|
url = "https://github.com/JetBrains/ideavim.git"
|
||||||
|
branch = "201"
|
||||||
|
useMirrors = false
|
||||||
|
})
|
@@ -335,6 +335,10 @@ Contributors:
|
|||||||
[![icon][github]](https://github.com/shaunpatterson)
|
[![icon][github]](https://github.com/shaunpatterson)
|
||||||
|
|
||||||
Shaun Patterson
|
Shaun Patterson
|
||||||
|
* [![icon][mail]](mailto:vladimir.petrenko@jetbrains.com)
|
||||||
|
[![icon][github]](https://github.com/vladimir-petrenko)
|
||||||
|
|
||||||
|
Vladimir Petrenko
|
||||||
|
|
||||||
If you are a contributor and your name is not listed here, feel free to
|
If you are a contributor and your name is not listed here, feel free to
|
||||||
contact the maintainers.
|
contact the maintainers.
|
||||||
|
19
CHANGES.md
19
CHANGES.md
@@ -22,6 +22,25 @@ It is important to distinguish EAP from traditional pre-release software.
|
|||||||
Please note that the quality of EAP versions may at times be way below even
|
Please note that the quality of EAP versions may at times be way below even
|
||||||
usual beta standards.
|
usual beta standards.
|
||||||
|
|
||||||
|
## 0.64, 2020-12-23
|
||||||
|
|
||||||
|
### Merged PRs:
|
||||||
|
* [260](https://github.com/JetBrains/ideavim/pull/260) by [Matt Ellis](https://github.com/citizenmatt): Refactor SearchGroup
|
||||||
|
|
||||||
|
### Fixes:
|
||||||
|
* [VIM-2194](https://youtrack.jetbrains.com/issue/VIM-2194) Fix caret shape during editing a new file
|
||||||
|
|
||||||
|
## 0.63, 2020-12-16
|
||||||
|
|
||||||
|
### Changes:
|
||||||
|
* Update the minimal required IJ version: 2020.2+
|
||||||
|
|
||||||
|
### Fixes:
|
||||||
|
* [CWM-927](https://youtrack.jetbrains.com/issue/CWM-927) Fix typing for CodeWithMe and IdeaVim
|
||||||
|
|
||||||
|
### Merged PRs:
|
||||||
|
* [259](https://github.com/JetBrains/ideavim/pull/259) by [Vladimir Petrenko](https://github.com/vladimir-petrenko): CWM-927 disable vim for client's hidden editor on host
|
||||||
|
|
||||||
## 0.62, 2020-12-15
|
## 0.62, 2020-12-15
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
|
@@ -59,7 +59,7 @@ runIdeForUiTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runPluginVerifier {
|
runPluginVerifier {
|
||||||
ideVersions = ["IC-2020.1.4", "IC-2020.2.3"]
|
ideVersions = ["IC-2020.2.3", "IC-2020.3"]
|
||||||
downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
|
downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
|
||||||
teamCityOutputFormat = true
|
teamCityOutputFormat = true
|
||||||
}
|
}
|
||||||
|
@@ -2,63 +2,20 @@
|
|||||||
<name>IdeaVim</name>
|
<name>IdeaVim</name>
|
||||||
<id>IdeaVIM</id>
|
<id>IdeaVIM</id>
|
||||||
<change-notes><![CDATA[
|
<change-notes><![CDATA[
|
||||||
<h3>Features:</h3>
|
<h3>Merged PRs:</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Support <code>unmap</code> and <code>mapclear</code> commands <a
|
<li>
|
||||||
href="https://youtrack.jetbrains.com/issue/VIM-1491">VIM-1491</a></li>
|
<a href="https://github.com/JetBrains/ideavim/pull/260">260</a>
|
||||||
<li>Support mappings in ex panel (<code>cmap</code>) <a
|
by <a href="https://github.com/citizenmatt">Matt Ellis</a>: Refactor SearchGroup
|
||||||
href="https://youtrack.jetbrains.com/issue/VIM-1227">VIM-1227</a></li>
|
</li>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Changes:</h3>
|
|
||||||
<ul>
|
|
||||||
<li><code>octal</code> is now disabled by default for <code>nrformats</code>. <a
|
|
||||||
href="https://youtrack.jetbrains.com/issue/VIM-2181">VIM-2181</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Fixes:</h3>
|
<h3>Fixes:</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2113">VIM-2113</a> Fix <code>cit</code> for empty tags</li>
|
<li>
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2114">VIM-2114</a> Unnamed register isn't changed after deleting
|
<a href="https://youtrack.jetbrains.com/issue/VIM-2194">VIM-2194</a>
|
||||||
empty tag
|
Fix caret shape during editing a new file
|
||||||
</li>
|
</li>
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-1475">VIM-1475</a> Enable block caret to be used in insert mode.
|
|
||||||
</li>
|
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-2170">VIM-2170</a> Fix an alternative range format for
|
|
||||||
<code>s</code> command
|
|
||||||
</li>
|
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-1913">VIM-1913</a>
|
|
||||||
<a href="https://youtrack.jetbrains.com/issue/VIM-2154">VIM-2154</a> Several fixes for AppCode templates
|
|
||||||
</li>
|
|
||||||
<li><a href="https://youtrack.jetbrains.com/issue/VIM-1756">VIM-1756</a> Fix startsel from insert mode</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Merged PRs:</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/249">249</a> by <a href="https://github.com/jpalus">Jan
|
|
||||||
Palus</a>: VIM-2113 Increase tag range only in visual mode
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/250">250</a> by <a href="https://github.com/jpalus">Jan
|
|
||||||
Palus</a>: VIM-2114 Do not override registers when deleting empty range
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/256">256</a> by <a href="https://github.com/brandoncc">Brandon
|
|
||||||
Conway</a>: Fix typo
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/254">254</a> by <a href="https://github.com/antekone">Grzegorz
|
|
||||||
Antoniak</a>: VIM-1475: Add an option to use block caret in insert mode
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/225">225</a> by <a href="https://github.com/sumoooru2">sumoooru2</a>:
|
|
||||||
Implement cmap
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/258">258</a> by <a href="https://github.com/citizenmatt">Matt
|
|
||||||
Ellis</a>: Show the correct handler class in :map
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/257">257</a> by <a href="https://github.com/citizenmatt">Matt
|
|
||||||
Ellis</a>: Extract SearchHighlightsHelper from SearchGroup
|
|
||||||
</li>
|
|
||||||
<li><a href="https://github.com/JetBrains/ideavim/pull/251">251</a> by <a href="https://github.com/shaunpatterson">Shaun
|
|
||||||
Patterson</a>: VIM-1756: startSel works in insert mode
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
]]>
|
]]>
|
||||||
</change-notes>
|
</change-notes>
|
||||||
@@ -79,7 +36,7 @@
|
|||||||
|
|
||||||
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
||||||
<!-- Check for [Version Update] tag in YouTrack as well -->
|
<!-- Check for [Version Update] tag in YouTrack as well -->
|
||||||
<idea-version since-build="201.5985.41"/>
|
<idea-version since-build="202.5103.13"/>
|
||||||
|
|
||||||
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform -->
|
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform -->
|
||||||
<depends>com.intellij.modules.lang</depends>
|
<depends>com.intellij.modules.lang</depends>
|
||||||
|
@@ -45,8 +45,8 @@ import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
|
|||||||
import com.maddyhome.idea.vim.helper.*;
|
import com.maddyhome.idea.vim.helper.*;
|
||||||
import com.maddyhome.idea.vim.key.*;
|
import com.maddyhome.idea.vim.key.*;
|
||||||
import com.maddyhome.idea.vim.option.OptionsManager;
|
import com.maddyhome.idea.vim.option.OptionsManager;
|
||||||
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
|
|
||||||
import com.maddyhome.idea.vim.ui.ShowCmd;
|
import com.maddyhome.idea.vim.ui.ShowCmd;
|
||||||
|
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -692,7 +692,7 @@ public class KeyHandler {
|
|||||||
@NotNull CommandNode node,
|
@NotNull CommandNode node,
|
||||||
CommandState editorState) {
|
CommandState editorState) {
|
||||||
// The user entered a valid command. Create the command and add it to the stack.
|
// The user entered a valid command. Create the command and add it to the stack.
|
||||||
final EditorActionHandlerBase action = node.getActionHolder().getAction();
|
final EditorActionHandlerBase action = node.getActionHolder().getInstance();
|
||||||
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
|
final CommandBuilder commandBuilder = editorState.getCommandBuilder();
|
||||||
final Argument.Type expectedArgumentType = commandBuilder.getExpectedArgumentType();
|
final Argument.Type expectedArgumentType = commandBuilder.getExpectedArgumentType();
|
||||||
|
|
||||||
@@ -739,7 +739,7 @@ public class KeyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean stopMacroRecord(CommandNode node, @NotNull CommandState editorState) {
|
private boolean stopMacroRecord(CommandNode node, @NotNull CommandState editorState) {
|
||||||
return editorState.isRecording() && node.getActionHolder().getAction() instanceof ToggleRecordingAction;
|
return editorState.isRecording() && node.getActionHolder().getInstance() instanceof ToggleRecordingAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startWaitingForArgument(Editor editor,
|
private void startWaitingForArgument(Editor editor,
|
||||||
|
@@ -53,7 +53,7 @@ public class RegisterActions {
|
|||||||
|
|
||||||
public static @Nullable EditorActionHandlerBase findAction(@NotNull String id) {
|
public static @Nullable EditorActionHandlerBase findAction(@NotNull String id) {
|
||||||
return VIM_ACTIONS_EP.extensions().filter(vimActionBean -> vimActionBean.getActionId().equals(id)).findFirst()
|
return VIM_ACTIONS_EP.extensions().filter(vimActionBean -> vimActionBean.getActionId().equals(id)).findFirst()
|
||||||
.map(ActionBeanClass::getAction).orElse(null);
|
.map(ActionBeanClass::getInstance).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull EditorActionHandlerBase findActionOrDie(@NotNull String id) {
|
public static @NotNull EditorActionHandlerBase findActionOrDie(@NotNull String id) {
|
||||||
|
@@ -24,7 +24,6 @@ import com.intellij.openapi.editor.Editor;
|
|||||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||||
import com.intellij.openapi.util.ThrowableComputable;
|
import com.intellij.openapi.util.ThrowableComputable;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.command.SelectionType;
|
|
||||||
import com.maddyhome.idea.vim.common.Register;
|
import com.maddyhome.idea.vim.common.Register;
|
||||||
import com.maddyhome.idea.vim.ex.handler.GotoLineHandler;
|
import com.maddyhome.idea.vim.ex.handler.GotoLineHandler;
|
||||||
import com.maddyhome.idea.vim.ex.ranges.Range;
|
import com.maddyhome.idea.vim.ex.ranges.Range;
|
||||||
@@ -209,7 +208,7 @@ public class CommandParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final ExBeanClass handlerHolder = node.getCommandHandler();
|
final ExBeanClass handlerHolder = node.getCommandHandler();
|
||||||
return handlerHolder != null ? handlerHolder.getHandler() : null;
|
return handlerHolder != null ? handlerHolder.getInstance() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -557,8 +556,8 @@ public class CommandParser {
|
|||||||
if (handlerHolder.getNames() != null) {
|
if (handlerHolder.getNames() != null) {
|
||||||
names = CommandDefinitionKt.commands(handlerHolder.getNames().split(","));
|
names = CommandDefinitionKt.commands(handlerHolder.getNames().split(","));
|
||||||
}
|
}
|
||||||
else if (handlerHolder.getHandler() instanceof ComplicatedNameExCommand) {
|
else if (handlerHolder.getInstance() instanceof ComplicatedNameExCommand) {
|
||||||
names = ((ComplicatedNameExCommand)handlerHolder.getHandler()).getNames();
|
names = ((ComplicatedNameExCommand)handlerHolder.getInstance()).getNames();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new RuntimeException("Cannot create an ex command: " + handlerHolder);
|
throw new RuntimeException("Cannot create an ex command: " + handlerHolder);
|
||||||
|
@@ -18,29 +18,23 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.ex
|
package com.maddyhome.idea.vim.ex
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.extensions.AbstractExtensionPointBean
|
import com.intellij.serviceContainer.BaseKeyedLazyInstance
|
||||||
import com.intellij.util.xmlb.annotations.Attribute
|
import com.intellij.util.xmlb.annotations.Attribute
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
|
|
||||||
// [Version Update] 202+
|
class ExBeanClass : BaseKeyedLazyInstance<CommandHandler>() {
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
class ExBeanClass : AbstractExtensionPointBean() {
|
|
||||||
@Attribute("implementation")
|
@Attribute("implementation")
|
||||||
var implementation: String? = null
|
var implementation: String? = null
|
||||||
|
|
||||||
@Attribute("names")
|
@Attribute("names")
|
||||||
var names: String? = null
|
var names: String? = null
|
||||||
|
|
||||||
val handler: CommandHandler by lazy {
|
override fun getImplementationClassName(): String? = implementation
|
||||||
this.instantiateClass<CommandHandler>(
|
|
||||||
implementation ?: "", ApplicationManager.getApplication().picoContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun register() {
|
fun register() {
|
||||||
if (pluginId != VimPlugin.getPluginId()) {
|
if (this.pluginDescriptor.pluginId != VimPlugin.getPluginId()) {
|
||||||
logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: $pluginId")
|
logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: ${this.pluginDescriptor.pluginId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
CommandParser.getInstance().addHandler(this)
|
CommandParser.getInstance().addHandler(this)
|
||||||
|
@@ -18,19 +18,13 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.extension
|
package com.maddyhome.idea.vim.extension
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.serviceContainer.BaseKeyedLazyInstance
|
||||||
import com.intellij.openapi.extensions.AbstractExtensionPointBean
|
|
||||||
import com.intellij.util.xmlb.annotations.Attribute
|
import com.intellij.util.xmlb.annotations.Attribute
|
||||||
import com.intellij.util.xmlb.annotations.Tag
|
import com.intellij.util.xmlb.annotations.Tag
|
||||||
import com.intellij.util.xmlb.annotations.XCollection
|
import com.intellij.util.xmlb.annotations.XCollection
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
|
|
||||||
// [Version Update] 202+
|
class ExtensionBeanClass : BaseKeyedLazyInstance<VimExtension>() {
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
class ExtensionBeanClass : AbstractExtensionPointBean() {
|
|
||||||
init {
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
@Attribute("implementation")
|
@Attribute("implementation")
|
||||||
var implementation: String? = null
|
var implementation: String? = null
|
||||||
|
|
||||||
@@ -46,14 +40,7 @@ class ExtensionBeanClass : AbstractExtensionPointBean() {
|
|||||||
@XCollection
|
@XCollection
|
||||||
var aliases: List<Alias>? = null
|
var aliases: List<Alias>? = null
|
||||||
|
|
||||||
var initialized = AtomicBoolean(false)
|
override fun getImplementationClassName(): String? = implementation
|
||||||
|
|
||||||
val handler: VimExtension by lazy {
|
|
||||||
initialized.set(true)
|
|
||||||
this.instantiateClass<VimExtension>(
|
|
||||||
implementation ?: "", ApplicationManager.getApplication().picoContainer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tag("alias")
|
@Tag("alias")
|
||||||
|
@@ -41,9 +41,7 @@ object VimExtensionRegistrar {
|
|||||||
|
|
||||||
VimExtension.EP_NAME.extensions.forEach(this::registerExtension)
|
VimExtension.EP_NAME.extensions.forEach(this::registerExtension)
|
||||||
|
|
||||||
// [VERSION UPDATE] 202+
|
VimExtension.EP_NAME.point.addExtensionPointListener(object : ExtensionPointListener<ExtensionBeanClass> {
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
VimExtension.EP_NAME.getPoint(null).addExtensionPointListener(object : ExtensionPointListener<ExtensionBeanClass> {
|
|
||||||
override fun extensionAdded(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) {
|
override fun extensionAdded(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) {
|
||||||
registerExtension(extension)
|
registerExtension(extension)
|
||||||
}
|
}
|
||||||
@@ -56,7 +54,7 @@ object VimExtensionRegistrar {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun registerExtension(extensionBean: ExtensionBeanClass) {
|
private fun registerExtension(extensionBean: ExtensionBeanClass) {
|
||||||
val name = extensionBean.name ?: extensionBean.handler.name
|
val name = extensionBean.name ?: extensionBean.instance.name
|
||||||
if (name in registeredExtensions) return
|
if (name in registeredExtensions) return
|
||||||
|
|
||||||
registeredExtensions.add(name)
|
registeredExtensions.add(name)
|
||||||
@@ -64,10 +62,10 @@ object VimExtensionRegistrar {
|
|||||||
val option = ToggleOption(name, name, false)
|
val option = ToggleOption(name, name, false)
|
||||||
option.addOptionChangeListener { _, _ ->
|
option.addOptionChangeListener { _, _ ->
|
||||||
if (isSet(name)) {
|
if (isSet(name)) {
|
||||||
extensionBean.handler.init()
|
extensionBean.instance.init()
|
||||||
logger.info("IdeaVim extension '$name' initialized")
|
logger.info("IdeaVim extension '$name' initialized")
|
||||||
} else {
|
} else {
|
||||||
extensionBean.handler.dispose()
|
extensionBean.instance.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addOption(option)
|
addOption(option)
|
||||||
@@ -75,13 +73,11 @@ object VimExtensionRegistrar {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun unregisterExtension(extension: ExtensionBeanClass) {
|
private fun unregisterExtension(extension: ExtensionBeanClass) {
|
||||||
val name = extension.name ?: extension.handler.name
|
val name = extension.name ?: extension.instance.name
|
||||||
if (name !in registeredExtensions) return
|
if (name !in registeredExtensions) return
|
||||||
registeredExtensions.remove(name)
|
registeredExtensions.remove(name)
|
||||||
removeAliases(extension)
|
removeAliases(extension)
|
||||||
if (extension.initialized.get()) {
|
extension.instance.dispose()
|
||||||
extension.handler.dispose()
|
|
||||||
}
|
|
||||||
removeOption(name)
|
removeOption(name)
|
||||||
remove(name)
|
remove(name)
|
||||||
logger.info("IdeaVim extension '$name' disposed")
|
logger.info("IdeaVim extension '$name' disposed")
|
||||||
@@ -95,7 +91,7 @@ object VimExtensionRegistrar {
|
|||||||
private fun registerAliases(extension: ExtensionBeanClass) {
|
private fun registerAliases(extension: ExtensionBeanClass) {
|
||||||
extension.aliases
|
extension.aliases
|
||||||
?.mapNotNull { it.name }
|
?.mapNotNull { it.name }
|
||||||
?.forEach { alias -> extensionAliases[alias] = extension.name ?: extension.handler.name }
|
?.forEach { alias -> extensionAliases[alias] = extension.name ?: extension.instance.name }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAliases(extension: ExtensionBeanClass) {
|
private fun removeAliases(extension: ExtensionBeanClass) {
|
||||||
|
@@ -1765,27 +1765,7 @@ public class ChangeGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void resetCaret(@NotNull Editor editor, boolean insert) {
|
public static void resetCaret(@NotNull Editor editor, boolean insert) {
|
||||||
Document doc = editor.getDocument();
|
editor.getSettings().setBlockCursor(!insert);
|
||||||
VirtualFile vf = FileDocumentManager.getInstance().getFile(doc);
|
|
||||||
if (vf != null) {
|
|
||||||
resetCaret(vf, editor.getProject(), insert);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
editor.getSettings().setBlockCursor(!insert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void resetCaret(@NotNull VirtualFile virtualFile, Project proj, boolean insert) {
|
|
||||||
logger.debug("Reset caret to a " + (insert ? "non-block" : "block") + " shape");
|
|
||||||
Document doc = FileDocumentManager.getInstance().getDocument(virtualFile);
|
|
||||||
if (doc == null) return; // Must be no text editor (such as image)
|
|
||||||
Editor[] editors = EditorFactory.getInstance().getEditors(doc, proj);
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("There are " + editors.length + " editors for virtual file " + virtualFile.getName());
|
|
||||||
}
|
|
||||||
for (Editor editor : editors) {
|
|
||||||
editor.getSettings().setBlockCursor(!insert);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -307,17 +307,17 @@ public class KeyGroup implements PersistentStateComponent<Element> {
|
|||||||
|
|
||||||
public void registerCommandAction(@NotNull ActionBeanClass actionHolder) {
|
public void registerCommandAction(@NotNull ActionBeanClass actionHolder) {
|
||||||
|
|
||||||
if (!VimPlugin.getPluginId().equals(actionHolder.getPluginId())) {
|
if (!VimPlugin.getPluginId().equals(actionHolder.getPluginDescriptor().getPluginId())) {
|
||||||
logger.error("IdeaVim doesn't accept contributions to `vimActions` extension points. " +
|
logger.error("IdeaVim doesn't accept contributions to `vimActions` extension points. " +
|
||||||
"Please create a plugin using `VimExtension`. " +
|
"Please create a plugin using `VimExtension`. " +
|
||||||
"Plugin to blame: " +
|
"Plugin to blame: " +
|
||||||
actionHolder.getPluginId());
|
actionHolder.getPluginDescriptor().getPluginId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<List<KeyStroke>> actionKeys = actionHolder.getParsedKeys();
|
Set<List<KeyStroke>> actionKeys = actionHolder.getParsedKeys();
|
||||||
if (actionKeys == null) {
|
if (actionKeys == null) {
|
||||||
final EditorActionHandlerBase action = actionHolder.getAction();
|
final EditorActionHandlerBase action = actionHolder.getInstance();
|
||||||
if (action instanceof ComplicatedKeysAction) {
|
if (action instanceof ComplicatedKeysAction) {
|
||||||
actionKeys = ((ComplicatedKeysAction)action).getKeyStrokesSet();
|
actionKeys = ((ComplicatedKeysAction)action).getKeyStrokesSet();
|
||||||
}
|
}
|
||||||
@@ -337,7 +337,7 @@ public class KeyGroup implements PersistentStateComponent<Element> {
|
|||||||
prefixes = new HashMap<>();
|
prefixes = new HashMap<>();
|
||||||
}
|
}
|
||||||
for (List<KeyStroke> keys : actionKeys) {
|
for (List<KeyStroke> keys : actionKeys) {
|
||||||
checkCommand(actionModes, actionHolder.getAction(), keys);
|
checkCommand(actionModes, actionHolder.getInstance(), keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.handler
|
package com.maddyhome.idea.vim.handler
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.serviceContainer.BaseKeyedLazyInstance
|
||||||
import com.intellij.openapi.extensions.AbstractExtensionPointBean
|
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import com.intellij.util.xmlb.annotations.Attribute
|
import com.intellij.util.xmlb.annotations.Attribute
|
||||||
import com.maddyhome.idea.vim.command.MappingMode
|
import com.maddyhome.idea.vim.command.MappingMode
|
||||||
@@ -47,9 +46,7 @@ import javax.swing.KeyStroke
|
|||||||
* The reason is startup performance. Using the extension points you don't even have to load classes of actions.
|
* The reason is startup performance. Using the extension points you don't even have to load classes of actions.
|
||||||
* So, all actions are loaded on demand, including classes in classloader.
|
* So, all actions are loaded on demand, including classes in classloader.
|
||||||
*/
|
*/
|
||||||
// [VERSION UPDATE] 202+
|
class ActionBeanClass : BaseKeyedLazyInstance<EditorActionHandlerBase>() {
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
class ActionBeanClass : AbstractExtensionPointBean() {
|
|
||||||
@Attribute("implementation")
|
@Attribute("implementation")
|
||||||
var implementation: String? = null
|
var implementation: String? = null
|
||||||
|
|
||||||
@@ -61,17 +58,14 @@ class ActionBeanClass : AbstractExtensionPointBean() {
|
|||||||
|
|
||||||
val actionId: String get() = implementation?.let { EditorActionHandlerBase.getActionId(it) } ?: ""
|
val actionId: String get() = implementation?.let { EditorActionHandlerBase.getActionId(it) } ?: ""
|
||||||
|
|
||||||
val action: EditorActionHandlerBase by lazy {
|
|
||||||
this.instantiateClass<EditorActionHandlerBase>(
|
|
||||||
implementation ?: "", ApplicationManager.getApplication().picoContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getParsedKeys(): Set<List<KeyStroke>>? {
|
fun getParsedKeys(): Set<List<KeyStroke>>? {
|
||||||
val myKeys = keys ?: return null
|
val myKeys = keys ?: return null
|
||||||
val escapedKeys = myKeys.splitByComma()
|
val escapedKeys = myKeys.splitByComma()
|
||||||
return EditorActionHandlerBase.parseKeysSet(escapedKeys)
|
return EditorActionHandlerBase.parseKeysSet(escapedKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getImplementationClassName(): String? = implementation
|
||||||
|
|
||||||
fun getParsedModes(): Set<MappingMode>? {
|
fun getParsedModes(): Set<MappingMode>? {
|
||||||
val myModes = modes ?: return null
|
val myModes = modes ?: return null
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.helper
|
package com.maddyhome.idea.vim.helper
|
||||||
|
|
||||||
|
import com.intellij.codeWithMe.ClientId
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||||
@@ -39,6 +40,7 @@ val Editor.fileSize: Int
|
|||||||
val Editor.isIdeaVimDisabledHere: Boolean
|
val Editor.isIdeaVimDisabledHere: Boolean
|
||||||
get() {
|
get() {
|
||||||
return disabledInDialog
|
return disabledInDialog
|
||||||
|
|| (!ClientId.isCurrentlyUnderLocalId) // CWM-927
|
||||||
|| (!OptionsManager.ideavimsupport.contains("singleline") && isDatabaseCell())
|
|| (!OptionsManager.ideavimsupport.contains("singleline") && isDatabaseCell())
|
||||||
|| (!OptionsManager.ideavimsupport.contains("singleline") && isOneLineMode)
|
|| (!OptionsManager.ideavimsupport.contains("singleline") && isOneLineMode)
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.helper;
|
package com.maddyhome.idea.vim.helper;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.lang.CodeDocumentationAwareCommenter;
|
import com.intellij.lang.CodeDocumentationAwareCommenter;
|
||||||
import com.intellij.lang.Commenter;
|
import com.intellij.lang.Commenter;
|
||||||
import com.intellij.lang.Language;
|
import com.intellij.lang.Language;
|
||||||
@@ -29,10 +30,14 @@ import com.intellij.psi.PsiComment;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.command.CommandState;
|
import com.maddyhome.idea.vim.command.CommandState;
|
||||||
|
import com.maddyhome.idea.vim.common.CharacterPosition;
|
||||||
import com.maddyhome.idea.vim.common.TextRange;
|
import com.maddyhome.idea.vim.common.TextRange;
|
||||||
import com.maddyhome.idea.vim.option.ListOption;
|
import com.maddyhome.idea.vim.option.ListOption;
|
||||||
import com.maddyhome.idea.vim.option.OptionsManager;
|
import com.maddyhome.idea.vim.option.OptionsManager;
|
||||||
|
import com.maddyhome.idea.vim.regexp.CharPointer;
|
||||||
|
import com.maddyhome.idea.vim.regexp.RegExp;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -44,11 +49,357 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.checkInString;
|
import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.checkInString;
|
||||||
|
import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.shouldIgnoreCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper methods for searching text
|
* Helper methods for searching text
|
||||||
*/
|
*/
|
||||||
public class SearchHelper {
|
public class SearchHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find text matching the given pattern.
|
||||||
|
*
|
||||||
|
* @param editor The editor to search in
|
||||||
|
* @param pattern The pattern to search for
|
||||||
|
* @param startOffset The offset to start searching from
|
||||||
|
* @param count Find the nth next occurrence of the pattern. Must be 1 or greater.
|
||||||
|
* @param searchOptions A set of options, such as direction and wrap
|
||||||
|
* @return A TextRange representing the result, or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static TextRange findPattern(@NotNull Editor editor,
|
||||||
|
@Nullable String pattern,
|
||||||
|
int startOffset,
|
||||||
|
int count,
|
||||||
|
EnumSet<SearchOptions> searchOptions) {
|
||||||
|
if (pattern == null || pattern.length() == 0) {
|
||||||
|
logger.warn("Pattern is null or empty. Cannot perform search");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction dir = searchOptions.contains(SearchOptions.BACKWARDS) ? Direction.BACKWARDS : Direction.FORWARDS;
|
||||||
|
|
||||||
|
//RE sp;
|
||||||
|
RegExp sp;
|
||||||
|
RegExp.regmmatch_T regmatch = new RegExp.regmmatch_T();
|
||||||
|
regmatch.rmm_ic = shouldIgnoreCase(pattern, searchOptions.contains(SearchOptions.IGNORE_SMARTCASE));
|
||||||
|
sp = new RegExp();
|
||||||
|
regmatch.regprog = sp.vim_regcomp(pattern, 1);
|
||||||
|
if (regmatch.regprog == null) {
|
||||||
|
if (logger.isDebugEnabled()) logger.debug("bad pattern: " + pattern);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int extra_col = 1;
|
||||||
|
int startcol = -1;
|
||||||
|
boolean found = false;
|
||||||
|
boolean match_ok = true;
|
||||||
|
LogicalPosition pos = editor.offsetToLogicalPosition(startOffset);
|
||||||
|
LogicalPosition endpos = null;
|
||||||
|
//REMatch match = null;
|
||||||
|
*/
|
||||||
|
|
||||||
|
CharacterPosition lpos = CharacterPosition.Companion.fromOffset(editor, startOffset);
|
||||||
|
RegExp.lpos_T pos = new RegExp.lpos_T();
|
||||||
|
pos.lnum = lpos.line;
|
||||||
|
pos.col = lpos.column;
|
||||||
|
|
||||||
|
int found;
|
||||||
|
int lnum; /* no init to shut up Apollo cc */
|
||||||
|
//RegExp.regmmatch_T regmatch;
|
||||||
|
CharPointer ptr;
|
||||||
|
int matchcol;
|
||||||
|
RegExp.lpos_T matchpos;
|
||||||
|
RegExp.lpos_T endpos = new RegExp.lpos_T();
|
||||||
|
int loop;
|
||||||
|
RegExp.lpos_T start_pos;
|
||||||
|
boolean at_first_line;
|
||||||
|
int extra_col = dir == Direction.FORWARDS ? 1 : 0;
|
||||||
|
boolean match_ok;
|
||||||
|
long nmatched;
|
||||||
|
//int submatch = 0;
|
||||||
|
boolean first_match = true;
|
||||||
|
|
||||||
|
int lineCount = EditorHelper.getLineCount(editor);
|
||||||
|
int startLine = 0;
|
||||||
|
int endLine = lineCount;
|
||||||
|
|
||||||
|
do /* loop for count */ {
|
||||||
|
start_pos = new RegExp.lpos_T(pos); /* remember start pos for detecting no match */
|
||||||
|
found = 0; /* default: not found */
|
||||||
|
at_first_line = true; /* default: start in first line */
|
||||||
|
if (pos.lnum == -1) /* correct lnum for when starting in line 0 */ {
|
||||||
|
pos.lnum = 0;
|
||||||
|
pos.col = 0;
|
||||||
|
at_first_line = false; /* not in first line now */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start searching in current line, unless searching backwards and
|
||||||
|
* we're in column 0.
|
||||||
|
*/
|
||||||
|
if (dir == Direction.BACKWARDS && start_pos.col == 0) {
|
||||||
|
lnum = pos.lnum - 1;
|
||||||
|
at_first_line = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lnum = pos.lnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lcount = EditorHelper.getLineCount(editor);
|
||||||
|
for (loop = 0; loop <= 1; ++loop) /* loop twice if 'wrapscan' set */ {
|
||||||
|
if (!searchOptions.contains(SearchOptions.WHOLE_FILE)) {
|
||||||
|
startLine = lnum;
|
||||||
|
endLine = lnum + 1;
|
||||||
|
}
|
||||||
|
for (; lnum >= startLine && lnum < endLine; lnum += dir.toInt(), at_first_line = false) {
|
||||||
|
/*
|
||||||
|
* Look for a match somewhere in the line.
|
||||||
|
*/
|
||||||
|
nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, 0);
|
||||||
|
if (nmatched > 0) {
|
||||||
|
/* match may actually be in another line when using \zs */
|
||||||
|
matchpos = new RegExp.lpos_T(regmatch.startpos[0]);
|
||||||
|
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
|
||||||
|
|
||||||
|
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum + matchpos.lnum));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward search in the first line: match should be after
|
||||||
|
* the start position. If not, continue at the end of the
|
||||||
|
* match (this is vi compatible) or on the next char.
|
||||||
|
*/
|
||||||
|
if (dir == Direction.FORWARDS && at_first_line) {
|
||||||
|
match_ok = true;
|
||||||
|
/*
|
||||||
|
* When match lands on a NUL the cursor will be put
|
||||||
|
* one back afterwards, compare with that position,
|
||||||
|
* otherwise "/$" will get stuck on end of line.
|
||||||
|
*/
|
||||||
|
while (matchpos.lnum == 0
|
||||||
|
&& (searchOptions.contains(SearchOptions.WANT_ENDPOS) && first_match
|
||||||
|
? (nmatched == 1 && endpos.col - 1 < start_pos.col + extra_col)
|
||||||
|
: (matchpos.col - (ptr.charAt(matchpos.col) == '\u0000' ? 1 : 0) < start_pos.col + extra_col))) {
|
||||||
|
if (nmatched > 1) {
|
||||||
|
/* end is in next line, thus no match in
|
||||||
|
* this line */
|
||||||
|
match_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
matchcol = endpos.col;
|
||||||
|
/* for empty match: advance one char */
|
||||||
|
if (matchcol == matchpos.col && ptr.charAt(matchcol) != '\u0000') {
|
||||||
|
++matchcol;
|
||||||
|
}
|
||||||
|
if (ptr.charAt(matchcol) == '\u0000' ||
|
||||||
|
(nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, matchcol)) == 0) {
|
||||||
|
match_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
matchpos = new RegExp.lpos_T(regmatch.startpos[0]);
|
||||||
|
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
|
||||||
|
|
||||||
|
/* Need to get the line pointer again, a
|
||||||
|
* multi-line search may have made it invalid. */
|
||||||
|
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum));
|
||||||
|
}
|
||||||
|
if (!match_ok) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir == Direction.BACKWARDS) {
|
||||||
|
/*
|
||||||
|
* Now, if there are multiple matches on this line,
|
||||||
|
* we have to get the last one. Or the last one before
|
||||||
|
* the cursor, if we're on that line.
|
||||||
|
* When putting the new cursor at the end, compare
|
||||||
|
* relative to the end of the match.
|
||||||
|
*/
|
||||||
|
match_ok = false;
|
||||||
|
for (;;) {
|
||||||
|
if (loop != 0 ||
|
||||||
|
(searchOptions.contains(SearchOptions.WANT_ENDPOS)
|
||||||
|
? (lnum + regmatch.endpos[0].lnum < start_pos.lnum || (lnum + regmatch.endpos[0].lnum == start_pos.lnum && regmatch.endpos[0].col - 1 < start_pos.col + extra_col))
|
||||||
|
: (lnum + regmatch.startpos[0].lnum < start_pos.lnum || (lnum + regmatch.startpos[0].lnum == start_pos.lnum && regmatch.startpos[0].col < start_pos.col + extra_col)))) {
|
||||||
|
/* Remember this position, we use it if it's
|
||||||
|
* the last match in the line. */
|
||||||
|
match_ok = true;
|
||||||
|
matchpos = new RegExp.lpos_T(regmatch.startpos[0]);
|
||||||
|
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We found a valid match, now check if there is
|
||||||
|
* another one after it.
|
||||||
|
* If vi-compatible searching, continue at the end
|
||||||
|
* of the match, otherwise continue one position
|
||||||
|
* forward.
|
||||||
|
*/
|
||||||
|
if (nmatched > 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
matchcol = endpos.col;
|
||||||
|
/* for empty match: advance one char */
|
||||||
|
if (matchcol == matchpos.col && ptr.charAt(matchcol) != '\u0000') {
|
||||||
|
++matchcol;
|
||||||
|
}
|
||||||
|
if (ptr.charAt(matchcol) == '\u0000' ||
|
||||||
|
(nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum + matchpos.lnum, matchcol)) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to get the line pointer again, a
|
||||||
|
* multi-line search may have made it invalid. */
|
||||||
|
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum + matchpos.lnum));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is only a match after the cursor, skip
|
||||||
|
* this match.
|
||||||
|
*/
|
||||||
|
if (!match_ok) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.lnum = lnum + matchpos.lnum;
|
||||||
|
pos.col = matchpos.col;
|
||||||
|
endpos.lnum = lnum + endpos.lnum;
|
||||||
|
found = 1;
|
||||||
|
first_match = false;
|
||||||
|
|
||||||
|
/* Set variables used for 'incsearch' highlighting. */
|
||||||
|
//search_match_lines = endpos.lnum - (lnum - first_lnum);
|
||||||
|
//search_match_endcol = endpos.col;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//line_breakcheck(); /* stop if ctrl-C typed */
|
||||||
|
//if (got_int)
|
||||||
|
// break;
|
||||||
|
|
||||||
|
if (loop != 0 && lnum == start_pos.lnum) {
|
||||||
|
break; /* if second loop, stop where started */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
at_first_line = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stop the search if wrapscan isn't set, after an interrupt and
|
||||||
|
* after a match
|
||||||
|
*/
|
||||||
|
if (!searchOptions.contains(SearchOptions.WRAP) || found != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 'wrapscan' is set we continue at the other end of the file.
|
||||||
|
* If 'shortmess' does not contain 's', we give a message.
|
||||||
|
* This message is also remembered in keep_msg for when the screen
|
||||||
|
* is redrawn. The keep_msg is cleared whenever another message is
|
||||||
|
* written.
|
||||||
|
*/
|
||||||
|
if (dir == Direction.BACKWARDS) /* start second loop at the other end */ {
|
||||||
|
lnum = lineCount - 1;
|
||||||
|
//if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
|
||||||
|
// give_warning((char_u *)_(top_bot_msg), TRUE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lnum = 0;
|
||||||
|
//if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
|
||||||
|
// give_warning((char_u *)_(bot_top_msg), TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if (got_int || called_emsg || break_loop)
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
while (--count > 0 && found != 0); /* stop after count matches or no match */
|
||||||
|
|
||||||
|
if (found == 0) /* did not find it */ {
|
||||||
|
//if ((options & SEARCH_MSG) == SEARCH_MSG)
|
||||||
|
if (searchOptions.contains(SearchOptions.SHOW_MESSAGES)) {
|
||||||
|
if (searchOptions.contains(SearchOptions.WRAP)) {
|
||||||
|
VimPlugin.showMessage(MessageHelper.message(Msg.e_patnotf2, pattern));
|
||||||
|
}
|
||||||
|
else if (lnum <= 0) {
|
||||||
|
VimPlugin.showMessage(MessageHelper.message(Msg.E384, pattern));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VimPlugin.showMessage(MessageHelper.message(Msg.E385, pattern));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return new TextRange(editor.logicalPositionToOffset(new LogicalPosition(pos.lnum, pos.col)),
|
||||||
|
// editor.logicalPositionToOffset(new LogicalPosition(endpos.lnum, endpos.col)));
|
||||||
|
//return new TextRange(editor.logicalPositionToOffset(new LogicalPosition(pos.lnum, 0)) + pos.col,
|
||||||
|
// editor.logicalPositionToOffset(new LogicalPosition(endpos.lnum, 0)) + endpos.col);
|
||||||
|
return new TextRange(new CharacterPosition(pos.lnum, pos.col).toOffset(editor),
|
||||||
|
new CharacterPosition(endpos.lnum, endpos.col).toOffset(editor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all occurrences of the pattern.
|
||||||
|
*
|
||||||
|
* @param editor The editor to search in
|
||||||
|
* @param pattern The pattern to search for
|
||||||
|
* @param startLine The start line of the range to search for, or -1 for the whole document
|
||||||
|
* @param endLine The end line of the range to search for, or -1 for the whole document
|
||||||
|
* @param ignoreCase Case sensitive or insensitive searching
|
||||||
|
* @return A list of TextRange objects representing the results
|
||||||
|
*/
|
||||||
|
public static @NotNull List<TextRange> findAll(@NotNull Editor editor,
|
||||||
|
@NotNull String pattern,
|
||||||
|
int startLine,
|
||||||
|
int endLine,
|
||||||
|
boolean ignoreCase) {
|
||||||
|
final List<TextRange> results = Lists.newArrayList();
|
||||||
|
final int lineCount = EditorHelper.getLineCount(editor);
|
||||||
|
final int actualEndLine = endLine == -1 ? lineCount : endLine;
|
||||||
|
|
||||||
|
final RegExp.regmmatch_T regMatch = new RegExp.regmmatch_T();
|
||||||
|
final RegExp regExp = new RegExp();
|
||||||
|
regMatch.regprog = regExp.vim_regcomp(pattern, 1);
|
||||||
|
if (regMatch.regprog == null) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
regMatch.rmm_ic = ignoreCase;
|
||||||
|
|
||||||
|
int col = 0;
|
||||||
|
for (int line = startLine; line <= actualEndLine; ) {
|
||||||
|
int matchedLines = regExp.vim_regexec_multi(regMatch, editor, lineCount, line, col);
|
||||||
|
if (matchedLines > 0) {
|
||||||
|
final CharacterPosition startPos = new CharacterPosition(line + regMatch.startpos[0].lnum,
|
||||||
|
regMatch.startpos[0].col);
|
||||||
|
final CharacterPosition endPos = new CharacterPosition(line + regMatch.endpos[0].lnum,
|
||||||
|
regMatch.endpos[0].col);
|
||||||
|
int start = startPos.toOffset(editor);
|
||||||
|
int end = endPos.toOffset(editor);
|
||||||
|
results.add(new TextRange(start, end));
|
||||||
|
|
||||||
|
if (start != end) {
|
||||||
|
line += matchedLines - 1;
|
||||||
|
col = endPos.column;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line += matchedLines;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line++;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean anyNonWhitespace(@NotNull Editor editor, int offset, int dir) {
|
public static boolean anyNonWhitespace(@NotNull Editor editor, int offset, int dir) {
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
|
@@ -23,24 +23,27 @@ import com.maddyhome.idea.vim.option.OptionsManager.ignorecase
|
|||||||
import com.maddyhome.idea.vim.option.OptionsManager.smartcase
|
import com.maddyhome.idea.vim.option.OptionsManager.smartcase
|
||||||
|
|
||||||
enum class Direction(private val value: Int) {
|
enum class Direction(private val value: Int) {
|
||||||
BACKWARDS(-1), FORWARDS(1), UNSET(0);
|
BACKWARDS(-1), FORWARDS(1);
|
||||||
|
|
||||||
fun toInt(): Int = value
|
fun toInt(): Int = value
|
||||||
fun reverse(): Direction = when (this) {
|
fun reverse(): Direction = when (this) {
|
||||||
BACKWARDS -> FORWARDS
|
BACKWARDS -> FORWARDS
|
||||||
FORWARDS -> BACKWARDS
|
FORWARDS -> BACKWARDS
|
||||||
UNSET -> UNSET
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromInt(value: Int) = when (value) {
|
fun fromInt(value: Int) = when (value) {
|
||||||
BACKWARDS.value -> BACKWARDS
|
BACKWARDS.value -> BACKWARDS
|
||||||
FORWARDS.value -> FORWARDS
|
FORWARDS.value -> FORWARDS
|
||||||
else -> UNSET
|
else -> FORWARDS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SearchOptions {
|
||||||
|
BACKWARDS, WANT_ENDPOS, WRAP, SHOW_MESSAGES, WHOLE_FILE, IGNORE_SMARTCASE
|
||||||
|
}
|
||||||
|
|
||||||
private data class State(val position: Int, val trigger: Char, val inQuote: Boolean?, val lastOpenSingleQuotePos: Int)
|
private data class State(val position: Int, val trigger: Char, val inQuote: Boolean?, val lastOpenSingleQuotePos: Int)
|
||||||
|
|
||||||
// bounds are considered inside corresponding quotes
|
// bounds are considered inside corresponding quotes
|
||||||
@@ -182,7 +185,19 @@ private fun quoteChanges(chars: CharSequence, begin: Int) = sequence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldIgnoreCase(pattern: String, ignoreSmartCase: Boolean): Boolean {
|
/**
|
||||||
val sc = smartcase.isSet && !ignoreSmartCase
|
* Check ignorecase and smartcase options to see if a case insensitive search should be performed with the given pattern.
|
||||||
|
*
|
||||||
|
* When ignorecase is not set, this will always return false - perform a case sensitive search.
|
||||||
|
*
|
||||||
|
* Otherwise, check smartcase. When set, the search will be case insensitive if the pattern contains only lowercase
|
||||||
|
* characters, and case sensitive (returns false) if the pattern contains any lowercase characters.
|
||||||
|
*
|
||||||
|
* The smartcase option can be ignored, e.g. when searching for the whole word under the cursor. This always performs a
|
||||||
|
* case insensitive search, so `\<Work\>` will match `Work` and `work`. But when choosing the same pattern from search
|
||||||
|
* history, the smartcase option is applied, and `\<Work\>` will only match `Work`.
|
||||||
|
*/
|
||||||
|
fun shouldIgnoreCase(pattern: String, ignoreSmartCaseOption: Boolean): Boolean {
|
||||||
|
val sc = smartcase.isSet && !ignoreSmartCaseOption
|
||||||
return ignorecase.isSet && !(sc && StringHelper.containsUpperCase(pattern))
|
return ignorecase.isSet && !(sc && StringHelper.containsUpperCase(pattern))
|
||||||
}
|
}
|
||||||
|
@@ -34,8 +34,6 @@ import com.intellij.openapi.project.ProjectManager
|
|||||||
import com.intellij.ui.ColorUtil
|
import com.intellij.ui.ColorUtil
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.ex.ranges.LineRange
|
import com.maddyhome.idea.vim.ex.ranges.LineRange
|
||||||
import com.maddyhome.idea.vim.group.SearchGroup
|
|
||||||
import com.maddyhome.idea.vim.group.SearchGroup.SearchOptions
|
|
||||||
import com.maddyhome.idea.vim.option.OptionsManager.hlsearch
|
import com.maddyhome.idea.vim.option.OptionsManager.hlsearch
|
||||||
import com.maddyhome.idea.vim.option.OptionsManager.wrapscan
|
import com.maddyhome.idea.vim.option.OptionsManager.wrapscan
|
||||||
import org.jetbrains.annotations.Contract
|
import org.jetbrains.annotations.Contract
|
||||||
@@ -107,7 +105,7 @@ private fun updateSearchHighlights(
|
|||||||
val startLine = searchRange?.startLine ?: 0
|
val startLine = searchRange?.startLine ?: 0
|
||||||
val endLine = searchRange?.endLine ?: -1
|
val endLine = searchRange?.endLine ?: -1
|
||||||
val results =
|
val results =
|
||||||
SearchGroup.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase))
|
SearchHelper.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase))
|
||||||
if (results.isNotEmpty()) {
|
if (results.isNotEmpty()) {
|
||||||
currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards)
|
currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards)
|
||||||
highlightSearchResults(editor, pattern, results, currentMatchOffset)
|
highlightSearchResults(editor, pattern, results, currentMatchOffset)
|
||||||
@@ -119,7 +117,7 @@ private fun updateSearchHighlights(
|
|||||||
if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP)
|
if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP)
|
||||||
if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE)
|
if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE)
|
||||||
if (!forwards) searchOptions.add(SearchOptions.BACKWARDS)
|
if (!forwards) searchOptions.add(SearchOptions.BACKWARDS)
|
||||||
val result = SearchGroup.findIt(editor, pattern, initialOffset, 1, searchOptions)
|
val result = SearchHelper.findPattern(editor, pattern, initialOffset, 1, searchOptions)
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
currentMatchOffset = result.startOffset
|
currentMatchOffset = result.startOffset
|
||||||
val results = listOf(result)
|
val results = listOf(result)
|
||||||
|
@@ -28,12 +28,12 @@ import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
|
|||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.project.DumbAwareAction
|
import com.intellij.openapi.project.DumbAwareAction
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.util.containers.IntArrayList
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser
|
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser
|
||||||
import com.maddyhome.idea.vim.helper.MessageHelper
|
import com.maddyhome.idea.vim.helper.MessageHelper
|
||||||
import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP
|
import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP
|
||||||
import icons.VimIcons
|
import icons.VimIcons
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
@@ -49,8 +49,6 @@ import java.util.regex.Pattern
|
|||||||
|
|
||||||
object VimRcFileState {
|
object VimRcFileState {
|
||||||
// List of hashes of non-empty trimmed lines
|
// List of hashes of non-empty trimmed lines
|
||||||
// [VERSION UPDATE] 202+
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
private val state = IntArrayList()
|
private val state = IntArrayList()
|
||||||
|
|
||||||
// ModificationStamp. Can be taken only from document. Doesn't play a big role, but can help speed up [equalTo]
|
// ModificationStamp. Can be taken only from document. Doesn't play a big role, but can help speed up [equalTo]
|
||||||
@@ -74,11 +72,11 @@ object VimRcFileState {
|
|||||||
val fileModificationStamp = document.modificationStamp
|
val fileModificationStamp = document.modificationStamp
|
||||||
if (fileModificationStamp == modificationStamp) return true
|
if (fileModificationStamp == modificationStamp) return true
|
||||||
|
|
||||||
val stateSize = state.size()
|
val stateSize = state.size
|
||||||
var i = 0
|
var i = 0
|
||||||
VimScriptParser.readText(document.charsSequence).forEach { line ->
|
VimScriptParser.readText(document.charsSequence).forEach { line ->
|
||||||
if (i >= stateSize) return false
|
if (i >= stateSize) return false
|
||||||
if (state.get(i) != line.hashCode()) return false
|
if (state.getInt(i) != line.hashCode()) return false
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if (i < stateSize) return false
|
if (i < stateSize) return false
|
||||||
|
@@ -25,7 +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+
|
[VERSION UPDATE] 203+
|
||||||
public void testEmpty() {
|
public void testEmpty() {
|
||||||
configureByJavaText("<caret>");
|
configureByJavaText("<caret>");
|
||||||
typeText(parseKeys("gqq"));
|
typeText(parseKeys("gqq"));
|
||||||
|
@@ -90,7 +90,7 @@ class VisualToggleBlockModeActionTest : VimTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
[VERSION UPDATE] 2020.2+
|
[VERSION UPDATE] 203+
|
||||||
fun `test on empty file`() {
|
fun `test on empty file`() {
|
||||||
doTest("<C-V>", "", "",
|
doTest("<C-V>", "", "",
|
||||||
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK)
|
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK)
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.plugins.ideavim.extension
|
package org.jetbrains.plugins.ideavim.extension
|
||||||
|
|
||||||
|
import com.intellij.ide.plugins.PluginManagerCore
|
||||||
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.VimPlugin
|
||||||
@@ -50,15 +51,14 @@ class OpMappingTest : VimTestCase() {
|
|||||||
|
|
||||||
extension = TestExtension.createBean()
|
extension = TestExtension.createBean()
|
||||||
|
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
|
||||||
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
|
|
||||||
enableExtensions("TestExtension")
|
enableExtensions("TestExtension")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tearDown() {
|
override fun tearDown() {
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
@Suppress("DEPRECATION")
|
||||||
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
|
VimExtension.EP_NAME.point.unregisterExtension(extension)
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,15 +137,14 @@ class OpMappingTest : VimTestCase() {
|
|||||||
typeText(parseKeys("Q"))
|
typeText(parseKeys("Q"))
|
||||||
myFixture.checkResult("I${c} found it in a legendary land")
|
myFixture.checkResult("I${c} found it in a legendary land")
|
||||||
|
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
@Suppress("DEPRECATION")
|
||||||
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
|
VimExtension.EP_NAME.point.unregisterExtension(extension)
|
||||||
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner))
|
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.instance.owner))
|
||||||
typeText(parseKeys("Q"))
|
typeText(parseKeys("Q"))
|
||||||
myFixture.checkResult("I${c} found it in a legendary land")
|
myFixture.checkResult("I${c} found it in a legendary land")
|
||||||
|
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
|
||||||
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
|
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.instance.owner))
|
||||||
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner))
|
|
||||||
enableExtensions("TestExtension")
|
enableExtensions("TestExtension")
|
||||||
typeText(parseKeys("Q"))
|
typeText(parseKeys("Q"))
|
||||||
myFixture.checkResult("I ${c}found it in a legendary land")
|
myFixture.checkResult("I ${c}found it in a legendary land")
|
||||||
@@ -157,13 +156,12 @@ class OpMappingTest : VimTestCase() {
|
|||||||
myFixture.checkResult("I${c} found it in a legendary land")
|
myFixture.checkResult("I${c} found it in a legendary land")
|
||||||
|
|
||||||
enterCommand("set noTestExtension")
|
enterCommand("set noTestExtension")
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
@Suppress("DEPRECATION")
|
||||||
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
|
VimExtension.EP_NAME.point.unregisterExtension(extension)
|
||||||
typeText(parseKeys("Q"))
|
typeText(parseKeys("Q"))
|
||||||
myFixture.checkResult("I${c} found it in a legendary land")
|
myFixture.checkResult("I${c} found it in a legendary land")
|
||||||
|
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
|
||||||
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
|
|
||||||
enableExtensions("TestExtension")
|
enableExtensions("TestExtension")
|
||||||
typeText(parseKeys("Q"))
|
typeText(parseKeys("Q"))
|
||||||
myFixture.checkResult("I ${c}found it in a legendary land")
|
myFixture.checkResult("I ${c}found it in a legendary land")
|
||||||
@@ -178,13 +176,12 @@ class PlugExtensionsTest : VimTestCase() {
|
|||||||
super.setUp()
|
super.setUp()
|
||||||
|
|
||||||
extension = TestExtension.createBean()
|
extension = TestExtension.createBean()
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
|
||||||
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tearDown() {
|
override fun tearDown() {
|
||||||
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+
|
@Suppress("DEPRECATION")
|
||||||
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension)
|
VimExtension.EP_NAME.point.unregisterExtension(extension)
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +209,7 @@ class PlugExtensionsTest : VimTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val ExtensionBeanClass.ext: TestExtension
|
private val ExtensionBeanClass.ext: TestExtension
|
||||||
get() = this.handler as TestExtension
|
get() = this.instance as TestExtension
|
||||||
|
|
||||||
private class TestExtension : VimExtension {
|
private class TestExtension : VimExtension {
|
||||||
|
|
||||||
@@ -296,6 +293,7 @@ private class TestExtension : VimExtension {
|
|||||||
val beanClass = ExtensionBeanClass()
|
val beanClass = ExtensionBeanClass()
|
||||||
beanClass.implementation = TestExtension::class.java.canonicalName
|
beanClass.implementation = TestExtension::class.java.canonicalName
|
||||||
beanClass.aliases = listOf(Alias().also { it.name = "MyTest" })
|
beanClass.aliases = listOf(Alias().also { it.name = "MyTest" })
|
||||||
|
beanClass.pluginDescriptor = PluginManagerCore.getPlugin(VimPlugin.getPluginId())!!
|
||||||
return beanClass
|
return beanClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,6 @@ class InfoFileTest : VimTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun forEachAction(supply: (action: EditorActionHandlerBase) -> Unit) {
|
private inline fun forEachAction(supply: (action: EditorActionHandlerBase) -> Unit) {
|
||||||
VIM_ACTIONS_EP.extensions.map { it.action }.forEach { supply(it) }
|
VIM_ACTIONS_EP.extensions.map { it.instance }.forEach { supply(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user