1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-09-14 05:32:10 +02:00

Compare commits

..

21 Commits

Author SHA1 Message Date
8de7a9f741 Set plugin version to chylex-27 2024-02-16 06:09:40 +01:00
5977840cef Disable speed search in Project tool window when NERDTree is enabled 2024-02-16 06:09:40 +01:00
d0fea229c4 Work around VIM-3306 (make paragraph-motion plugin go to the end of the line) 2024-02-16 06:09:40 +01:00
9eeac4a788 Apply scrolloff after executing native IDEA actions 2024-02-16 06:09:40 +01:00
8370661b0d Stay on same line after reindenting 2024-02-16 06:09:40 +01:00
3f88e64abf Implement motions to go to next/previous misspelled word 2024-02-16 06:09:39 +01:00
28e3a7c894 Update search register when using f/t 2024-02-16 06:09:39 +01:00
bc859c65f5 Automatically add unambiguous imports after running a macro 2024-02-16 06:09:39 +01:00
141fc8ed22 Fix(VIM-3179): Respect virtual space below editor (imperfectly) 2024-02-16 06:09:39 +01:00
dec494639c Fix(VIM-3178): Workaround to support "Jump to Source" action mapping 2024-02-16 06:09:39 +01:00
d06688033b Fix(VIM-3166): Workaround to fix broken filtering of visual lines 2024-02-16 06:09:39 +01:00
98110b9132 Add support for count for visual and line motion surround 2024-02-16 06:09:39 +01:00
a0404b8664 Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2024-02-16 06:09:39 +01:00
a2a30d545e Fix(VIM-696) Restore visual mode after undo/redo, and disable incompatible actions 2024-02-16 06:09:38 +01:00
4f3bf039c9 Revert(VIM-2884): Fix moving lines to cursor 2024-02-15 08:30:02 +01:00
1f4b97fa00 Respect count with <Action> mappings 2024-02-15 08:30:02 +01:00
61301fdbf5 Add Matchit support for Java statements 2024-02-15 08:30:02 +01:00
c980250529 Change matchit plugin to use HTML patterns in unrecognized files 2024-02-15 08:30:02 +01:00
bdb4b02016 Reset insert mode when switching active editor 2024-02-15 08:30:02 +01:00
62039a00d3 Remove update checker 2024-02-15 08:30:02 +01:00
95c66fd4a6 Set custom plugin version 2024-02-15 08:30:01 +01:00
167 changed files with 54932 additions and 109576 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

View File

@@ -52,7 +52,6 @@ jobs:
name: ui-test-fails-report-mac
path: |
build/reports
tests/ui-ij-tests/build/reports
sandbox-idea-log
# build-for-ui-test-linux:
# runs-on: ubuntu-latest

View File

@@ -52,5 +52,4 @@ jobs:
name: ui-test-fails-report-mac
path: |
build/reports
tests/ui-py-tests/build/reports
sandbox-idea-log

View File

@@ -49,7 +49,6 @@ jobs:
name: ui-test-fails-report-mac
path: |
build/reports
tests/ui-ij-tests/build/reports
sandbox-idea-log
# build-for-ui-test-linux:
# runs-on: ubuntu-latest

View File

@@ -46,8 +46,8 @@ object Qodana : IdeaVimBuildType({
version = Qodana.JVMVersion.LATEST
}
reportAsTests = true
additionalDockerArguments = "-e QODANA_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmdhbml6YXRpb24iOiIzUFZrQSIsInByb2plY3QiOiIzN1FlQSIsInRva2VuIjoiM0t2bXoifQ.uohp81tM7iAfvvB6k8faarfpV-OjusAaEbWQ8iNrOgs"
additionalQodanaArguments = "--baseline qodana.sarif.json"
cloudToken = "credentialsJSON:6b79412e-9198-4862-9223-c5019488f903"
}
}
@@ -63,6 +63,7 @@ object Qodana : IdeaVimBuildType({
timezone = "SERVER"
}
param("dayOfWeek", "Sunday")
enabled = false
}
}

View File

@@ -1,9 +1,11 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.RelativeId
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.GradleBuildStep
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.changeBuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.expectSteps
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.update
/*
This patch script was generated by TeamCity on settings change in UI.
@@ -11,18 +13,6 @@ To apply the patch, change the buildType with id = 'IdeaVimTests_Latest_EAP'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("IdeaVimTests_Latest_EAP")) {
check(artifactRules == """
+:build/reports => build/reports
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
""".trimIndent()) {
"Unexpected option value: artifactRules = $artifactRules"
}
artifactRules = """
+:build/reports => build/reports
+:/mnt/agent/temp/buildTmp/ => /mnt/agent/temp/buildTmp/
+:tests/java-tests/build/reports => tests/java-tests/build/reports
""".trimIndent()
expectSteps {
gradle {
tasks = "clean test"

View File

@@ -25,20 +25,11 @@ usual beta standards.
## To Be Released
### Fixes:
* [VIM-3291](https://youtrack.jetbrains.com/issue/VIM-3291) Remove sync of editor selection between different opened editors
* [VIM-3234](https://youtrack.jetbrains.com/issue/VIM-3234) The space character won't mix in the tab chars after >> and << commands
*
### Merged PRs:
* [805](https://github.com/JetBrains/ideavim/pull/805) by [chylex](https://github.com/chylex): VIM-3238 Fix recording a macro that replays another macro
* [806](https://github.com/JetBrains/ideavim/pull/806) by [chylex](https://github.com/chylex): Enforce LF line separator in project code style
## 2.9.0, 2024-02-20
### Fixes:
* [VIM-3055](https://youtrack.jetbrains.com/issue/VIM-3055) Fix the issue with double deleting after dot
### Merged PRs:
* [725](https://github.com/JetBrains/ideavim/pull/725) by [Emanuel Gestosa](https://github.com/emanuelgestosa): Regex
* [805](https://github.com/JetBrains/ideavim/pull/805) by [chylex](https://github.com/chylex): VIM-3238 Fix recording a macro that replays another macro
## 2.8.0, 2024-01-30

View File

@@ -52,11 +52,11 @@ buildscript {
classpath("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.8.0.202311291450-r")
classpath("org.kohsuke:github-api:1.305")
classpath("io.ktor:ktor-client-core:2.3.8")
classpath("io.ktor:ktor-client-cio:2.3.8")
classpath("io.ktor:ktor-client-auth:2.3.8")
classpath("io.ktor:ktor-client-content-negotiation:2.3.8")
classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.8")
classpath("io.ktor:ktor-client-core:2.3.7")
classpath("io.ktor:ktor-client-cio:2.3.7")
classpath("io.ktor:ktor-client-auth:2.3.7")
classpath("io.ktor:ktor-client-content-negotiation:2.3.7")
classpath("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
// This comes from the changelog plugin
// classpath("org.jetbrains:markdown:0.3.1")
@@ -70,7 +70,7 @@ plugins {
application
id("java-test-fixtures")
id("org.jetbrains.intellij") version "1.17.2"
id("org.jetbrains.intellij") version "1.17.1"
id("org.jetbrains.changelog") version "2.2.0"
id("org.jetbrains.kotlinx.kover") version "0.6.1"
@@ -144,12 +144,12 @@ dependencies {
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.2")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
}
configurations {
@@ -308,8 +308,6 @@ tasks {
val pluginVersion = version
// Don't forget to update plugin.xml
patchPluginXml {
sinceBuild.set("233.11799.30")
// Get the latest available change notes from the changelog file
changeNotes.set(
provider {
@@ -431,14 +429,12 @@ val prId: String by project
tasks.register("updateMergedPr") {
doLast {
val x = changelog.getUnreleased()
println("x")
// if (project.hasProperty("prId")) {
// println("Got pr id: $prId")
// updateMergedPr(prId.toInt())
// } else {
// error("Cannot get prId")
// }
if (project.hasProperty("prId")) {
println("Got pr id: $prId")
updateMergedPr(prId.toInt())
} else {
error("Cannot get prId")
}
}
}
@@ -462,7 +458,7 @@ val fixVersionsElementType = "VersionBundleElement"
tasks.register("releaseActions") {
group = "other"
doLast {
val tickets = getYoutrackTicketsByQuery("%23%7BReady+To+Release%7D%20and%20tag:%20%7BIdeaVim%20Released%20In%20EAP%7D%20")
val tickets = getYoutrackTicketsByQuery("%23%7BReady+To+Release%7D")
if (tickets.isNotEmpty()) {
println("Updating statuses for tickets: $tickets")
setYoutrackStatus(tickets, "Fixed")

View File

@@ -8,16 +8,17 @@
# suppress inspection "UnusedProperty" for whole file
ideaVersion=2023.3.2
ideaVersion=2023.3.3
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
ideaType=IC
downloadIdeaSources=true
instrumentPluginCode=true
version=SNAPSHOT
version=chylex-27
javaVersion=17
remoteRobotVersion=0.11.22
antlrVersion=4.10.1
kotlin.incremental.useClasspathSnapshot=false
# Please don't forget to update kotlin version in buildscript section
# Also update kotlinxSerializationVersion version

File diff suppressed because one or more lines are too long

View File

@@ -21,9 +21,6 @@ exclude:
- src/test/java/org/jetbrains/plugins/ideavim/propertybased/samples/SimpleText.kt
- src/main/java/com/maddyhome/idea/vim/vimscript/parser/generated
- src/main/java/com/maddyhome/idea/vim/package-info.java
- vim-engine/src/main/java/com/maddyhome/idea/vim/regexp/parser/generated
- src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java
- tests/ui-fixtures
dependencyIgnores:
- name: "acejump"
- name: "icu4j"

View File

@@ -22,11 +22,11 @@ repositories {
dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.22")
implementation("io.ktor:ktor-client-core:2.3.8")
implementation("io.ktor:ktor-client-cio:2.3.8")
implementation("io.ktor:ktor-client-content-negotiation:2.3.8")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.8")
implementation("io.ktor:ktor-client-auth:2.3.8")
implementation("io.ktor:ktor-client-core:2.3.7")
implementation("io.ktor:ktor-client-cio:2.3.7")
implementation("io.ktor:ktor-client-content-negotiation:2.3.7")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
implementation("io.ktor:ktor-client-auth:2.3.7")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r")
// This is needed for jgit to connect to ssh

View File

@@ -22,7 +22,7 @@ import kotlinx.serialization.json.jsonPrimitive
*/
@Suppress("SpellCheckingInspection")
val knownPlugins = setOf(
val knownPlugins = listOf(
"IdeaVimExtension",
"github.zgqq.intellij-enhance",
"org.jetbrains.IdeaVim-EasyMotion",
@@ -31,12 +31,7 @@ val knownPlugins = setOf(
"com.github.copilot",
"com.github.dankinsoid.multicursor",
"com.joshestein.ideavim-quickscope",
"ca.alexgirard.HarpoonIJ",
"me.kyren223.harpoonforjb", // https://plugins.jetbrains.com/plugin/23771-harpoonforjb
"com.github.erotourtes.harpoon", // https://plugins.jetbrains.com/plugin/21796-harpooner
"me.kyren223.trident", // https://plugins.jetbrains.com/plugin/23818-trident
"com.protoseo.input-source-auto-converter",
// "cc.implicated.intellij.plugins.bunny", // I don't want to include this plugin in the list of IdeaVim plugins as I don't understand what this is for
@@ -47,7 +42,7 @@ suspend fun main() {
parameter("dependency", "IdeaVIM")
parameter("includeOptional", true)
}
val output = response.body<List<String>>().toSet()
val output = response.body<List<String>>()
println(output)
if (knownPlugins != output) {
val newPlugins = (output - knownPlugins).map { it to (getPluginLinkByXmlId(it) ?: "Can't find plugin link") }

View File

@@ -8,12 +8,6 @@
package scripts.release
import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.revwalk.RevWalk
import org.eclipse.jgit.revwalk.filter.RevFilter
fun main(args: Array<String>) {
println("HI!")
val projectDir = args[0]
@@ -25,12 +19,10 @@ fun main(args: Array<String>) {
check(branch == "master") {
"We should be on master branch"
}
val mergeBaseCommit = getMergeBaseWithMaster(projectDir, objectId)
println("Base commit $mergeBaseCommit")
withGit(projectDir) { git ->
val log = git.log().setMaxCount(500).call().toList()
println("First commit hash in log: " + log.first().name + " log size: ${log.size}")
val logDiff = log.takeWhile { it.id.name != mergeBaseCommit }
val logDiff = log.takeWhile { it.id.name != objectId.name }
val numCommits = logDiff.size
println("Log diff size is $numCommits")
check(numCommits < 450) {
@@ -43,18 +35,3 @@ fun main(args: Array<String>) {
println("##teamcity[setParameter name='env.ORG_GRADLE_PROJECT_version' value='$nextVersion']")
}
}
private fun getMergeBaseWithMaster(projectDir: String, tag: ObjectId): String {
withRepo(projectDir) { repo ->
val master = repo.resolve("master")
RevWalk(repo).use { walk ->
val tagRevCommit = walk.parseCommit(tag)
val masterRevCommit = walk.parseCommit(master)
walk.setRevFilter(RevFilter.MERGE_BASE)
walk.markStart(tagRevCommit)
walk.markStart(masterRevCommit)
val mergeBase: RevCommit = walk.next()
return mergeBase.name
}
}
}

View File

@@ -14,7 +14,7 @@ import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.maddyhome.idea.vim.group.EditorHolderService
@Service(Service.Level.PROJECT)
@Service
internal class VimProjectService(val project: Project) : Disposable {
override fun dispose() {
// Not sure if this is a best solution

View File

@@ -14,7 +14,6 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.setChangeMarks
import com.maddyhome.idea.vim.command.Argument
@@ -22,7 +21,6 @@ import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.common.argumentCaptured
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VimActionHandler
@@ -31,67 +29,21 @@ import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
// todo make it multicaret
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
val func = injector.globalOptions().operatorfunc
if (func.isEmpty()) {
val operatorFunction = injector.keyGroup.operatorFunction
if (operatorFunction == null) {
VimPlugin.showMessage(MessageHelper.message("E774"))
return false
}
val scriptContext = CommandLineVimLContext
// The option value is either a function name, which should have a handler, or it might be a lambda expression, or a
// `function` or `funcref` call expression, all of which will return a funcref (with a handler)
var handler = injector.functionService.getFunctionHandlerOrNull(null, func, scriptContext)
if (handler == null) {
val expression = injector.vimscriptParser.parseExpression(func)
if (expression != null) {
try {
val value = expression.evaluate(editor, context, scriptContext)
if (value is VimFuncref) {
handler = value.handler
}
} catch (ex: ExException) {
// Get the argument for function('...') or funcref('...') for the error message
val functionName = if (expression is FunctionCallExpression && expression.arguments.size > 0) {
expression.arguments[0].evaluate(editor, context, scriptContext).toString()
}
else {
func
}
VimPlugin.showMessage("E117: Unknown function: $functionName")
return false
}
}
}
if (handler == null) {
VimPlugin.showMessage("E117: Unknown function: $func")
return false
}
val arg = when (selectionType) {
SelectionType.LINE_WISE -> "line"
SelectionType.CHARACTER_WISE -> "char"
SelectionType.BLOCK_WISE -> "block"
}
val saveRepeatHandler = VimRepeater.repeatHandler
injector.markService.setChangeMarks(editor.primaryCaret(), textRange)
KeyHandler.getInstance().reset(editor)
val arguments = listOf(SimpleExpression(arg))
handler.executeFunction(arguments, editor, context, scriptContext)
val result = operatorFunction.apply(editor, context, selectionType)
VimRepeater.repeatHandler = saveRepeatHandler
return true
return result
}
@CommandOrMotion(keys = ["g@"], modes = [Mode.NORMAL])

View File

@@ -23,17 +23,17 @@ public class CommandState(private val machine: VimStateMachine) {
public val isOperatorPending: Boolean
get() = machine.isOperatorPending
public val mode: Mode
public val mode: CommandState.Mode
get() {
val myMode = machine.mode
return when (myMode) {
is com.maddyhome.idea.vim.state.mode.Mode.CMD_LINE -> Mode.CMD_LINE
com.maddyhome.idea.vim.state.mode.Mode.INSERT -> Mode.INSERT
is com.maddyhome.idea.vim.state.mode.Mode.NORMAL -> Mode.COMMAND
is com.maddyhome.idea.vim.state.mode.Mode.OP_PENDING -> Mode.OP_PENDING
com.maddyhome.idea.vim.state.mode.Mode.REPLACE -> Mode.REPLACE
is com.maddyhome.idea.vim.state.mode.Mode.SELECT -> Mode.SELECT
is com.maddyhome.idea.vim.state.mode.Mode.VISUAL -> Mode.VISUAL
is com.maddyhome.idea.vim.state.mode.Mode.CMD_LINE -> CommandState.Mode.CMD_LINE
com.maddyhome.idea.vim.state.mode.Mode.INSERT -> CommandState.Mode.INSERT
is com.maddyhome.idea.vim.state.mode.Mode.NORMAL -> CommandState.Mode.COMMAND
is com.maddyhome.idea.vim.state.mode.Mode.OP_PENDING -> CommandState.Mode.OP_PENDING
com.maddyhome.idea.vim.state.mode.Mode.REPLACE -> CommandState.Mode.REPLACE
is com.maddyhome.idea.vim.state.mode.Mode.SELECT -> CommandState.Mode.SELECT
is com.maddyhome.idea.vim.state.mode.Mode.VISUAL -> CommandState.Mode.VISUAL
}
}

View File

@@ -14,34 +14,21 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.change.Extension
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.ImmutableVimCaret
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.CommandLineHelper
import com.maddyhome.idea.vim.helper.TestInputModel
import com.maddyhome.idea.vim.helper.noneOfEnum
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.ui.ModalEntry
import com.maddyhome.idea.vim.vimscript.model.Executable
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.expressions.Scope
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
import java.awt.event.KeyEvent
import java.util.*
import javax.swing.KeyStroke
/**
@@ -133,6 +120,12 @@ public object VimExtensionFacade {
.setAlias(name, CommandAlias.Call(minimumNumberOfArguments, maximumNumberOfArguments, name, handler))
}
/** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */
@JvmStatic
public fun setOperatorFunction(function: OperatorFunction) {
VimPlugin.getKey().operatorFunction = function
}
/**
* Runs normal mode commands similar to ':normal! {commands}'.
* Mappings doesn't work with this function
@@ -214,65 +207,4 @@ public object VimExtensionFacade {
public fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) {
VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList(), type)
}
@JvmStatic
public fun exportScriptFunction(
scope: Scope?,
name: String,
args: List<String>,
defaultArgs: List<Pair<String, Expression>>,
hasOptionalArguments: Boolean,
flags: EnumSet<FunctionFlag>,
function: ScriptFunction
) {
var functionDeclaration: FunctionDeclaration? = null
val body = listOf(object : Executable {
// This context is set to the function declaration during initialisation and then set to the function execution
// context during execution
override lateinit var vimContext: VimLContext
override var rangeInScript: TextRange = TextRange(0, 0)
override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult {
return function.execute(editor, context, functionDeclaration!!.functionVariables)
}
})
functionDeclaration = FunctionDeclaration(
scope,
name,
args,
defaultArgs,
body,
replaceExisting = true,
flags,
hasOptionalArguments
)
functionDeclaration.rangeInScript = TextRange(0, 0)
body.forEach { it.vimContext = functionDeclaration }
injector.functionService.storeFunction(functionDeclaration)
}
}
public fun VimExtensionFacade.exportOperatorFunction(name: String, function: OperatorFunction) {
exportScriptFunction(null, name, listOf("type"), emptyList(), false, noneOfEnum()) {
editor, context, args ->
val type = args["type"]?.asString()
val selectionType = when (type) {
"line" -> SelectionType.LINE_WISE
"block" -> SelectionType.BLOCK_WISE
"char" -> SelectionType.CHARACTER_WISE
else -> return@exportScriptFunction ExecutionResult.Error
}
if (function.apply(editor, context, selectionType)) {
ExecutionResult.Success
}
else {
ExecutionResult.Error
}
}
}
public fun interface ScriptFunction {
public fun execute(editor: VimEditor, context: ExecutionContext, args: Map<String, VimDataType>): ExecutionResult
}

View File

@@ -22,26 +22,26 @@ import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.ImmutableVimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.getLineEndOffset
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.command.TextObjectVisualType
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.exportOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.vimStateMachine
@@ -49,22 +49,17 @@ import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import java.util.*
internal class CommentaryExtension : VimExtension {
companion object {
private const val OPERATOR_FUNC = "CommentaryOperatorFunc"
fun doCommentary(
editor: VimEditor,
context: ExecutionContext,
range: TextRange,
selectionType: SelectionType,
resetCaret: Boolean = true,
resetCaret: Boolean,
): Boolean {
val mode = editor.vimStateMachine.mode
if (mode !is Mode.VISUAL) {
@@ -72,7 +67,8 @@ internal class CommentaryExtension : VimExtension {
}
return runWriteAction {
// Treat block- and character-wise selections as block comments. Fall back if the first action isn't available
// Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action
// isn't available
val actions = if (selectionType === SelectionType.LINE_WISE) {
listOf(IdeActions.ACTION_COMMENT_LINE, IdeActions.ACTION_COMMENT_BLOCK)
} else {
@@ -117,7 +113,6 @@ internal class CommentaryExtension : VimExtension {
// first non-whitespace character, then the caret is in the right place. If it's inserted at the first column,
// then the caret is now in a bit of a weird place. We can't detect this scenario, so we just have to accept
// the difference
// TODO: If we don't move the caret to the start offset, we should maintain the current logical position
if (resetCaret) {
editor.primaryCaret().moveToOffset(range.startOffset)
}
@@ -150,16 +145,6 @@ internal class CommentaryExtension : VimExtension {
putKeyMapping(MappingMode.N, injector.parser.parseKeys("<Plug>(CommentLine)"), owner, plugCommentaryLineKeys, true)
addCommand("Commentary", CommentaryCommandAliasHandler())
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, CommentaryOperatorFunction())
}
private class CommentaryOperatorFunction : OperatorFunction {
// todo make it multicaret
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
val range = injector.markService.getChangeMarks(editor.primaryCaret()) ?: return false
return doCommentary(editor, context, range, selectionType ?: SelectionType.CHARACTER_WISE, true)
}
}
/**
@@ -168,13 +153,19 @@ internal class CommentaryExtension : VimExtension {
* E.g. handles the `gc` in `gc_`, by setting the operator function, then invoking `g@` to receive the `_` motion to
* invoke the operator. This object is both the mapping handler and the operator function.
*/
private class CommentaryOperatorHandler : ExtensionHandler {
private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
injector.globalOptions().operatorfunc = OPERATOR_FUNC
setOperatorFunction(this)
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
}
// todo make it multicaret
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
val range = injector.markService.getChangeMarks(editor.primaryCaret()) ?: return false
return doCommentary(editor, context, range, selectionType ?: SelectionType.CHARACTER_WISE, true)
}
}
private class CommentaryMappingHandler : ExtensionHandler {

View File

@@ -19,23 +19,22 @@ import com.intellij.openapi.util.Key
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.getOffset
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.setChangeMarks
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.SelectionType.CHARACTER_WISE
import com.maddyhome.idea.vim.state.mode.selectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.extension.exportOperatorFunction
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.state.mode.mode
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition
@@ -73,15 +72,17 @@ internal class VimExchangeExtension : VimExtension {
putKeyMappingIfMissing(MappingMode.X, injector.parser.parseKeys("X"), owner, injector.parser.parseKeys(EXCHANGE_CMD), true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("cxc"), owner, injector.parser.parseKeys(EXCHANGE_CLEAR_CMD), true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("cxx"), owner, injector.parser.parseKeys(EXCHANGE_LINE_CMD), true)
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator())
}
companion object {
@NonNls private const val EXCHANGE_CMD = "<Plug>(Exchange)"
@NonNls private const val EXCHANGE_CLEAR_CMD = "<Plug>(ExchangeClear)"
@NonNls private const val EXCHANGE_LINE_CMD = "<Plug>(ExchangeLine)"
@NonNls private const val OPERATOR_FUNC = "ExchangeOperatorFunc"
@NonNls
const val EXCHANGE_CMD = "<Plug>(Exchange)"
@NonNls
const val EXCHANGE_CLEAR_CMD = "<Plug>(ExchangeClear)"
@NonNls
const val EXCHANGE_LINE_CMD = "<Plug>(ExchangeLine)"
val EXCHANGE_KEY = Key<Exchange>("exchange")
@@ -107,7 +108,7 @@ internal class VimExchangeExtension : VimExtension {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
injector.globalOptions().operatorfunc = OPERATOR_FUNC
setOperatorFunction(Operator(false))
executeNormalWithoutMapping(injector.parser.parseKeys(if (isLine) "g@_" else "g@"), editor.ij)
}
}
@@ -124,12 +125,12 @@ internal class VimExchangeExtension : VimExtension {
val mode = editor.mode
// Leave visual mode to create selection marks
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
Operator(true).apply(editor, context, mode.selectionType ?: SelectionType.CHARACTER_WISE)
Operator(true).apply(editor, context, mode.selectionType ?: CHARACTER_WISE)
}
}
}
private class Operator(private val isVisual: Boolean = false) : OperatorFunction {
private class Operator(private val isVisual: Boolean) : OperatorFunction {
fun Editor.getMarkOffset(mark: Mark) = IjVimEditor(this).getOffset(mark.line, mark.col)
fun SelectionType.getString() = when (this) {
SelectionType.CHARACTER_WISE -> "v"
@@ -147,7 +148,7 @@ internal class VimExchangeExtension : VimExtension {
else -> HighlighterTargetArea.EXACT_RANGE
}
val isVisualLine = ex.type == SelectionType.LINE_WISE
val endAdj = if (!(isVisualLine) && (hlArea == HighlighterTargetArea.EXACT_RANGE || isVisual)) 1 else 0
val endAdj = if (!(isVisualLine) && (hlArea == HighlighterTargetArea.EXACT_RANGE || (isVisual))) 1 else 0
return ijEditor.markupModel.addRangeHighlighter(
ijEditor.getMarkOffset(ex.start),
(ijEditor.getMarkOffset(ex.end) + endAdj).coerceAtMost(ijEditor.fileSize),
@@ -157,7 +158,7 @@ internal class VimExchangeExtension : VimExtension {
)
}
val currentExchange = getExchange(ijEditor, isVisual, selectionType ?: SelectionType.CHARACTER_WISE)
val currentExchange = getExchange(ijEditor, isVisual, selectionType ?: CHARACTER_WISE)
val exchange1 = ijEditor.getUserData(EXCHANGE_KEY)
if (exchange1 == null) {
val highlighter = highlightExchange(currentExchange)

View File

@@ -233,7 +233,7 @@ private object FileTypePatterns {
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
this.cMakePatterns
} else {
return null
this.htmlPatterns
}
}

View File

@@ -502,6 +502,13 @@ internal class NerdTree : VimExtension {
}
},
)
for (c in ('a'..'z') + ('A'..'Z')) {
val ks = KeyStroke.getKeyStroke(c)
if (ks !in actionsRoot) {
registerCommand(c.toString(), NerdAction.Code { _, _, _ -> })
}
}
}
companion object {

View File

@@ -11,8 +11,8 @@ package com.maddyhome.idea.vim.extension.paragraphmotion
import com.intellij.openapi.editor.Caret
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.getLineEndForOffset
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.normalizeOffset
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.extension.ExtensionHandler
@@ -45,8 +45,7 @@ internal class ParagraphMotion : VimExtension {
}
fun moveCaretToNextParagraph(editor: VimEditor, caret: Caret, count: Int): Int? {
return injector.searchHelper.findNextParagraph(editor, caret.vim, count, true)
?.let { editor.normalizeOffset(it, true) }
return injector.searchHelper.findNextParagraph(editor, caret.vim, count, true)?.let(editor::getLineEndForOffset)
}
}
}

View File

@@ -14,12 +14,12 @@ import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.ImmutableVimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.getLineEndOffset
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.SelectionType.CHARACTER_WISE
import com.maddyhome.idea.vim.state.mode.isLine
import com.maddyhome.idea.vim.state.mode.selectionType
import com.maddyhome.idea.vim.common.TextRange
@@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.exportOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.state.mode.mode
@@ -53,13 +53,11 @@ internal class ReplaceWithRegister : VimExtension {
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gr"), owner, injector.parser.parseKeys(RWR_OPERATOR), true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("grr"), owner, injector.parser.parseKeys(RWR_LINE), true)
putKeyMappingIfMissing(MappingMode.X, injector.parser.parseKeys("gr"), owner, injector.parser.parseKeys(RWR_VISUAL), true)
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator())
}
private class RwrVisual : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val typeInEditor = editor.mode.selectionType ?: SelectionType.CHARACTER_WISE
val typeInEditor = editor.mode.selectionType ?: CHARACTER_WISE
editor.sortedCarets().forEach { caret ->
val selectionStart = caret.selectionStart
val selectionEnd = caret.selectionEnd
@@ -75,7 +73,7 @@ internal class ReplaceWithRegister : VimExtension {
override val isRepeatable: Boolean = true
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
injector.globalOptions().operatorfunc = OPERATOR_FUNC
setOperatorFunction(Operator())
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
}
}
@@ -114,11 +112,11 @@ internal class ReplaceWithRegister : VimExtension {
editor.primaryCaret() to VimSelection.create(
range.startOffset,
range.endOffset - 1,
selectionType ?: SelectionType.CHARACTER_WISE,
selectionType ?: CHARACTER_WISE,
editor,
),
),
selectionType ?: SelectionType.CHARACTER_WISE,
selectionType ?: CHARACTER_WISE,
)
// todo multicaret
doReplace(ijEditor, editor.primaryCaret(), visualSelection)
@@ -134,10 +132,14 @@ internal class ReplaceWithRegister : VimExtension {
}
companion object {
@NonNls private const val RWR_OPERATOR = "<Plug>ReplaceWithRegisterOperator"
@NonNls private const val RWR_LINE = "<Plug>ReplaceWithRegisterLine"
@NonNls private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
@NonNls private const val OPERATOR_FUNC = "ReplaceWithRegisterOperatorFunc"
@NonNls
private const val RWR_OPERATOR = "<Plug>ReplaceWithRegisterOperator"
@NonNls
private const val RWR_LINE = "<Plug>ReplaceWithRegisterLine"
@NonNls
private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
private fun doReplace(editor: Editor, caret: ImmutableVimCaret, visualSelection: PutData.VisualSelection) {
val registerGroup = injector.registerGroup

View File

@@ -0,0 +1,30 @@
package com.maddyhome.idea.vim.extension.surround
import com.intellij.util.text.CharSequenceSubSequence
internal data class RepeatedCharSequence(val text: CharSequence, val count: Int) : CharSequence {
override val length = text.length * count
override fun get(index: Int): Char {
if (index < 0 || index >= length) throw IndexOutOfBoundsException()
return text[index % text.length]
}
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
return CharSequenceSubSequence(this, startIndex, endIndex)
}
override fun toString(): String {
return text.repeat(count)
}
companion object {
fun of(text: CharSequence, count: Int): CharSequence {
return when (count) {
0 -> ""
1 -> text
else -> RepeatedCharSequence(text, count)
}
}
}
}

View File

@@ -13,10 +13,10 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimChangeGroup
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.endsWithNewLine
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.setChangeMarks
import com.maddyhome.idea.vim.command.MappingMode
@@ -24,17 +24,18 @@ import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegisterForCaret
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
import com.maddyhome.idea.vim.extension.exportOperatorFunction
import com.maddyhome.idea.vim.state.mode.mode
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
@@ -77,15 +78,13 @@ internal class VimSurroundExtension : VimExtension {
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("ds"), owner, injector.parser.parseKeys("<Plug>DSurround"), true)
putKeyMappingIfMissing(MappingMode.XO, injector.parser.parseKeys("S"), owner, injector.parser.parseKeys("<Plug>VSurround"), true)
}
VimExtensionFacade.exportOperatorFunction(OPERATOR_FUNC, Operator())
}
private class YSurroundHandler : ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
injector.globalOptions().operatorfunc = OPERATOR_FUNC
setOperatorFunction(Operator(supportsMultipleCursors = false, count = 1)) // TODO
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
}
}
@@ -106,7 +105,7 @@ internal class VimSurroundExtension : VimExtension {
val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
if (lastNonWhiteSpaceOffset != null) {
val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
performSurround(pair, range, it)
performSurround(pair, range, it, count = operatorArguments.count1)
}
// it.moveToOffset(lineStartOffset)
}
@@ -126,15 +125,13 @@ internal class VimSurroundExtension : VimExtension {
private class VSurroundHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart
// NB: Operator ignores SelectionType anyway
if (!Operator().apply(editor, context, editor.mode.selectionType)) {
if (!Operator(supportsMultipleCursors = true, count = operatorArguments.count1).apply(editor, context, editor.mode.selectionType)) {
return
}
runWriteAction {
// Leave visual mode
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
editor.ij.caretModel.moveToOffset(selectionStart)
}
}
}
@@ -155,6 +152,10 @@ internal class VimSurroundExtension : VimExtension {
companion object {
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
}
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets
val surroundings = editor.sortedCarets()
.map {
@@ -262,21 +263,42 @@ internal class VimSurroundExtension : VimExtension {
}
}
private class Operator : OperatorFunction {
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
val ijEditor = editor.ij
val c = getChar(ijEditor)
private class Operator(private val supportsMultipleCursors: Boolean, private val count: Int) : OperatorFunction {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
val editor = vimEditor.ij
val c = getChar(editor)
if (c.code == 0) return true
val pair = getOrInputPair(c, ijEditor) ?: return false
// XXX: Will it work with line-wise or block-wise selections?
val range = getSurroundRange(editor.currentCaret()) ?: return false
performSurround(pair, range, editor.currentCaret(), selectionType == SelectionType.LINE_WISE)
val pair = getOrInputPair(c, editor) ?: return false
runWriteAction {
val change = VimPlugin.getChange()
if (supportsMultipleCursors) {
editor.runWithEveryCaretAndRestore {
applyOnce(editor, change, pair, count)
}
}
else {
applyOnce(editor, change, pair, count)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
}
}
return true
}
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
// XXX: Will it work with line-wise or block-wise selections?
val primaryCaret = editor.caretModel.primaryCaret
val range = getSurroundRange(primaryCaret.vim)
if (range != null) {
val start = RepeatedCharSequence.of(pair.first, count)
val end = RepeatedCharSequence.of(pair.second, count)
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, start)
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + start.length, end)
}
}
private fun getSurroundRange(caret: VimCaret): TextRange? {
val editor = caret.editor
val ijEditor = editor.ij
@@ -293,9 +315,7 @@ private val LOG = logger<VimSurroundExtension>()
private const val REGISTER = '"'
private const val OPERATOR_FUNC = "SurroundOperatorFunc"
private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern()
private val tagNameAndAttributesCapturePattern = "(\\S+)([^>]*)>".toPattern()
private val SURROUND_PAIRS = mapOf(
'b' to ("(" to ")"),
@@ -361,15 +381,15 @@ private fun getChar(editor: Editor): Char {
return res
}
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, tagsOnNewLines: Boolean = false) {
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) {
runWriteAction {
val editor = caret.editor
val change = VimPlugin.getChange()
val leftSurround = pair.first + if (tagsOnNewLines) "\n" else ""
val leftSurround = RepeatedCharSequence.of(pair.first + if (tagsOnNewLines) "\n" else "", count)
val isEOF = range.endOffset == editor.text().length
val hasNewLine = editor.endsWithNewLine()
val rightSurround = if (tagsOnNewLines) {
val rightSurround = (if (tagsOnNewLines) {
if (isEOF && !hasNewLine) {
"\n" + pair.second
} else {
@@ -377,7 +397,7 @@ private fun performSurround(pair: Pair<String, String>, range: TextRange, caret:
}
} else {
pair.second
}
}).let { RepeatedCharSequence.of(it, count) }
change.insertText(editor, caret, range.startOffset, leftSurround)
change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)

View File

@@ -78,7 +78,6 @@ import java.math.BigInteger
import java.util.*
import java.util.function.Consumer
import kotlin.math.max
import kotlin.math.min
/**
* Provides all the insert/replace related functionality
@@ -395,6 +394,7 @@ public class ChangeGroup : VimChangeGroupBase() {
context: ExecutionContext,
range: TextRange,
) {
val startPos = editor.offsetToBufferPosition(caret.offset.point)
val startOffset = editor.getLineStartForOffset(range.startOffset)
val endOffset = editor.getLineEndForOffset(range.endOffset)
val ijEditor = (editor as IjVimEditor).editor
@@ -419,11 +419,7 @@ public class ChangeGroup : VimChangeGroupBase() {
}
}
val afterAction = {
val firstLine = editor.offsetToBufferPosition(
min(startOffset.toDouble(), endOffset.toDouble()).toInt()
).line
val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
caret.moveToOffset(newOffset)
caret.moveToOffset(injector.motion.moveCaretToLineStartSkipLeading(editor, startPos.line))
restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
}
if (project != null) {
@@ -535,7 +531,7 @@ public class ChangeGroup : VimChangeGroupBase() {
val soff = editor.getLineStartOffset(l)
val eoff = editor.getLineEndOffset(l, true)
val woff = injector.motion.moveCaretToLineStartSkipLeading(editor, l)
val col = editor.offsetToBufferPosition(woff).column
val col = editor.offsetToVisualPosition(woff).column
val limit = max(0.0, (col + dir * indentConfig.getTotalIndent(count)).toDouble())
.toInt()
if (col > 0 || soff != eoff) {

View File

@@ -8,11 +8,9 @@
package com.maddyhome.idea.vim.group
import com.intellij.openapi.components.Service
import com.maddyhome.idea.vim.api.VimCommandGroupBase
/**
* @author Elliot Courant
*/
@Service
internal class CommandGroup : VimCommandGroupBase()

View File

@@ -20,6 +20,7 @@ import com.maddyhome.idea.vim.options.OptionAccessScope
*/
@Suppress("SpellCheckingInspection")
public open class GlobalIjOptions(scope: OptionAccessScope) : OptionsPropertiesBase(scope) {
public var closenotebooks: Boolean by optionProperty(IjOptions.closenotebooks)
public var ide: String by optionProperty(IjOptions.ide)
public var ideamarks: Boolean by optionProperty(IjOptions.ideamarks)
public var ideastatusicon: String by optionProperty(IjOptions.ideastatusicon)
@@ -28,16 +29,15 @@ public open class GlobalIjOptions(scope: OptionAccessScope) : OptionsPropertiesB
public val lookupkeys: StringListOptionValue by optionProperty(IjOptions.lookupkeys)
public var trackactionids: Boolean by optionProperty(IjOptions.trackactionids)
public var visualdelay: Int by optionProperty(IjOptions.visualdelay)
public var showmodewidget: Boolean by optionProperty(IjOptions.showmodewidget)
// Temporary options to control work-in-progress behaviour
public var closenotebooks: Boolean by optionProperty(IjOptions.closenotebooks)
public var commandOrMotionAnnotation: Boolean by optionProperty(IjOptions.commandOrMotionAnnotation)
public var exCommandAnnotation: Boolean by optionProperty(IjOptions.exCommandAnnotation)
public var oldundo: Boolean by optionProperty(IjOptions.oldundo)
public var showmodewidget: Boolean by optionProperty(IjOptions.showmodewidget)
public var unifyjumps: Boolean by optionProperty(IjOptions.unifyjumps)
public var useNewRegex: Boolean by optionProperty(IjOptions.useNewRegex)
public var exCommandAnnotation: Boolean by optionProperty(IjOptions.exCommandAnnotation)
public var vimscriptFunctionAnnotation: Boolean by optionProperty(IjOptions.vimscriptFunctionAnnotation)
public var commandOrMotionAnnotation: Boolean by optionProperty(IjOptions.commandOrMotionAnnotation)
public var useNewRegex: Boolean by optionProperty(IjOptions.useNewRegex)
}
/**

View File

@@ -33,6 +33,8 @@ public object IjOptions {
Options.overrideDefaultValue(Options.clipboard, VimString("ideaput,autoselect,exclude:cons\\|linux"))
}
public val closenotebooks: ToggleOption = addOption(ToggleOption("closenotebooks", GLOBAL, "closenotebooks", true))
public val exCommandAnnotation: ToggleOption = addOption(ToggleOption("excommandannotation", GLOBAL, "excommandannotation", true))
public val ide: StringOption = addOption(
StringOption("ide", GLOBAL, "ide", ApplicationNamesInfo.getInstance().fullProductNameWithEdition)
)
@@ -79,17 +81,13 @@ public object IjOptions {
"<Tab>,<Down>,<Up>,<Enter>,<Left>,<Right>,<C-Down>,<C-Up>,<PageUp>,<PageDown>,<C-J>,<C-Q>")
)
public val trackactionids: ToggleOption = addOption(ToggleOption("trackactionids", GLOBAL, "tai", false))
public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true))
public val visualdelay: UnsignedNumberOption = addOption(UnsignedNumberOption("visualdelay", GLOBAL, "visualdelay", 100))
// Temporary feature flags during development, not really intended for external use
public val closenotebooks: ToggleOption = addOption(ToggleOption("closenotebooks", GLOBAL, "closenotebooks", true, isHidden = true))
public val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isHidden = true))
public val exCommandAnnotation: ToggleOption = addOption(ToggleOption("excommandannotation", GLOBAL, "excommandannotation", true, isHidden = true))
public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", false, isHidden = true))
public val showmodewidget: ToggleOption = addOption(ToggleOption("showmodewidget", GLOBAL, "showmodewidget", false, isHidden = true))
public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true, isHidden = true))
public val useNewRegex: ToggleOption = addOption(ToggleOption("usenewregex", GLOBAL, "usenewregex", true, isHidden = true))
public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isHidden = true))
public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", true, isTemporary = true))
public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isTemporary = true))
public val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isTemporary = true))
public val showmodewidget: ToggleOption = addOption(ToggleOption("showmodewidget", GLOBAL, "showmodewidget", false, isTemporary = true))
public val useNewRegex: ToggleOption = addOption(ToggleOption("usenewregex", GLOBAL, "usenewregex", true, isTemporary = true))
// This needs to be Option<out VimDataType> so that it can work with derived option types, such as NumberOption, which
// derives from Option<VimInt>

View File

@@ -0,0 +1,68 @@
package com.maddyhome.idea.vim.group
import com.intellij.codeInsight.daemon.ReferenceImporter
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import java.util.function.BooleanSupplier
internal object MacroAutoImport {
fun run(editor: Editor, dataContext: DataContext) {
val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return
if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) {
return
}
val importers = ReferenceImporter.EP_NAME.extensionList
if (importers.isEmpty()) {
return
}
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Auto import", true) {
override fun run(indicator: ProgressIndicator) {
val fixes = ReadAction.nonBlocking<List<BooleanSupplier>> {
val fixes = mutableListOf<BooleanSupplier>()
file.accept(object : PsiRecursiveElementWalkingVisitor() {
override fun visitElement(element: PsiElement) {
for (reference in element.references) {
if (reference.resolve() != null) {
continue
}
for (importer in importers) {
importer.computeAutoImportAtOffset(editor, file, element.textRange.startOffset, true)
?.let(fixes::add)
}
}
super.visitElement(element)
}
})
return@nonBlocking fixes
}.executeSynchronously()
ApplicationManager.getApplication().invokeAndWait {
WriteCommandAction.writeCommandAction(project)
.withName("Auto Import")
.withGroupId("IdeaVimAutoImportAfterMacro")
.shouldRecordActionForActiveDocument(true)
.run<RuntimeException> {
fixes.forEach { it.asBoolean }
}
}
}
})
}
}

View File

@@ -7,10 +7,7 @@
*/
package com.maddyhome.idea.vim.group
import com.intellij.codeInsight.completion.CompletionPhase
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressManager
@@ -22,11 +19,11 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.MessageHelper.message
import com.maddyhome.idea.vim.macro.VimMacroBase
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
/**
* Used to handle playback of macros
*/
@Service
internal class MacroGroup : VimMacroBase() {
// If it's null, this is the top macro (as in most cases). If it's not null, this macro is executed from top macro
@@ -80,7 +77,7 @@ internal class MacroGroup : VimMacroBase() {
ProgressManager.getInstance().executeNonCancelableSection {
// Prevent autocompletion during macros.
// See https://github.com/JetBrains/ideavim/pull/772 for details
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion)
// CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion)
getInstance().handleKey(editor, key, context)
}
if (injector.messages.isError()) return@runnable
@@ -92,6 +89,9 @@ internal class MacroGroup : VimMacroBase() {
} finally {
keyStack.removeFirst()
}
if (!isInternalMacro) {
MacroAutoImport.run(editor.ij, context.ij)
}
}
if (isInternalMacro) {

View File

@@ -8,7 +8,6 @@
package com.maddyhome.idea.vim.group
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.components.Service
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.LogicalPosition
@@ -84,7 +83,6 @@ import kotlin.math.min
/**
* This handles all motion related commands and marks
*/
@Service
internal class MotionGroup : VimMotionGroupBase() {
override fun onAppCodeMovement(editor: VimEditor, caret: VimCaret, offset: Int, oldOffset: Int) {
AppCodeTemplates.onMovement(editor.ij, caret.ij, oldOffset < offset)

View File

@@ -21,7 +21,6 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.ide.CopyPasteManager
import com.intellij.openapi.keymap.KeymapUtil
@@ -56,7 +55,6 @@ import javax.swing.KeyStroke
* This service is can be used as application level and as project level service.
* If project is null, this means that this is an application level service and notification will be shown for all projects
*/
@Service(Service.Level.PROJECT, Service.Level.APP)
internal class NotificationService(private val project: Project?) {
// This constructor is used to create an applicationService
@Suppress("unused")

View File

@@ -214,8 +214,8 @@ public class SearchGroup extends IjVimSearchGroup implements PersistentStateComp
* @param patternOffset The pattern offset, e.g. `/{pattern}/{offset}`
* @param direction The direction to search
*/
@TestOnly
public void setLastSearchState(@SuppressWarnings("unused") @NotNull Editor editor, @NotNull String pattern,
@Override
public void setLastSearchState(@SuppressWarnings("unused") @NotNull VimEditor editor, @NotNull String pattern,
@NotNull String patternOffset, Direction direction) {
if (globalIjOptions(injector).getUseNewRegex()) {
super.setLastSearchState(pattern, patternOffset, direction);

View File

@@ -8,11 +8,9 @@
package com.maddyhome.idea.vim.group
import com.intellij.openapi.components.Service
import org.apache.commons.codec.binary.Base64
import org.jdom.Element
@Service
internal class XMLGroup {
/**
* Set the text of an XML element, safely encode it if needed.

View File

@@ -14,7 +14,6 @@ import com.intellij.ide.DataManager
import com.intellij.ide.PasteProvider
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.components.Service
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.ex.EditorEx
@@ -52,7 +51,6 @@ import com.maddyhome.idea.vim.state.mode.isChar
import com.maddyhome.idea.vim.state.mode.isLine
import java.awt.datatransfer.DataFlavor
@Service
internal class PutGroup : VimPutBase() {
override fun getProviderForPasteViaIde(

View File

@@ -8,7 +8,6 @@
package com.maddyhome.idea.vim.helper
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.CaretVisualAttributes
@@ -86,10 +85,7 @@ private fun Editor.updatePrimaryCaretVisualAttributes() {
caretModel.primaryCaret.visualAttributes = AttributesCache.getCaretVisualAttributes(this)
// Make sure the caret is visible as soon as it's set. It might be invisible while blinking
// NOTE: At the moment, this causes project leak in tests
if (!ApplicationManager.getApplication().isUnitTestMode) {
(this as? EditorEx)?.setCaretVisible(true)
}
}
private fun Editor.updateSecondaryCaretsVisualAttributes() {

View File

@@ -329,7 +329,7 @@ public class EditorHelper {
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
// For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.

View File

@@ -12,6 +12,7 @@ package com.maddyhome.idea.vim.helper
import com.intellij.codeWithMe.ClientId
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.CaretState
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
@@ -19,6 +20,8 @@ import com.intellij.util.ui.table.JBTableRowEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.group.IjOptionConstants
import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.inBlockSelection
import java.awt.Component
import javax.swing.JComponent
import javax.swing.JTable
@@ -93,3 +96,41 @@ internal val Caret.vimLine: Int
*/
internal val Editor.vimLine: Int
get() = this.caretModel.currentCaret.vimLine
internal inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) {
val caretModel = this.caretModel
val carets = if (this.vim.inBlockSelection) null else caretModel.allCarets
if (carets == null || carets.size == 1) {
action()
}
else {
var initialDocumentSize = this.document.textLength
var documentSizeDifference = 0
val caretOffsets = carets.map { it.selectionStart to it.selectionEnd }
val restoredCarets = mutableListOf<CaretState>()
caretModel.removeSecondaryCarets()
for ((selectionStart, selectionEnd) in caretOffsets) {
if (selectionStart == selectionEnd) {
caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference)
}
else {
caretModel.primaryCaret.setSelection(
selectionStart + documentSizeDifference,
selectionEnd + documentSizeDifference
)
}
action()
restoredCarets.add(caretModel.caretsAndSelections.single())
val documentLength = this.document.textLength
documentSizeDifference += documentLength - initialDocumentSize
initialDocumentSize = documentLength
}
caretModel.caretsAndSelections = restoredCarets
}
}

View File

@@ -14,7 +14,6 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.api.normalizeVisualColumn
import com.maddyhome.idea.vim.api.options
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.state.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenHeight
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenWidth
import com.maddyhome.idea.vim.helper.EditorHelper.getNonNormalizedVisualLineAtBottomOfScreen
@@ -29,6 +28,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.VimStateMachine
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
@@ -56,7 +56,7 @@ internal object ScrollViewHelper {
// that this needs to be replaced as a more or less dumb line for line rewrite.
val topLine = getVisualLineAtTopOfScreen(editor)
val bottomLine = getVisualLineAtBottomOfScreen(editor)
val lastLine = vimEditor.getVisualLineCount() - 1
val lastLine = vimEditor.getVisualLineCount() + editor.settings.additionalLinesCount
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
val scrollOffset = injector.options(vimEditor).scrolloff

View File

@@ -26,13 +26,15 @@ import com.intellij.spellchecker.SpellCheckerSeveritiesProvider;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.EngineEditorHelperKt;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.regexp.*;
import com.maddyhome.idea.vim.regexp.match.VimMatchResult;
import com.maddyhome.idea.vim.common.CharacterPosition;
import com.maddyhome.idea.vim.common.Direction;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.regexp.*;
import com.maddyhome.idea.vim.regexp.match.VimMatchResult;
import com.maddyhome.idea.vim.regexp.CharPointer;
import com.maddyhome.idea.vim.regexp.RegExp;
import com.maddyhome.idea.vim.state.VimStateMachine;
import com.maddyhome.idea.vim.state.mode.Mode;
import it.unimi.dsi.fastutil.ints.IntComparator;

View File

@@ -31,8 +31,4 @@ public object StringHelper {
return Arrays.stream(string).flatMap { o: String -> injector.parser.parseKeys(o).stream() }
.collect(Collectors.toList())
}
@JvmStatic
@Deprecated("Use key.isCloseKeyStroke()", ReplaceWith("key.isCloseKeyStroke()"))
public fun isCloseKeyStroke(key: KeyStroke): Boolean = key.isCloseKeyStroke()
}

View File

@@ -14,6 +14,7 @@ import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.command.undo.UndoManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
@@ -21,6 +22,8 @@ import com.maddyhome.idea.vim.common.ChangesListener
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.state.mode.inVisualMode
import com.maddyhome.idea.vim.undo.UndoRedoBase
/**
@@ -39,6 +42,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
restoreVisualMode(editor)
} else {
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
@@ -74,6 +78,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
if (undoManager.isRedoAvailable(fileEditor)) {
if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
restoreVisualMode(editor)
} else {
undoManager.redo(fileEditor)
CommandProcessor.getInstance().runUndoTransparentAction {
@@ -131,4 +136,21 @@ internal class UndoRedoHelper : UndoRedoBase() {
val hasChanges: Boolean
get() = changeListener.hasChanged || initialPath != editor.getPath()
}
private fun restoreVisualMode(editor: VimEditor) {
if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
// Visual block selection is restored into multiple carets, so multi-carets that form a block are always
// identified as visual block mode, leading to false positives.
// Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
// visual block mode.
val wantedMode = if (detectedMode == SelectionType.BLOCK_WISE)
SelectionType.CHARACTER_WISE
else
detectedMode
VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
}
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.helper
import com.intellij.ide.plugins.StandalonePluginUpdateChecker
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.icons.VimIcons
@Service(Service.Level.APP)
internal class VimStandalonePluginUpdateChecker : StandalonePluginUpdateChecker(
VimPlugin.getPluginId(),
updateTimestampProperty = PROPERTY_NAME,
NotificationService.IDEAVIM_STICKY_GROUP,
VimIcons.IDEAVIM,
) {
override fun skipUpdateCheck(): Boolean = VimPlugin.isNotEnabled() || "dev" in VimPlugin.getVersion()
companion object {
private const val PROPERTY_NAME = "ideavim.statistics.timestamp"
val instance: VimStandalonePluginUpdateChecker = service()
}
}

View File

@@ -21,6 +21,6 @@ public final class VimIcons {
public static final @NotNull Icon YOUTRACK = load("/icons/youtrack.svg");
private static @NotNull Icon load(@NotNull @NonNls String path) {
return IconManager.getInstance().getIcon(path, VimIcons.class.getClassLoader());
return IconManager.getInstance().getIcon(path, VimIcons.class);
}
}

View File

@@ -9,19 +9,11 @@
package com.maddyhome.idea.vim.inspections
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiEditorUtil
import com.maddyhome.idea.vim.extension.ExtensionBeanClass
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.vimscript.model.commands.SetCommand
import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser
internal class UsePlugSyntaxInspection : LocalInspectionTool() {
override fun getGroupDisplayName(): String {
@@ -31,54 +23,11 @@ internal class UsePlugSyntaxInspection : LocalInspectionTool() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
val file = holder.file
if (file.name != ".ideavimrc" && file.name != "_ideavimrc") return PsiElementVisitor.EMPTY_VISITOR
val plugins = buildPlugins()
return object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) {
if (element !is LeafPsiElement) return
val myScript = VimscriptParser.parse(element.text)
myScript.units.forEach { unit ->
if (unit is SetCommand) {
val argument = unit.argument
val alias = plugins[argument]
if (alias != null) {
holder.registerProblem(
element,
unit.rangeInScript.let { TextRange(it.startOffset, it.endOffset - 1) },
"""
Use `Plug` syntax for defining extensions
""".trimIndent(),
object : LocalQuickFix {
override fun getFamilyName(): String {
return "Use Plug syntax"
}
override fun applyFix(p0: Project, p1: ProblemDescriptor) {
val editor = PsiEditorUtil.findEditor(file)
editor?.document?.replaceString(
unit.rangeInScript.startOffset,
unit.rangeInScript.endOffset - 1,
"Plug '$alias'"
)
holder.registerProblem(element, TextRange.create(10, 20), "Hi there")
}
}
)
}
}
}
}
}
}
private fun buildPlugins(): HashMap<String, String> {
val res = HashMap<String, String>()
VimExtension.EP_NAME.extensions.forEach { extension: ExtensionBeanClass ->
val alias = extension.aliases?.first { it.name?.count { it == '/' } == 1 }?.name
?: extension.aliases?.firstOrNull()?.name
val name = extension.name
if (alias != null && name != null) {
res[name] = alias
}
}
return res
}
}

View File

@@ -8,7 +8,7 @@
package com.maddyhome.idea.vim.listener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.editor.Editor
import org.acejump.session.SessionManager
@@ -16,11 +16,12 @@ import org.acejump.session.SessionManager
* Key handling for IdeaVim should be updated to editorHandler usage. In this case this class can be safely removed.
*/
@Suppress("DEPRECATION")
internal interface AceJumpService {
fun isActive(editor: Editor): Boolean
companion object {
fun getInstance(): AceJumpService? = ApplicationManager.getApplication().getService(AceJumpService::class.java)
fun getInstance(): AceJumpService? = ServiceManager.getService(AceJumpService::class.java)
}
}

View File

@@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.impl.ScrollingModelImpl
import com.intellij.openapi.project.DumbAwareToggleAction
import com.intellij.openapi.util.TextRange
import com.maddyhome.idea.vim.KeyHandler
@@ -56,6 +57,7 @@ internal object IdeaSpecifics {
private val surrounderAction =
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null
private var caretOffset = -1
private var completionPrevDocumentLength: Int? = null
private var completionPrevDocumentOffset: Int? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
@@ -64,6 +66,7 @@ internal object IdeaSpecifics {
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) {
editor = hostEditor
caretOffset = hostEditor.caretModel.offset
}
val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
@@ -95,7 +98,8 @@ internal object IdeaSpecifics {
if (VimPlugin.isNotEnabled()) return
val editor = editor
if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
if (editor != null) {
if (action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
val prevDocumentLength = completionPrevDocumentLength
val prevDocumentOffset = completionPrevDocumentOffset
@@ -122,16 +126,28 @@ internal object IdeaSpecifics {
)
}
) {
editor?.let {
val commandState = it.vim.vimStateMachine
val commandState = editor.vim.vimStateMachine
commandState.mode = Mode.NORMAL()
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
KeyHandler.getInstance().reset(it.vim)
}
VimPlugin.getChange().insertBeforeCursor(editor.vim, event.dataContext.vim)
KeyHandler.getInstance().reset(editor.vim)
}
//endregion
if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
val scrollModel = editor.scrollingModel as ScrollingModelImpl
if (scrollModel.isScrollingNow) {
val v = scrollModel.verticalScrollOffset
val h = scrollModel.horizontalScrollOffset
scrollModel.finishAnimation()
scrollModel.scroll(h, v)
scrollModel.finishAnimation()
}
injector.scroll.scrollCaretIntoView(editor.vim)
}
}
this.editor = null
this.caretOffset = -1
}
}

View File

@@ -66,14 +66,15 @@ import com.maddyhome.idea.vim.group.IjOptions
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.OptionGroup
import com.maddyhome.idea.vim.group.ScrollGroup
import com.maddyhome.idea.vim.group.SearchGroup
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl
import com.maddyhome.idea.vim.group.visual.VimVisualTimer
import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.handler.correctorRequester
import com.maddyhome.idea.vim.handler.keyCheckRequests
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
import com.maddyhome.idea.vim.helper.StrictMode
import com.maddyhome.idea.vim.helper.VimStandalonePluginUpdateChecker
import com.maddyhome.idea.vim.helper.exitSelectMode
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.forceBarCursor
@@ -90,6 +91,8 @@ import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.VimStateMachine
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.inSelectMode
import com.maddyhome.idea.vim.state.mode.mode
import com.maddyhome.idea.vim.state.mode.selectionType
@@ -303,6 +306,16 @@ internal object VimListenerManager {
class VimFileEditorManagerListener : FileEditorManagerListener {
override fun selectionChanged(event: FileEditorManagerEvent) {
if (VimPlugin.isNotEnabled()) return
val newEditor = event.newEditor
if (newEditor is TextEditor) {
val editor = newEditor.editor
if (editor.isInsertMode) {
VimStateMachine.getInstance(editor).mode = Mode.NORMAL()
KeyHandler.getInstance().reset(editor.vim)
}
}
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
FileGroup.fileEditorManagerSelectionChangedCallback(event)
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
@@ -367,8 +380,6 @@ internal object VimListenerManager {
event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
}
VimStandalonePluginUpdateChecker.instance.pluginUsed()
}
override fun editorReleased(event: EditorFactoryEvent) {
@@ -431,6 +442,8 @@ internal object VimListenerManager {
}
private object EditorSelectionHandler : SelectionListener {
private var myMakingChanges = false
/**
* This event is executed for each caret using [com.intellij.openapi.editor.CaretModel.runForEachCaret]
*/
@@ -479,9 +492,22 @@ internal object VimListenerManager {
IdeaSelectionControl.controlNonVimSelectionChange(editor)
}
if (document is DocumentEx && document.isInEventsHandling) {
if (myMakingChanges || document is DocumentEx && document.isInEventsHandling) {
return
}
myMakingChanges = true
try {
// Synchronize selections between editors
val newRange = selectionEvent.newRange
for (e in localEditors(document)) {
if (e != editor) {
e.selectionModel.vimSetSystemSelectionSilently(newRange.startOffset, newRange.endOffset)
}
}
} finally {
myMakingChanges = false
}
}
}

View File

@@ -43,10 +43,6 @@ internal class IjVimApplication : VimApplicationBase() {
return ApplicationManager.getApplication().isUnitTestMode
}
override fun isInternal(): Boolean {
return ApplicationManager.getApplication().isInternal
}
override fun postKey(stroke: KeyStroke, editor: VimEditor) {
val component: Component = SwingUtilities.getAncestorOfClass(Window::class.java, editor.ij.component)
val event = createKeyEvent(stroke, component)

View File

@@ -32,7 +32,7 @@ import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser.parseExpression
import org.jetbrains.annotations.TestOnly
import javax.swing.KeyStroke
public open class IjVimSearchGroup : VimSearchGroupBase() {
public abstract class IjVimSearchGroup : VimSearchGroupBase() {
init {
// TODO: Investigate migrating these listeners to use the effective value change listener

View File

@@ -15,7 +15,7 @@ import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesColle
internal class ActionTracker : CounterUsagesCollector() {
companion object {
private val GROUP = EventLogGroup("vim.actions", 1, "FUS")
private val GROUP = EventLogGroup("vim.actions", 1)
private val TRACKED_ACTIONS = GROUP.registerEvent(
"tracked",
EventFields.StringValidatedByCustomRule("action_id", ActionRuleValidator::class.java),

View File

@@ -48,7 +48,7 @@ internal class OptionsState : ApplicationUsagesCollector() {
}
companion object {
private val GROUP = EventLogGroup("vim.options", 1, "FUS")
private val GROUP = EventLogGroup("vim.options", 1)
private val IDEAJOIN = BooleanEventField(IjOptions.ideajoin.name)
private val IDEAMARKS = BooleanEventField(IjOptions.ideamarks.name)

View File

@@ -31,7 +31,7 @@ internal class PluginState : ApplicationUsagesCollector() {
}
companion object {
private val GROUP = EventLogGroup("vim.common", 1, "FUS")
private val GROUP = EventLogGroup("vim.common", 1)
val extensionNames = listOf("textobj-entire", "argtextobj", "ReplaceWithRegister", "vim-paragraph-motion", "highlightedyank", "multiple-cursors", "exchange", "NERDTree", "surround", "commentary", "matchit", "textobj-indent")
val enabledExtensions = HashSet<String>()

View File

@@ -72,7 +72,7 @@ internal class ShortcutConflictState : ApplicationUsagesCollector() {
}
companion object {
private val GROUP = EventLogGroup("vim.handlers", 1, "FUS")
private val GROUP = EventLogGroup("vim.handlers", 1)
private val keyStrokes = listOf(
KeyStroke.getKeyStroke('1'.code, CTRL_DOWN_MASK),

View File

@@ -37,7 +37,7 @@ internal class VimscriptState : ApplicationUsagesCollector() {
}
companion object {
private val GROUP = EventLogGroup("vim.vimscript", 1, "FUS")
private val GROUP = EventLogGroup("vim.vimscript", 1)
val sourcedFiles = HashSet<String>()
val extensionsEnabledWithPlug = HashSet<String>()

View File

@@ -31,7 +31,7 @@ internal class Troubleshooter {
fun findIncorrectMappings(): List<Problem> {
val problems = ArrayList<Problem>()
MappingMode.entries.forEach { mode ->
MappingMode.values().forEach { mode ->
injector.keyGroup.getKeyMapping(mode).getByOwner(MappingOwner.IdeaVim.InitScript).forEach { (_, to) ->
if (to is ToKeysMappingInfo) {
if (":action" in to.toKeys.joinToString { it.keyChar.toString() }) {

View File

@@ -12,7 +12,6 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.diagnostic.logger
@@ -160,8 +159,8 @@ internal class ReloadVimRc : DumbAwareAction() {
internal class ReloadFloatingToolbar : AbstractFloatingToolbarProvider(ACTION_GROUP) {
override val autoHideable: Boolean = false
override fun register(dataContext: DataContext, component: FloatingToolbarComponent, parentDisposable: Disposable) {
super.register(dataContext, component, parentDisposable)
override fun register(component: FloatingToolbarComponent, parentDisposable: Disposable) {
super.register(component, parentDisposable)
val action = {
component.scheduleShow()
}

View File

@@ -9,16 +9,15 @@ package com.maddyhome.idea.vim.ui
import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionToolbarPosition
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.keymap.KeymapUtil
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.ui.ComboBoxTableRenderer
import com.intellij.openapi.ui.StripeTable
import com.intellij.openapi.wm.IdeFocusManager
import com.intellij.ui.DumbAwareActionButton
import com.intellij.ui.HyperlinkLabel
import com.intellij.ui.IdeBorderFactory
import com.intellij.ui.JBColor
@@ -170,7 +169,7 @@ internal class VimEmulationConfigurable : Configurable {
return getColumnModel().getColumn(column.index)
}
private class ShortcutOwnerRenderer : ComboBoxTableRenderer<ShortcutOwner>(ShortcutOwner.entries.toTypedArray()) {
private class ShortcutOwnerRenderer : ComboBoxTableRenderer<ShortcutOwner>(ShortcutOwner.values()) {
override fun customizeComponent(owner: ShortcutOwner, table: JTable, isSelected: Boolean) {
super.customizeComponent(owner, table, isSelected)
if (owner == ShortcutOwner.UNDEFINED) {
@@ -193,7 +192,7 @@ internal class VimEmulationConfigurable : Configurable {
private val ourMembers: MutableMap<Int, Column> = HashMap()
init {
for (column in entries) {
for (column in values()) {
ourMembers[column.index] = column
}
}
@@ -225,7 +224,7 @@ internal class VimEmulationConfigurable : Configurable {
}
override fun getColumnCount(): Int {
return Column.entries.size
return Column.values().size
}
override fun getValueAt(rowIndex: Int, columnIndex: Int): Any? {
@@ -295,21 +294,19 @@ internal class VimEmulationConfigurable : Configurable {
private class CopyForRcAction(
private val myModel: VimShortcutConflictsTable.Model,
) : DumbAwareAction(
) : DumbAwareActionButton(
"Copy Config for .ideavimrc",
"Copy config for .ideavimrc in sethandler format",
AllIcons.Actions.Copy,
) {
override fun update(e: AnActionEvent) {
override fun updateButton(e: AnActionEvent) {
val enabled: Boolean = myModel.rows.stream().anyMatch {
it.owner is AllModes && (it.owner as AllModes).owner != ShortcutOwner.UNDEFINED
}
e.presentation.isEnabled = enabled
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun actionPerformed(e: AnActionEvent) {
val stringBuilder = StringBuilder()
for (row in myModel.rows) {
@@ -331,16 +328,14 @@ internal class VimEmulationConfigurable : Configurable {
class ResetHandlersAction(
private val myModel: VimShortcutConflictsTable.Model,
private val myTable: VimShortcutConflictsTable,
) : DumbAwareAction("Reset Handlers", "Reset handlers", AllIcons.General.Reset) {
override fun update(e: AnActionEvent) {
) : DumbAwareActionButton("Reset Handlers", "Reset handlers", AllIcons.General.Reset) {
override fun updateButton(e: AnActionEvent) {
val enabled: Boolean = myModel.rows.stream().anyMatch {
it.owner is AllModes && (it.owner as AllModes).owner != ShortcutOwner.UNDEFINED
}
e.presentation.isEnabled = enabled
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun actionPerformed(e: AnActionEvent) {
TableUtil.stopEditing(myTable)
for (row in myModel.rows) {

View File

@@ -121,11 +121,16 @@ public class ExTextField extends JTextField {
}
void setType(@NotNull String type) {
String hkey = switch (type.charAt(0)) {
case '/', '?' -> HistoryConstants.SEARCH;
case ':' -> HistoryConstants.COMMAND;
default -> null;
};
String hkey = null;
switch (type.charAt(0)) {
case '/':
case '?':
hkey = HistoryConstants.SEARCH;
break;
case ':':
hkey = HistoryConstants.COMMAND;
break;
}
if (hkey != null) {
history = VimPlugin.getHistory().getEntries(hkey, 0, 0);
@@ -135,7 +140,7 @@ public class ExTextField extends JTextField {
/**
* Stores the current text for use in filtering history. Required for scrolling through multiple history entries
* <p>
*
* Called whenever the text is changed, either by typing, or by special characters altering the text (e.g. Delete)
*/
void saveLastEntry() {
@@ -299,10 +304,7 @@ public class ExTextField extends JTextField {
*/
void cancel() {
clearCurrentAction();
Editor editor = EditorHolderService.getInstance().getEditor();
if (editor != null) {
VimPlugin.getProcess().cancelExEntry(new IjVimEditor(editor), true);
}
VimPlugin.getProcess().cancelExEntry(new IjVimEditor(EditorHolderService.getInstance().getEditor()), true);
}
public void setCurrentAction(@NotNull MultiStepAction action, char pendingIndicator) {
@@ -320,7 +322,7 @@ public class ExTextField extends JTextField {
/**
* Text to show while composing a digraph or inserting a literal or register
* <p>
*
* The prompt character is inserted directly into the text of the text field, rather than drawn over the top of the
* current character. When the action has been completed, the new character(s) are either inserted or overwritten,
* depending on the insert/overwrite status of the text field. This mimics Vim's behaviour.
@@ -489,7 +491,7 @@ public class ExTextField extends JTextField {
/**
* Updates the bounds of the caret and repaints those bounds.
* <p>
*
* This method is not guaranteed to be called before paint(). The bounds are for use by repaint().
*
* @param r The current location of the caret, usually provided by MapToView. The x and y appear to be the upper

View File

@@ -153,7 +153,7 @@ public class ModeWidgetPopup : AnAction() {
group {
row {
label(MessageHelper.getMessage("widget.mode.popup.field.theme"))
comboBox(ModeWidgetTheme.entries).bindItem(modeColors::theme.toNullableProperty())
comboBox(ModeWidgetTheme.values().toList()).bindItem(modeColors::theme.toNullableProperty())
}
row { browserLink("Suggest your theme", "https://youtrack.jetbrains.com/issue/VIM-1377/Normal-mode-needs-to-be-more-obvious") }
}.topGap(TopGap.NONE).visibleIf(!advancedSettings.selected)
@@ -360,7 +360,7 @@ public enum class ModeWidgetTheme(private var value: String) {
public companion object {
public fun parseString(string: String): ModeWidgetTheme? {
return entries.firstOrNull { it.value == string }
return ModeWidgetTheme.values().firstOrNull { it.value == string }
}
public fun getDefaultTheme(): ModeWidgetTheme = TERM

View File

@@ -8,20 +8,24 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.MotionGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.ScrollGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimScrollGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.ChangeGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimChangeGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.CommandGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.VimMarkServiceImpl"
serviceInterface="com.maddyhome.idea.vim.api.VimMarkService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.VimJumpServiceImpl"
serviceInterface="com.maddyhome.idea.vim.api.VimJumpService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.RegisterGroup"
serviceInterface="com.maddyhome.idea.vim.register.VimRegisterGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.XMLGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.FileGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.SearchGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.ProcessGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimProcessGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.MacroGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.DigraphGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/>
@@ -34,6 +38,7 @@
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.visual.VisualMotionGroup"
serviceInterface="com.maddyhome.idea.vim.api.VimVisualMotionGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.yank.YankGroupBase"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.copy.PutGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.vimscript.services.IjVariableService"
serviceInterface="com.maddyhome.idea.vim.vimscript.services.VariableService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.IjStatisticsService"
@@ -48,5 +53,6 @@
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.IjVimSystemInfoService"
serviceInterface="com.maddyhome.idea.vim.api.SystemInfoService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.NotificationService"/>
</extensions>
</idea-plugin>

View File

@@ -1,12 +1,4 @@
<!--
~ Copyright 2003-2023 The IdeaVim authors
~
~ Use of this source code is governed by an MIT-style
~ license that can be found in the LICENSE.txt file or at
~ https://opensource.org/licenses/MIT.
-->
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
<name>IdeaVim</name>
<id>IdeaVIM</id>
<description><![CDATA[
@@ -21,13 +13,13 @@
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
</ul>
]]></description>
<version>SNAPSHOT</version>
<version>chylex</version>
<vendor>JetBrains</vendor>
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
<!-- Check for [Version Update] tag in YouTrack as well -->
<!-- Also, please update the value in build.gradle.kts file-->
<idea-version since-build="233.11799.30"/>
<idea-version since-build="232"/>
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
<depends>com.intellij.modules.platform</depends>
@@ -62,6 +54,7 @@
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable groupId="editor" instance="com.maddyhome.idea.vim.ui.VimEmulationConfigurable"/>
<projectService serviceImplementation="com.maddyhome.idea.vim.group.NotificationService"/>
<projectService serviceImplementation="com.maddyhome.idea.vim.group.LastTabService"/>
<statusBarWidgetFactory id="IdeaVimMode" implementation="com.maddyhome.idea.vim.ui.widgets.mode.ModeWidgetFactory" order="last, before Memory"/>
<statusBarWidgetFactory id="IdeaVim-Icon" implementation="com.maddyhome.idea.vim.ui.StatusBarIconFactory" order="last, before IdeaVimMode"/>
@@ -157,5 +150,6 @@
</group>
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
<action id="VimJumpToSource" class="com.intellij.diff.actions.impl.OpenInEditorAction" />
</actions>
</idea-plugin>

View File

@@ -137,7 +137,7 @@ widget.mode.popup.tab.dark=Dark Theme
widget.mode.popup.color.instruction=Use HEX color values for exact colors; use v:status_bar_bg to use your IDE's status bar background color and v:status_bar_fg for the foreground
widget.mode.popup.field.theme=Widget theme:
widget.mode.popup.field.advanced.settings=Full color customization (advanced)
widget.mode.popup.group.title.full.customization=Full Customization
widget.mode.popup.group.title.full.customization=Full customization
widget.mode.popup.group.normal.title=Normal Mode
widget.mode.popup.group.insert.title=Insert Mode
widget.mode.popup.group.replace.title=Replace Mode

View File

@@ -9,10 +9,10 @@ package org.jetbrains.plugins.ideavim.action
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.helper.vimStateMachine
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase

View File

@@ -15,7 +15,6 @@ import com.maddyhome.idea.vim.key.MappingOwner
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
class RepeatActionTest : VimTestCase() {
@@ -111,20 +110,4 @@ class RepeatActionTest : VimTestCase() {
)
}
}
@Test
@Disabled("This test throws `Recursive runForEachCaret invocations are not allowed`")
fun `repeat command with execution of ij action`() {
doTest(
"c<C-End><C-I><esc>.",
"""
${c}1234567890
${c}1234567890
""".trimIndent(),
"""
${c}1234567890
${c}1234567890
""".trimIndent()
)
}
}

View File

@@ -11,8 +11,8 @@ package org.jetbrains.plugins.ideavim.action
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.key.MappingOwner
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase

View File

@@ -1,150 +0,0 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.action.change
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
class OperatorActionTest : VimTestCase() {
@Test
fun `test operator action throws error if operatorfunc is empty`() {
doTest("g@w", "lorem ipsum", "lorem ipsum")
assertPluginErrorMessageContains("E774: 'operatorfunc' is empty")
}
@Test
fun `test operator action throws error if operatorfunc is name of unknown function`() {
doTest("g@w", "lorem ipsum", "lorem ipsum") {
enterCommand("set operatorfunc=Foo")
}
assertPluginErrorMessageContains("E117: Unknown function: Foo")
}
@Test
fun `test operator action with function name`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"xxxxx ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal `[v`]rx"
|endfunction
""".trimMargin())
enterCommand("noremap gx :set opfunc=Redact<CR>g@")
}
}
@Test
fun `test operator action with character wise motion`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"charlorem ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal i" . a:type
|endfunction
""".trimMargin())
enterCommand("noremap gx :set opfunc=Redact<CR>g@")
}
}
@Test
fun `test operator action with linewise motion`() {
doTest("Vgx",
"lorem ipsum dolor sit amet",
"linelorem ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal i" . a:type
|endfunction
""".trimMargin())
enterCommand("noremap gx <Esc>:set opfunc=Redact<CR>gvg@")
}
}
@Test
fun `test operator action with blockwise motion`() {
doTest("<C-V>gx",
"lorem ipsum dolor sit amet",
"blocklorem ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal i" . a:type
|endfunction
""".trimMargin())
enterCommand("noremap gx <Esc>:set opfunc=Redact<CR>gvg@")
}
}
@Test
fun `test operator action with function`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"xxxxx ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal `[v`]rx"
|endfunction
""".trimMargin())
enterCommand("noremap gx :set opfunc=function('Redact')<CR>g@")
}
}
@Test
fun `test operator action throws error with unknown function`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"lorem ipsum dolor sit amet"
) {
enterCommand("noremap gx :set opfunc=function('Foo')<CR>g@")
}
assertPluginErrorMessageContains("E117: Unknown function: Foo")
}
@Test
fun `test operator function with funcref`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"xxxxx ipsum dolor sit amet"
) {
executeVimscript("""function! Redact(type)
| execute "normal `[v`]rx"
|endfunction
""".trimMargin())
enterCommand("noremap gx :set opfunc=funcref('Redact')<CR>g@")
}
}
@Test
fun `test operator action throws error with unknown function ref`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"lorem ipsum dolor sit amet"
) {
enterCommand("noremap gx :set opfunc=funcref('Foo')<CR>g@")
}
assertPluginErrorMessageContains("E117: Unknown function: Foo")
}
@Test
@Disabled(":set does not correctly parse the quotes in the lambda syntax")
// The parser is treating the second double-quote char as a comment. The argument to the command is parsed as:
// opfunc={ arg -> execute "`[v`]rx
// The map command is properly handled - the `<CR>g@` is correctly understood, and the full lambda is passed to the
// parser, but the parser does not fully handle the text
fun `test operator function with lambda`() {
doTest("gxe",
"lorem ipsum dolor sit amet",
"lorem ipsum dolor sit amet"
) {
enterCommand("noremap gx :set opfunc={ arg -> execute \"`[v`]rx\" }<CR>g@")
}
}
}

View File

@@ -10,9 +10,9 @@ package org.jetbrains.plugins.ideavim.action.change
import com.intellij.idea.TestFor
import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test

View File

@@ -11,9 +11,9 @@
package org.jetbrains.plugins.ideavim.action.change.delete
import com.maddyhome.idea.vim.VimPlugin
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest

View File

@@ -9,9 +9,9 @@
package org.jetbrains.plugins.ideavim.action.change.delete
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase

View File

@@ -10,8 +10,8 @@
package org.jetbrains.plugins.ideavim.action.change.delete
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -13,10 +13,10 @@ import com.intellij.notification.EventLog
import com.intellij.notification.Notification
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.impl.OptionTest

View File

@@ -18,11 +18,11 @@ import com.intellij.testFramework.ExtensionTestUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.rangeOf
import org.junit.jupiter.api.Test

View File

@@ -9,8 +9,8 @@
package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.rangeOf
import org.junit.jupiter.api.Test

View File

@@ -13,9 +13,9 @@ import com.intellij.ide.CopyPasteManagerEx
import com.intellij.openapi.ide.CopyPasteManager
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -12,11 +12,11 @@ package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.annotations.TestWithoutPrimaryClipboard
import org.jetbrains.plugins.ideavim.rangeOf

View File

@@ -10,12 +10,12 @@ package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.jetbrains.plugins.ideavim.annotations.TestWithoutPrimaryClipboard
import org.junit.Ignore

View File

@@ -12,11 +12,11 @@ package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test

View File

@@ -13,6 +13,7 @@ package org.jetbrains.plugins.ideavim.action.motion.gn
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
@@ -85,7 +86,7 @@ class GnNextTextObjectTest : VimTestCase() {
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
configureByText(before)
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
typeText(keys)
assertState(after)
assertState(Mode.NORMAL())

View File

@@ -13,6 +13,7 @@ package org.jetbrains.plugins.ideavim.action.motion.gn
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
@@ -63,7 +64,7 @@ class GnPreviousTextObjectTest : VimTestCase() {
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
configureByText(before)
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
typeText(keys)
assertState(after)
assertState(Mode.NORMAL())

View File

@@ -12,6 +12,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.SkipNeovimReason
@@ -57,7 +58,7 @@ class VisualSelectNextSearchTest : VimTestCase() {
@Test
fun testWithoutSpaces() {
configureByText("test<caret>test")
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
typeText(injector.parser.parseKeys("gn"))
assertOffset(7)
assertSelection("test")

View File

@@ -12,6 +12,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.SkipNeovimReason
@@ -54,7 +55,7 @@ class VisualSelectPreviousSearchTest : VimTestCase() {
@Test
fun testWithoutSpaces() {
configureByText("tes<caret>ttest")
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
typeText(injector.parser.parseKeys("gN"))
assertOffset(0)
assertSelection("test")

View File

@@ -11,9 +11,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -11,9 +11,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -12,9 +12,9 @@ package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -11,9 +11,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -11,9 +11,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.leftright
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -8,8 +8,11 @@
package org.jetbrains.plugins.ideavim.action.motion.search
import com.maddyhome.idea.vim.api.getVisualLineCount
import com.maddyhome.idea.vim.newapi.IjVimEditor
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class SearchAgainNextActionTest : VimTestCase() {
@Test

View File

@@ -10,6 +10,7 @@ package org.jetbrains.plugins.ideavim.action.motion.search
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase
@@ -167,7 +168,7 @@ class SearchAgainPreviousActionTest : VimTestCase() {
private fun doTestWithSearch(keys: String, before: String, after: String) {
doTest(keys, before, after) {
VimPlugin.getSearch().setLastSearchState(it, "all", "", Direction.FORWARDS)
VimPlugin.getSearch().setLastSearchState(it.vim, "all", "", Direction.FORWARDS)
}
}
}

View File

@@ -9,9 +9,9 @@
package org.jetbrains.plugins.ideavim.action.motion.select
import com.maddyhome.idea.vim.state.mode.Mode
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test

View File

@@ -12,9 +12,9 @@ package org.jetbrains.plugins.ideavim.action.motion.select
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.Test

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.select.motion
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

View File

@@ -10,9 +10,9 @@
package org.jetbrains.plugins.ideavim.action.motion.select.motion
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import com.maddyhome.idea.vim.options.OptionConstants
import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestOptionConstants
import org.jetbrains.plugins.ideavim.TestWithoutNeovim

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