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

Compare commits

...

26 Commits

Author SHA1 Message Date
Alex Plate
1791692d92 Use java boolean 2022-07-05 12:26:16 +03:00
Alex Plate
ba23c9ab5e Rename variable service 2022-07-05 11:27:53 +03:00
Alex Plate
f96ab37bcb Rename Scope 2022-07-05 11:04:08 +03:00
Alex Plate
0da34bbb34 Compatibility of toggleOption 2022-07-05 10:56:45 +03:00
Alex Plate
51e7c745ea Move number option to a different package 2022-07-05 10:26:14 +03:00
aleksei.plate
8347251572 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:58 +00:00
aleksei.plate
ce8512f4e0 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:22 +00:00
aleksei.plate
a724a19d00 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:00 +00:00
Alex Plate
7eae7a98e8 Command state compatibility 2022-07-05 10:05:02 +03:00
Alex Plate
fe9566eebd Convert helper to kt 2022-07-04 10:59:24 +03:00
Alex Plate
b69756730f Rename .java to .kt 2022-07-04 10:59:23 +03:00
Alex Plate
6cd1a60b53 More compatibility 2022-07-04 10:33:31 +03:00
Alex Plate
9d935e47b5 Move compatibility 2022-07-04 09:49:50 +03:00
Alex Plate
a7d5372d06 Move classes to a different package 2022-07-04 09:49:50 +03:00
Alex Plate
a575942c81 Compatibility 2022-07-04 09:49:50 +03:00
aleksei.plate
3cf6c53a8e TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:40:47 +00:00
aleksei.plate
91d86680de TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:22:54 +00:00
aleksei.plate
d1d082fb99 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:15:19 +00:00
aleksei.plate
2c634d1bf0 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:06:43 +00:00
aleksei.plate
02a6fe4dc9 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:46 +00:00
aleksei.plate
223d681526 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:33 +00:00
aleksei.plate
f42ef1c2fc TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:27 +00:00
Alex Plate
f4817b2111 Add compatibility verifier to the repo 2022-07-04 08:59:31 +03:00
Alex Plate
6f5def0abf Update formatting 2022-07-03 00:19:25 +00:00
filipp
f0fcd7f133 Better offset for multiple carets with surround 2022-07-02 18:59:21 +06:00
filipp
6115adb72e Add registers to carets 2022-07-02 18:51:10 +06:00
78 changed files with 3626 additions and 2161 deletions

View File

@@ -4,7 +4,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
@@ -17,17 +17,33 @@ create(DslContext.projectId, BuildType({
name = "IdeaVim compatibility with external plugins"
vcs {
root(RelativeId("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster"))
root(DslContext.settingsRoot)
}
steps {
script {
scriptContent = "go run test.go"
name = "Check"
scriptContent = """
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}io.github.mishkun.ideavimsneak' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
""".trimIndent()
}
}
triggers {
vcs {
schedule {
schedulingPolicy = daily {
hour = 4
}
branchFilter = ""
triggerBuild = always()
withPendingChangesOnly = false
}
}

View File

@@ -48,13 +48,13 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
import com.maddyhome.idea.vim.listener.VimListenerManager;
import com.maddyhome.idea.vim.newapi.IjVimInjector;
import com.maddyhome.idea.vim.options.OptionService;
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage;
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService;
import com.maddyhome.idea.vim.vimscript.services.VimVariableService;
import com.maddyhome.idea.vim.vimscript.services.OptionService;
import com.maddyhome.idea.vim.vimscript.services.VariableService;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -226,8 +226,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
return (PutGroup)VimInjectorKt.getInjector().getPut();
}
public static @NotNull VimVariableService getVariableService() {
return ApplicationManager.getApplication().getService(VimVariableService.class);
public static @NotNull VariableService getVariableService() {
return ApplicationManager.getApplication().getService(VariableService.class);
}
public static @NotNull OptionService getOptionService() {

View File

@@ -34,8 +34,8 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import java.util.*

View File

@@ -30,6 +30,15 @@ class CommandState(private val machine: VimStateMachine) {
val isOperatorPending: Boolean
get() = machine.isOperatorPending
val mode: CommandState.Mode
get() = machine.mode.ij
val commandBuilder: CommandBuilder
get() = machine.commandBuilder
val mappingState: MappingState
get() = machine.mappingState
enum class Mode {
// Basic modes
COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/
@@ -50,7 +59,6 @@ class CommandState(private val machine: VimStateMachine) {
}
}
val CommandState.SubMode.engine: VimStateMachine.SubMode
get() = when (this) {
CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE
@@ -73,7 +81,6 @@ val CommandState.Mode.engine: VimStateMachine.Mode
CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT
}
val VimStateMachine.Mode.ij: CommandState.Mode
get() = when (this) {
VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND

View File

@@ -23,6 +23,7 @@ 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.VimCaret
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.CommandAlias
@@ -182,12 +183,24 @@ object VimExtensionFacade {
return reg.keys
}
@JvmStatic
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
val reg = caret.registerStorage.getRegister(register) ?: return null
return reg.keys
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?) {
VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList())
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegisterForCaret(register: Char, caret: VimCaret, keys: List<KeyStroke?>?) {
caret.registerStorage.setKeys(register, keys?.filterNotNull() ?: emptyList())
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) {

View File

@@ -25,9 +25,9 @@ import com.maddyhome.idea.vim.api.VimExtensionRegistrator
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.statistic.PluginState
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType

View File

@@ -34,13 +34,14 @@ 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.VimStateMachine
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.TextObjectVisualType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.command.MappingMode
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.addCommand
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
@@ -48,7 +49,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper

View File

@@ -31,10 +31,11 @@ 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
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
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.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
@@ -42,7 +43,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
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.ExtensionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition

View File

@@ -33,21 +33,21 @@ 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.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.command.MappingMode
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.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotionOrError
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import java.util.*

View File

@@ -29,8 +29,8 @@ 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
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension

View File

@@ -44,11 +44,11 @@ import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.common.addLeafs
import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.key.addLeafs
import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.group.KeyGroup

View File

@@ -24,10 +24,10 @@ import com.maddyhome.idea.vim.api.ExecutionContext
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.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.SearchHelper

View File

@@ -65,15 +65,14 @@ class ReplaceWithRegister : VimExtension {
private class RwrVisual : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
val caretsAndSelections = mutableMapOf<VimCaret, VimSelection>()
val typeInEditor = SelectionType.fromSubMode(editor.subMode)
editor.forEachCaret { caret ->
val selectionStart = caret.selectionStart
val selectionEnd = caret.selectionEnd
caretsAndSelections += caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor)
val visualSelection = caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor)
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), typeInEditor))
}
doReplace(editor.ij, PutData.VisualSelection(caretsAndSelections, typeInEditor))
editor.exitVisualModeNative()
}
}
@@ -97,11 +96,11 @@ class ReplaceWithRegister : VimExtension {
val lineStart = editor.getLineStartOffset(logicalLine)
val lineEnd = editor.getLineEndOffset(logicalLine, true)
caretsAndSelections += caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor)
}
val visualSelection = caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor)
caretsAndSelections += visualSelection
val visualSelection = PutData.VisualSelection(caretsAndSelections, SelectionType.LINE_WISE)
doReplace(editor.ij, visualSelection)
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), SelectionType.LINE_WISE))
}
editor.forEachCaret { caret ->
val vimStart = caretsAndSelections[caret]?.vimStart
@@ -126,7 +125,8 @@ class ReplaceWithRegister : VimExtension {
),
selectionType
)
doReplace(editor, visualSelection)
// todo multicaret
doReplace(editor, editor.vim.primaryCaret(), visualSelection)
return true
}
@@ -147,8 +147,9 @@ class ReplaceWithRegister : VimExtension {
@NonNls
private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
private fun doReplace(editor: Editor, visualSelection: PutData.VisualSelection) {
val savedRegister = VimPlugin.getRegister().lastRegister ?: return
private fun doReplace(editor: Editor, caret: VimCaret, visualSelection: PutData.VisualSelection) {
val lastRegisterChar = injector.registerGroup.lastRegisterChar
val savedRegister = caret.registerStorage.getRegister(lastRegisterChar) ?: return
var usedType = savedRegister.type
var usedText = savedRegister.text
@@ -173,8 +174,8 @@ class ReplaceWithRegister : VimExtension {
VimPlugin.getPut().putText(IjVimEditor(editor), IjExecutionContext(EditorDataContext.init(editor)), putData)
}
VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister)
VimPlugin.getRegister().saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister)
caret.registerStorage.saveRegister(savedRegister.name, savedRegister)
caret.registerStorage.saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister)
}
}
}

View File

@@ -22,23 +22,23 @@ import com.intellij.openapi.application.runWriteAction
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.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
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.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
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.setRegister
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimCaret
@@ -46,6 +46,7 @@ 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
import com.maddyhome.idea.vim.put.PutData
import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
@@ -115,33 +116,70 @@ class VimSurroundExtension : VimExtension {
if (charTo.code == 0) return
val newSurround = getOrInputPair(charTo, editor.ij) ?: return
runWriteAction { change(editor.ij, charFrom, newSurround) }
runWriteAction { change(editor, context, charFrom, newSurround) }
}
companion object {
fun change(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
// We take over the " register, so preserve it
val oldValue: List<KeyStroke>? = getRegister(REGISTER)
// Empty the " register
setRegister(REGISTER, null)
// Extract the inner value
perform("di" + pick(charFrom), editor)
val innerValue: MutableList<KeyStroke> = getRegister(REGISTER)?.toMutableList() ?: mutableListOf()
// If the surrounding characters were not found, the register will be empty
if (innerValue.isNotEmpty()) {
// Delete the surrounding
perform("da" + pick(charFrom), editor)
// Insert the surrounding characters and paste
if (newSurround != null) {
innerValue.addAll(0, injector.parser.parseKeys(newSurround.first))
innerValue.addAll(injector.parser.parseKeys(newSurround.second))
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets
val surroundings = editor.sortedCarets()
.map {
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
setRegisterForCaret(REGISTER, it, null)
SurroundingInfo(it, null, oldValue, null)
}
pasteSurround(innerValue, editor)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
// Delete surrounding's content
perform("di" + pick(charFrom), editor.ij)
// Add info about surrounding's inner text and location
surroundings.forEach {
val registerValue = getRegisterForCaret(REGISTER, it.caret)
val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue
it.innerText = innerValue
val lineEndOffset = injector.engineEditorHelper.getLineEndOffset(editor, it.caret.getLine().line, false)
if (lineEndOffset == it.caret.offset.point) {
it.isLineEnd = true
}
}
// Remove surrounding
perform("da" + pick(charFrom), editor.ij)
surroundings.forEach {
if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
it.innerText = emptyList()
}
// caret should be placed at the first char of inserted text
// the best solution would be using [ mark after the paste, but marks are not supported by multicaret
// todo
if (it.innerText != null) {
it.offset = it.caret.offset.point
}
}
surroundings
.filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
.map { surrounding ->
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList())
val putData = PutData(textData, null, 1, insertTextBeforeCaret = !surrounding.isLineEnd, rawIndent = true, caretAfterInsertedText = false)
surrounding.caret to putData
}.forEach {
injector.put.putTextForCaret(editor, it.first, context, it.second)
}
surroundings.forEach {
it.restoreRegister()
}
if (surroundings.size == 1) {
surroundings.first().moveCaret()
}
// Restore the old value
setRegister(REGISTER, oldValue)
}
private fun perform(sequence: String, editor: Editor) {
@@ -149,21 +187,6 @@ class VimSurroundExtension : VimExtension {
.use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) }
}
private fun pasteSurround(
innerValue: List<KeyStroke?>,
editor: Editor,
) { // This logic is direct from vim-surround
val offset = editor.caretModel.offset
val lineEndOffset = EditorHelper.getLineEndForOffset(editor, offset)
val motionEndMark = VimPlugin.getMark().getMark(editor.vim, ']')
val motionEndOffset = if (motionEndMark != null) {
EditorHelper.getOffset(editor, motionEndMark.logicalLine, motionEndMark.col)
} else -1
val pasteCommand = if (motionEndOffset == lineEndOffset && offset + 1 == lineEndOffset) "p" else "P"
setRegister(REGISTER, innerValue)
perform(pasteCommand, editor)
}
private fun pick(charFrom: Char) = when (charFrom) {
'a' -> '>'
'r' -> ']'
@@ -172,6 +195,18 @@ class VimSurroundExtension : VimExtension {
}
}
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var offset: Int?, var isLineEnd: Boolean = false) {
fun restoreRegister() {
setRegisterForCaret(REGISTER, caret, oldRegisterContent)
}
fun moveCaret() {
if (innerText != null && offset != null) {
caret.moveToOffset(offset!! + if (isLineEnd) 1 else 0)
}
}
}
private class DSurroundHandler : ExtensionHandler {
override val isRepeatable = true
@@ -180,7 +215,7 @@ class VimSurroundExtension : VimExtension {
val charFrom = getChar(editor.ij)
if (charFrom.code == 0) return
runWriteAction { CSurroundHandler.change(editor.ij, charFrom, null) }
runWriteAction { CSurroundHandler.change(editor, context, charFrom, null) }
}
}

View File

@@ -675,7 +675,7 @@ public class ChangeGroup extends VimChangeGroupBase {
}
}
if (pos > wsoff) {
deleteText(editor, new TextRange(wsoff, pos), null);
deleteText(editor, new TextRange(wsoff, pos), null, caret);
}
}
}

View File

@@ -38,8 +38,7 @@ import com.maddyhome.idea.vim.action.ComplicatedKeysAction;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.common.Node;
import com.maddyhome.idea.vim.common.NodesKt;
import com.maddyhome.idea.vim.key.Node;
import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.HelperKt;

View File

@@ -34,8 +34,8 @@ 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.injector
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.isBlock
import com.maddyhome.idea.vim.command.isChar
import com.maddyhome.idea.vim.command.isLine
@@ -60,10 +60,14 @@ import java.awt.datatransfer.DataFlavor
import kotlin.math.min
class PutGroup : VimPutBase() {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean): Boolean {
val additionalData = collectPreModificationData(editor, data)
data.visualSelection?.let { deleteSelectedText(editor, data) }
val processedText = processText(editor, data) ?: return false
putForCaret(editor, caret, data, additionalData, context, processedText)
if (editor.primaryCaret() == caret && updateVisualMarks) {
wrapInsertedTextWithVisualMarks(editor, data, processedText)
}
return true
}
@@ -118,7 +122,9 @@ class PutGroup : VimPutBase() {
editor, caret, context, text.text, text.typeInRegister, subMode,
startOffset, data.count, data.indent, data.caretAfterInsertedText
)
if (caret == editor.primaryCaret()) {
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
}
moveCaretToEndPosition(
editor,
caret,

View File

@@ -18,18 +18,16 @@
package com.maddyhome.idea.vim.group.copy
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.util.containers.ContainerUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction
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.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.listener.VimYankListener
@@ -46,8 +44,8 @@ class YankGroup : YankGroupBase() {
fun removeListener(listener: VimYankListener) = yankListeners.remove(listener)
private fun notifyListeners(editor: Editor, textRange: TextRange) = yankListeners.forEach {
it.yankPerformed(editor, textRange)
private fun notifyListeners(editor: VimEditor, textRange: TextRange) = yankListeners.forEach {
it.yankPerformed(editor.ij, textRange)
}
/**
@@ -67,32 +65,38 @@ class YankGroup : YankGroupBase() {
operatorArguments: OperatorArguments
): Boolean {
val motion = argument.motion
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val caretModel = editor.ij.caretModel
if (caretModel.caretCount <= 0) return false
val nativeCaretCount = editor.nativeCarets().size
if (nativeCaretCount <= 0) return false
val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
val carretToRange = HashMap<VimCaret, TextRange>(nativeCaretCount)
val ranges = ArrayList<Pair<Int, Int>>(nativeCaretCount)
// This logic is from original vim
val startOffsets =
if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<Caret, Int>(caretModel.caretCount)
val startOffsets = if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<VimCaret, Int>(nativeCaretCount)
for (caret in caretModel.allCarets) {
val motionRange = MotionGroup.getMotionRange(editor.ij, caret, context.ij, argument, operatorArguments)
for (caret in editor.nativeCarets()) {
val motionRange = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments)
?: continue
assert(motionRange.size() == 1)
ranges.add(motionRange.startOffset to motionRange.endOffset)
startOffsets?.put(caret, motionRange.normalize().startOffset)
carretToRange[caret] = TextRange(motionRange.startOffset, motionRange.endOffset)
}
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val range = getTextRange(ranges, type) ?: return false
if (range.size() == 0) return false
val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
return yankRange(editor.ij, range, selectionType, startOffsets)
return yankRange(
editor,
carretToRange,
range,
type,
startOffsets
)
}
/**
@@ -103,19 +107,21 @@ class YankGroup : YankGroupBase() {
* @return true if able to yank the lines, false if not
*/
override fun yankLine(editor: VimEditor, count: Int): Boolean {
val caretModel = editor.ij.caretModel
val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
for (caret in caretModel.allCarets) {
val start = VimPlugin.getMotion().moveCaretToLineStart(editor, caret.vim)
val end = min(VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret.vim, count - 1, true) + 1, editor.fileSize().toInt())
val caretCount = editor.nativeCarets().size
val ranges = ArrayList<Pair<Int, Int>>(caretCount)
val caretToRange = HashMap<VimCaret, TextRange>(caretCount)
for (caret in editor.nativeCarets()) {
val start = injector.motion.moveCaretToLineStart(editor, caret)
val end = min(injector.motion.moveCaretToLineEndOffset(editor, caret, count - 1, true) + 1, editor.fileSize().toInt())
if (end == -1) continue
ranges.add(start to end)
caretToRange[caret] = TextRange(start, end)
}
val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false
return yankRange(editor.ij, range, SelectionType.LINE_WISE, null)
return yankRange(editor, caretToRange, range, SelectionType.LINE_WISE, null)
}
/**
@@ -129,6 +135,7 @@ class YankGroup : YankGroupBase() {
override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean {
range ?: return false
val caretToRange = HashMap<VimCaret, TextRange>()
val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
if (type == SelectionType.LINE_WISE) {
@@ -143,24 +150,25 @@ class YankGroup : YankGroupBase() {
}
}
val caretModel = editor.ij.caretModel
val rangeStartOffsets = range.startOffsets
val rangeEndOffsets = range.endOffsets
return if (moveCursor) {
val startOffsets = HashMap<Caret, Int>(caretModel.caretCount)
val startOffsets = HashMap<VimCaret, Int>(editor.nativeCarets().size)
if (type == SelectionType.BLOCK_WISE) {
startOffsets[caretModel.primaryCaret] = range.normalize().startOffset
startOffsets[editor.primaryCaret()] = range.normalize().startOffset
caretToRange[editor.primaryCaret()] = range
} else {
val carets = caretModel.allCarets
for (i in carets.indices) {
startOffsets[carets[i]] = TextRange(rangeStartOffsets[i], rangeEndOffsets[i]).normalize().startOffset
for ((i, caret) in editor.nativeCarets().withIndex()) {
val textRange = TextRange(rangeStartOffsets[i], rangeEndOffsets[i])
startOffsets[caret] = textRange.normalize().startOffset
caretToRange[caret] = textRange
}
}
yankRange(editor.ij, range, selectionType, startOffsets)
return if (moveCursor) {
yankRange(editor, caretToRange, range, selectionType, startOffsets)
} else {
yankRange(editor.ij, range, selectionType, null)
yankRange(editor, caretToRange, range, selectionType, null)
}
}
@@ -192,15 +200,20 @@ class YankGroup : YankGroupBase() {
}
private fun yankRange(
editor: Editor,
editor: VimEditor,
caretToRange: Map<VimCaret, TextRange>,
range: TextRange,
type: SelectionType,
startOffsets: Map<Caret, Int>?,
startOffsets: Map<VimCaret, Int>?,
): Boolean {
startOffsets?.forEach { (caret, offset) -> MotionGroup.moveCaret(editor, caret, offset) }
startOffsets?.forEach { (caret, offset) -> injector.motion.moveCaret(editor, caret, offset) }
notifyListeners(editor, range)
return VimPlugin.getRegister().storeText(editor.vim, range, type, false)
var result = true
for ((caret, range) in caretToRange) {
result = caret.registerStorage.storeText(editor, range, type, false) && result
}
return result
}
}

View File

@@ -25,7 +25,7 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.exitSelectMode
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.hasVisualSelection
@@ -35,8 +35,8 @@ import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.isTemplateActive
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.popAllModes
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.listener.VimListenerManager
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim

View File

@@ -25,11 +25,11 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes

View File

@@ -25,9 +25,9 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjExecutionContext

View File

@@ -15,25 +15,30 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.helper
package com.maddyhome.idea.vim.helper;
import javax.swing.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
import com.maddyhome.idea.vim.api.injector
import java.util.*
import java.util.stream.Collectors
import javax.swing.KeyStroke
/**
* COMPATIBILITY-LAYER: Created a helper class
*/
public class StringHelper {
public static List<KeyStroke> parseKeys(String string) {
return injector.getParser().parseKeys(string);
object StringHelper {
@JvmStatic
fun parseKeys(string: String): List<KeyStroke> {
return injector.parser.parseKeys(string)
}
public static List<KeyStroke> parseKeys(String... string) {
return Arrays.stream(string).flatMap(o -> injector.getParser().parseKeys(o).stream()).collect(Collectors.toList());
@JvmStatic
fun parseKeys(vararg string: String): List<KeyStroke> {
return Arrays.stream(string).flatMap { o: String -> injector.parser.parseKeys(o).stream() }
.collect(Collectors.toList())
}
@JvmStatic
fun isCloseKeyStroke(stroke: KeyStroke): Boolean {
return stroke.isCloseKeyStroke()
}
}

View File

@@ -27,8 +27,9 @@ import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.UserDataHolder
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
@@ -73,6 +74,7 @@ var Caret.vimInsertStart: RangeMarker by userDataOr {
this.offset
)
}
var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
// ------------------ Editor
fun unInitializeEditor(editor: Editor) {

View File

@@ -19,8 +19,6 @@
package com.maddyhome.idea.vim.key
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.addLeafs
fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder)

View File

@@ -40,9 +40,9 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope

View File

@@ -32,8 +32,8 @@ import com.maddyhome.idea.vim.api.VimChangeGroupBase
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.IndentConfig
import com.maddyhome.idea.vim.common.OperatedRange

View File

@@ -22,7 +22,10 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.CaretRegisterStorage
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimCaretBase
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimVisualPosition
@@ -38,13 +41,23 @@ import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection
import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.registerStorage
import com.maddyhome.idea.vim.helper.vimInsertStart
import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
import com.maddyhome.idea.vim.helper.vimLine
import com.maddyhome.idea.vim.helper.vimSelectionStart
class IjVimCaret(val caret: Caret) : VimCaret {
class IjVimCaret(val caret: Caret) : VimCaretBase() {
override val registerStorage: CaretRegisterStorage
get() {
var storage = this.caret.registerStorage
if (storage == null) {
storage = CaretRegisterStorageBase(editor.primaryCaret().ij == caret)
this.caret.registerStorage = storage
}
return storage
}
override val editor: VimEditor
get() = IjVimEditor(caret.editor)
override val offset: Offset

View File

@@ -38,9 +38,9 @@ import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimSelectionModel
import com.maddyhome.idea.vim.api.VimVisualPosition
import com.maddyhome.idea.vim.api.VirtualFile
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset

View File

@@ -68,7 +68,7 @@ import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.vimscript.services.OptionService
import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.ui.VimRcFileState
@@ -76,7 +76,7 @@ import com.maddyhome.idea.vim.undo.VimUndoRedo
import com.maddyhome.idea.vim.vimscript.Executor
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.PatternService
import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.vimscript.services.VariableService
import com.maddyhome.idea.vim.yank.VimYankGroup
class IjVimInjector : VimInjectorBase() {
@@ -161,7 +161,7 @@ class IjVimInjector : VimInjectorBase() {
override val functionService: VimscriptFunctionService
get() = FunctionStorage
override val variableService: VimVariableService
override val variableService: VariableService
get() = service()
override val vimrcFileState: VimrcFileState
get() = VimRcFileState

View File

@@ -22,6 +22,8 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.smartcaseName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutName
import com.maddyhome.idea.vim.options.OptionConstants.Companion.timeoutlenName
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
@@ -34,6 +36,10 @@ object OptionsManager {
get() = (injector.optionService as IjVimOptionService).getRawOption(ignorecaseName) as ToggleOption
val smartcase: ToggleOption
get() = (injector.optionService as IjVimOptionService).getRawOption(smartcaseName) as ToggleOption
val timeout: ToggleOption
get() = (injector.optionService as IjVimOptionService).getRawOption(timeoutName) as ToggleOption
val timeoutlen: NumberOption
get() = (injector.optionService as IjVimOptionService).getRawOption(timeoutlenName) as NumberOption
val iskeyword: KeywordOption
get() = KeywordOption(KeywordOptionHelper)
}

View File

@@ -20,8 +20,8 @@ package com.maddyhome.idea.vim.ui
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
import com.maddyhome.idea.vim.helper.vimStateMachine
import java.awt.KeyEventDispatcher
import java.awt.KeyboardFocusManager
import java.awt.Toolkit

View File

@@ -25,9 +25,9 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.hasBlockOrUnderscoreCaret
import com.maddyhome.idea.vim.helper.hasVisualSelection
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.vim

View File

@@ -33,7 +33,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
import com.maddyhome.idea.vim.vimscript.model.expressions.Scope
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
internal class VimVariableServiceImpl : VimVariableServiceBase() {
class IjVariableService : VimVariableServiceBase() {
override fun storeVariable(variable: Variable, value: VimDataType, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) {
super.storeVariable(variable, value, editor, context, vimContext)

View File

@@ -20,9 +20,9 @@ package com.maddyhome.idea.vim.vimscript.services
import com.intellij.openapi.application.ApplicationNamesInfo
import com.maddyhome.idea.vim.api.VimOptionServiceBase
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.StringOption
import com.maddyhome.idea.vim.option.ToggleOption
internal class IjVimOptionService : VimOptionServiceBase() {

View File

@@ -26,13 +26,13 @@
serviceInterface="com.maddyhome.idea.vim.api.VimVisualMotionGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.copy.YankGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.copy.PutGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.vimscript.services.VimVariableServiceImpl"
serviceInterface="com.maddyhome.idea.vim.vimscript.services.VimVariableService"/>
<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"
serviceInterface="com.maddyhome.idea.vim.api.VimStatistics"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.vimscript.services.IjVimOptionService"
serviceInterface="com.maddyhome.idea.vim.options.OptionService"/>
serviceInterface="com.maddyhome.idea.vim.vimscript.services.OptionService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.IjVimStorageService"
serviceInterface="com.maddyhome.idea.vim.api.VimStorageService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.IjVimSystemInfoService"

View File

@@ -31,9 +31,8 @@ import com.maddyhome.idea.vim.helper.RunnableHelper;
import com.maddyhome.idea.vim.helper.TestInputModel;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceImpl;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -63,7 +62,7 @@ public abstract class JavaVimTestCase extends JavaCodeInsightFixtureTestCase {
@Override
protected void tearDown() throws Exception {
ExEntryPanel.getInstance().deactivate(false);
((VimVariableServiceImpl) VimPlugin.getVariableService()).clear();
VimPlugin.getVariableService().clear();
Timer swingTimer = VimVisualTimer.INSTANCE.getSwingTimer();
if (swingTimer != null) {
swingTimer.stop();

View File

@@ -21,10 +21,10 @@ package org.jetbrains.plugins.ideavim
import com.maddyhome.idea.vim.RegisterActions.VIM_ACTIONS_EP
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.handler.ActionBeanClass
import junit.framework.TestCase
import javax.swing.KeyStroke

View File

@@ -50,9 +50,9 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.VimShortcutKeyAction
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.VimStateMachine.SubMode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.ExOutputModel.Companion.getInstance
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.swingTimer
@@ -61,9 +61,9 @@ import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
import com.maddyhome.idea.vim.helper.RunnableHelper.runWriteCommand
import com.maddyhome.idea.vim.helper.TestInputModel
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.getGuiCursorMode
import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.ToKeysMappingInfo
@@ -77,7 +77,6 @@ import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.parser.errors.IdeavimErrorListener
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceImpl
import org.assertj.core.api.Assertions
import org.junit.Assert
import java.awt.event.KeyEvent
@@ -137,7 +136,7 @@ abstract class VimTestCase : UsefulTestCase() {
}
SelectionVimListenerSuppressor.lock().use { myFixture.tearDown() }
ExEntryPanel.getInstance().deactivate(false)
(VimPlugin.getVariableService() as VimVariableServiceImpl).clear()
VimPlugin.getVariableService().clear()
VimFuncref.lambdaCounter = 0
VimFuncref.anonymousCounter = 0
IdeavimErrorListener.testLogger.clear()

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,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.VimStateMachine
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.key.MappingOwner
import junit.framework.TestCase
import org.jetbrains.plugins.ideavim.SkipNeovimReason

View File

@@ -20,8 +20,8 @@ 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.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.VimTestCase

View File

@@ -56,8 +56,7 @@ class PutViaIdeaTest : VimTestCase() {
val before = "${c}I found it in a legendary land"
configureByText(before)
VimPlugin.getRegister()
.storeText(myFixture.editor.vim, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
injector.registerGroup.storeText('"', "legendary", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("ve" + "p"))
val after = "legendar${c}y it in a legendary land"

View File

@@ -115,9 +115,9 @@ class PutVisualTextActionTest : VimTestCase() {
@TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
fun `test put visual text multicaret`() {
val before = "${c}I found ${c}it in a ${c}legendary land"
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "legendary", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "legendary", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("ve" + "\"*p"))
val after = "legendar${c}y legendar${c}y in a legendar${c}y land"
assertState(after)
}
@@ -254,9 +254,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
${c}hard by the torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"*p"))
val after = """
A Discovery
@@ -285,9 +285,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
${c}hard by the$c torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "\"*p"))
val after = """
A Discovery
@@ -314,9 +314,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
${c}hard by the$c torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("ve" + "2p"))
configureByText(before)
injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("ve" + "2\"*p"))
val after = """
A Discovery
@@ -461,9 +461,10 @@ class PutVisualTextActionTest : VimTestCase() {
akin to moonlight, tempering its blue,
the dingy ${c}underside, the checquered fringe.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
// VimPlugin.getRegister().storeText(editor.vim, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("ve" + "\"*p"))
val after = """
A Discovery
@@ -592,9 +593,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
hard by the ${c}torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """
A Discovery
@@ -628,9 +629,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
hard by the ${c}torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(injector.parser.parseKeys("V" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "Discovery", SelectionType.CHARACTER_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """
A Discovery
@@ -753,9 +754,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
hard by the ${c}torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """
A Discovery
@@ -789,9 +790,9 @@ class PutVisualTextActionTest : VimTestCase() {
where it was settled on some sodden sand
hard by the ${c}torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("V" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "A Discovery\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """
A Discovery
@@ -995,9 +996,9 @@ class PutVisualTextActionTest : VimTestCase() {
akin to moonlight, tempering its blue,
the dingy ${c}underside, the checquered fringe.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, editor.rangeOf("|found|", 2), SelectionType.BLOCK_WISE, false)
typeText(injector.parser.parseKeys("V" + "p"))
configureByText(before)
injector.registerGroup.storeText('*', "|found|\n|l roc|\n|ere i|", SelectionType.BLOCK_WISE)
typeText(injector.parser.parseKeys("V" + "\"*p"))
val after = """
A Discovery

View File

@@ -202,9 +202,9 @@ class PutVisualTextMoveCursorActionTest : VimTestCase() {
${c}zxcvbn
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor.vim, TextRange(14, 21), SelectionType.LINE_WISE, false)
typeText(injector.parser.parseKeys("vl" + "gp"))
configureByText(before)
injector.registerGroup.storeText('*', "zxcvbn\n", SelectionType.LINE_WISE)
typeText(injector.parser.parseKeys("vl" + "\"*gp"))
val after = """
q
zxcvbn

View File

@@ -24,7 +24,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import junit.framework.TestCase
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
@@ -79,47 +79,48 @@ class YankVisualActionTest : VimTestCase() {
}
fun `test yank multicaret`() {
doTest(
injector.parser.parseKeys("viw" + "y"),
"""
val text = """
A Discovery
I ${c}found it in a legendary land
all rocks and lavender and tufted grass,
where it ${c}was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
"found\nwas", SelectionType.BLOCK_WISE
)
""".trimIndent()
configureByText(text)
typeText(injector.parser.parseKeys("viw" + "y"))
val editor = myFixture.editor.vim
val lastRegister = injector.registerGroup.lastRegisterChar
val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
assertEquals(listOf("found", "was"), registers)
}
@TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
fun testYankVisualRange() {
val before = """
q${c}werty
asdf${c}gh
${c}zxcvbn
""".trimIndent()
configureByText(before)
typeText(injector.parser.parseKeys("vey"))
val lastRegister = VimPlugin.getRegister().lastRegister
TestCase.assertNotNull(lastRegister)
val text = lastRegister!!.text
TestCase.assertNotNull(text)
typeText(injector.parser.parseKeys("G" + "$" + "p"))
val after = """
qwerty
asdfgh
zxcvbn
${c}werty
gh
zxcvbn
""".trimIndent()
assertState(after)
}
// todo multicaret
// @TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
// fun testYankVisualRange() {
// val before = """
// q${c}werty
// asdf${c}gh
// ${c}zxcvbn
//
// """.trimIndent()
// configureByText(before)
// typeText(injector.parser.parseKeys("vey"))
//
// val lastRegister = VimPlugin.getRegister().lastRegister
// TestCase.assertNotNull(lastRegister)
// val text = lastRegister!!.text
// TestCase.assertNotNull(text)
//
// typeText(injector.parser.parseKeys("G" + "$" + "p"))
// val after = """
// qwerty
// asdfgh
// zxcvbn
// wert${c}yg${c}hzxcvb${c}n
// """.trimIndent()
// assertState(after)
// }
fun `test yank line`() {
doTest(
@@ -152,17 +153,22 @@ class YankVisualActionTest : VimTestCase() {
}
fun `test yank multicaret line`() {
doTest(
injector.parser.parseKeys("V" + "y"),
"""
val text = """
A Discovery
I found it in a legendary land
all ${c}rocks and lavender and tufted grass,
where it was settled on some sodden sand
hard by ${c}the torrent of a mountain pass.
""".trimIndent(),
"all rocks and lavender and tufted grass,\nhard by the torrent of a mountain pass.\n", SelectionType.LINE_WISE
""".trimIndent()
configureByText(text)
typeText(injector.parser.parseKeys("V" + "y"))
val editor = myFixture.editor.vim
val lastRegister = injector.registerGroup.lastRegisterChar
val registers = editor.carets().map { it.registerStorage.getRegister(lastRegister)?.rawText }
assertEquals(
listOf("all rocks and lavender and tufted grass,\n", "hard by the torrent of a mountain pass.\n"),
registers
)
}
@@ -180,35 +186,15 @@ class YankVisualActionTest : VimTestCase() {
configureByText(before)
typeText(injector.parser.parseKeys("Vy"))
val lastRegister = VimPlugin.getRegister().lastRegister
TestCase.assertNotNull(lastRegister)
val text = lastRegister!!.text
TestCase.assertNotNull(text)
TestCase.assertEquals(
"""
qwe
zxc
rty
""".trimIndent(),
text
)
typeText(injector.parser.parseKeys("p"))
val after = """
qwe
${c}qwe
zxc
rty
asd
zxc
${c}qwe
zxc
rty
rty
${c}qwe
zxc
${c}zxc
rty
${c}rty
fgh
vbn

View File

@@ -221,11 +221,9 @@ class MultipleCaretsTest : VimTestCase() {
val after = """qwe
|rty
|${c}rty
|fgh
|asd
|fgh
|${c}rty
|fgh
|${c}fgh
|zxc
|vbn
""".trimMargin()

View File

@@ -25,15 +25,15 @@ 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
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.extension.Alias
import com.maddyhome.idea.vim.extension.ExtensionBeanClass
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
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.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.isEndAllowed

View File

@@ -20,8 +20,8 @@ package org.jetbrains.plugins.ideavim.extension.replacewithregister
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.register.RegisterConstants.UNNAMED_REGISTER
@@ -367,8 +367,6 @@ class ReplaceWithRegisterTest : VimTestCase() {
I found it in a legendary land
where it was settled on some sodden sand
where it was settled on some sodden sand
I found it in a legendary land
where it was settled on some sodden sand
""".trimIndent()
)

View File

@@ -541,4 +541,32 @@ class VimSurroundExtensionTest : VimTestCase() {
val keys = ":map gw ds)<CR>" + "qqgwqj@q"
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
}
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test change surround with multicaret`() {
val before = """
(${c}abc)
(${c}xyz)
"""
val after = """
[abc]
[xyz]
"""
doTest(listOf("cs(]"), before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
}
@TestWithoutNeovim(SkipNeovimReason.PLUGIN)
fun `test delete surround with multicaret`() {
val before = """
(${c}abc)
(${c}xyz)
"""
val after = """
abc
xyz
"""
doTest(listOf("ds("), before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
}
}

View File

@@ -22,7 +22,7 @@ import com.intellij.ide.IdeEventQueue
import com.intellij.openapi.editor.Editor
import com.intellij.testFramework.PlatformTestUtil
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim

Binary file not shown.

View File

@@ -29,12 +29,12 @@ import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.VimStateMachine.Companion.getInstance
import com.maddyhome.idea.vim.command.MappingState
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.common.CurrentCommandState
import com.maddyhome.idea.vim.common.DigraphResult
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.common.argumentCaptured
import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.diagnostic.debug

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.action.copy
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.injector
import com.maddyhome.idea.vim.command.Argument
@@ -40,14 +41,28 @@ sealed class PutTextBaseAction(
argument: Argument?,
operatorArguments: OperatorArguments
): Boolean {
val lastRegister = injector.registerGroup.lastRegister
val textData = if (lastRegister != null) TextData(
lastRegister.text ?: injector.parser.toPrintableString(lastRegister.keys),
lastRegister.type,
lastRegister.transferableData
) else null
val putData = PutData(textData, null, operatorArguments.count1, insertTextBeforeCaret, indent, caretAfterInsertedText, -1)
return injector.put.putText(editor, context, putData)
val count = operatorArguments.count1
val caretToPutData = editor.sortedCarets().associateWith { getPutDataForCaret(it, count) }
var result = true
injector.application.runWriteAction {
caretToPutData.forEach {
result = injector.put.putTextForCaret(editor, it.key, context, it.value) && result
}
}
return result
}
private fun getPutDataForCaret(caret: VimCaret, count: Int): PutData {
val lastRegisterChar = injector.registerGroup.lastRegisterChar
val register = caret.registerStorage.getRegister(lastRegisterChar)
val textData = register?.let {
TextData(
register.text ?: injector.parser.toPrintableString(register.keys),
register.type,
register.transferableData
)
}
return PutData(textData, null, count, insertTextBeforeCaret, indent, caretAfterInsertedText, -1)
}
}

View File

@@ -52,16 +52,30 @@ sealed class PutVisualTextBaseAction(
operatorArguments: OperatorArguments,
): Boolean {
if (caretsAndSelections.isEmpty()) return false
val textData = injector.registerGroup.lastRegister?.let { PutData.TextData(it.text, it.type, it.transferableData) }
val count = cmd.count
val caretToPutData = editor.sortedCarets().associateWith { getPutDataForCaret(it, caretsAndSelections[it], count) }
injector.registerGroup.resetRegister()
var result = true
injector.application.runWriteAction {
caretToPutData.forEach {
result = injector.put.putTextForCaret(editor, it.key, context, it.value, true) && result
}
}
return result
}
val selection = PutData.VisualSelection(
caretsAndSelections,
caretsAndSelections.values.first().type
private fun getPutDataForCaret(caret: VimCaret, selection: VimSelection?, count: Int): PutData {
val lastRegisterChar = injector.registerGroup.lastRegisterChar
val register = caret.registerStorage.getRegister(lastRegisterChar)
val textData = register?.let {
PutData.TextData(
register.text ?: injector.parser.toPrintableString(register.keys),
register.type,
register.transferableData
)
val putData = PutData(textData, selection, cmd.count, insertTextBeforeCaret, indent, caretAfterInsertedText)
return injector.put.putText(editor, context, putData, true)
}
val visualSelection = selection?.let { PutData.VisualSelection(mapOf(caret to it), it.type) }
return PutData(textData, visualSelection, count, insertTextBeforeCaret, indent, caretAfterInsertedText)
}
}

View File

@@ -1,12 +1,17 @@
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.register.Register
import javax.swing.KeyStroke
// TODO: 29.12.2021 Split interface to mutable and immutable
interface VimCaret {
val registerStorage: CaretRegisterStorage
val editor: VimEditor
val offset: Offset
var vimLastColumn: Int
@@ -36,3 +41,19 @@ interface VimCaret {
fun setNativeSelection(start: Offset, end: Offset)
fun removeNativeSelection()
}
interface CaretRegisterStorage {
/**
* Stores text to caret's recordable (named/numbered/unnamed) register
*/
fun storeText(editor: VimEditor, range: TextRange, type: SelectionType, isDelete: Boolean): Boolean
/**
* Gets text from caret's recordable register
* If the register is not recordable - global text state will be returned
*/
fun getRegister(r: Char): Register?
fun setKeys(register: Char, keys: List<KeyStroke>)
fun saveRegister(r: Char, register: Register)
}

View File

@@ -0,0 +1,56 @@
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.register.Register
import com.maddyhome.idea.vim.register.RegisterConstants
import com.maddyhome.idea.vim.register.VimRegisterGroupBase
import javax.swing.KeyStroke
abstract class VimCaretBase : VimCaret
open class CaretRegisterStorageBase(private val isCaretPrimary: Boolean) : CaretRegisterStorage, VimRegisterGroupBase() {
override var lastRegisterChar: Char
get() {
return injector.registerGroup.lastRegisterChar
}
set(value) {}
override fun storeText(editor: VimEditor, range: TextRange, type: SelectionType, isDelete: Boolean): Boolean {
if (isCaretPrimary) {
return injector.registerGroup.storeText(editor, range, type, isDelete)
}
val register = lastRegisterChar
if (!RegisterConstants.RECORDABLE_REGISTERS.contains(register)) {
return false
}
return super.storeText(editor, range, type, isDelete)
}
override fun getRegister(r: Char): Register? {
if (isCaretPrimary || !RegisterConstants.RECORDABLE_REGISTERS.contains(r)) {
return injector.registerGroup.getRegister(r)
}
return super.getRegister(r)
}
override fun setKeys(register: Char, keys: List<KeyStroke>) {
if (isCaretPrimary) {
injector.registerGroup.setKeys(register, keys)
}
if (!RegisterConstants.RECORDABLE_REGISTERS.contains(register)) {
return
}
return super.setKeys(register, keys)
}
override fun saveRegister(r: Char, register: Register) {
if (isCaretPrimary) {
injector.registerGroup.saveRegister(r, register)
}
if (!RegisterConstants.RECORDABLE_REGISTERS.contains(r)) {
return
}
return super.saveRegister(r, register)
}
}

View File

@@ -83,7 +83,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
override fun deleteCharacter(editor: VimEditor, caret: VimCaret, count: Int, isChange: Boolean): Boolean {
val endOffset = injector.motion.getOffsetOfHorizontalMotion(editor, caret, count, true)
if (endOffset != -1) {
val res = deleteText(editor, TextRange(caret.offset.point, endOffset), SelectionType.CHARACTER_WISE)
val res = deleteText(editor, TextRange(caret.offset.point, endOffset), SelectionType.CHARACTER_WISE, caret)
val pos = caret.offset.point
val norm = injector.engineEditorHelper.normalizeOffset(editor, caret.getLogicalPosition().line, pos, isChange)
if (norm != pos ||
@@ -132,6 +132,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
editor: VimEditor,
range: TextRange,
type: SelectionType?,
caret: VimCaret,
): Boolean {
var updatedRange = range
// Fix for https://youtrack.jetbrains.net/issue/VIM-35
@@ -145,7 +146,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
}
}
if (type == null ||
editor.inInsertMode || injector.registerGroup.storeText(editor, updatedRange, type, true)
editor.inInsertMode || caret.registerStorage.storeText(editor, updatedRange, type, true)
) {
val startOffsets = updatedRange.startOffsets
val endOffsets = updatedRange.endOffsets
@@ -154,9 +155,11 @@ abstract class VimChangeGroupBase : VimChangeGroup {
}
if (type != null) {
val start = updatedRange.startOffset
if (editor.primaryCaret() == caret) {
injector.markGroup.setMark(editor, MARK_CHANGE_POS, start)
injector.markGroup.setChangeMarks(editor, TextRange(start, start + 1))
}
}
return true
}
return false
@@ -631,7 +634,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
val rangeToDelete = TextRange(startOffset, offset)
editor.nativeCarets().filter { it != caret && rangeToDelete.contains(it.offset.point) }
.forEach { editor.removeCaret(it) }
val res = deleteText(editor, rangeToDelete, SelectionType.CHARACTER_WISE)
val res = deleteText(editor, rangeToDelete, SelectionType.CHARACTER_WISE, caret)
if (usesVirtualSpace) {
injector.motion.moveCaret(editor, caret, startOffset)
} else {
@@ -726,7 +729,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
logger.debug("offset=$offset")
}
if (offset != -1) {
val res = deleteText(editor, TextRange(start, offset), SelectionType.LINE_WISE)
val res = deleteText(editor, TextRange(start, offset), SelectionType.LINE_WISE, caret)
if (res && caret.offset.point >= editor.fileSize() && caret.offset.point != 0) {
injector.motion.moveCaret(
editor, caret, injector.motion.moveCaretToLineStartSkipLeadingOffset(
@@ -856,7 +859,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
// Update the last column before we delete, or we might be retrieving the data for a line that no longer exists
caret.vimLastColumn = caret.inlayAwareVisualColumn
val removeLastNewLine = removeLastNewLine(editor, range, type)
val res = deleteText(editor, range, type)
val res = deleteText(editor, range, type, caret)
if (removeLastNewLine) {
val textLength = editor.fileSize().toInt()
editor.deleteString(TextRange(textLength - 1, textLength))
@@ -975,7 +978,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
} else {
injector.motion.moveCaretToLineStart(editor, caret.getLogicalPosition().line + 1)
}
deleteText(editor, TextRange(caret.offset.point, offset), null)
deleteText(editor, TextRange(caret.offset.point, offset), null, caret)
if (spaces && !hasTrailingWhitespace) {
insertText(editor, caret, " ")
injector.motion.moveCaret(

View File

@@ -9,11 +9,11 @@ import com.maddyhome.idea.vim.helper.VimCommandLineHelper
import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.vimscript.services.OptionService
import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.undo.VimUndoRedo
import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.vimscript.services.VariableService
import com.maddyhome.idea.vim.yank.VimYankGroup
interface VimInjector {
@@ -117,7 +117,7 @@ interface VimInjector {
// Can't be fully moved to vim-engine.
val vimscriptParser: VimscriptParser
// !! in progress
val variableService: VimVariableService
val variableService: VariableService
// !! in progress
val functionService: VimscriptFunctionService
// Can't be fully moved to vim-engine.

View File

@@ -8,10 +8,10 @@ import com.maddyhome.idea.vim.api.stubs.VimProcessGroupStub
import com.maddyhome.idea.vim.common.VimMachine
import com.maddyhome.idea.vim.common.VimMachineBase
import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.vimscript.services.OptionService
import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.register.VimRegisterGroupBase
import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.vimscript.services.VariableService
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceBase
abstract class VimInjectorBase : VimInjector {
@@ -23,7 +23,7 @@ abstract class VimInjectorBase : VimInjector {
override val parser: VimStringParser = object : VimStringParserBase() {}
override val vimMachine: VimMachine = object : VimMachineBase() {}
override val optionService: OptionService by lazy { object : VimOptionServiceBase(){} }
override val variableService: VimVariableService by lazy { object : VimVariableServiceBase(){} }
override val variableService: VariableService by lazy { object : VimVariableServiceBase(){} }
override val registerGroup: VimRegisterGroup by lazy { registerGroupStub }
override val registerGroupIfCreated: VimRegisterGroup? by lazy { registerGroupStub }

View File

@@ -17,7 +17,7 @@
*/
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.key.KeyMapping

View File

@@ -1,8 +1,8 @@
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
import com.maddyhome.idea.vim.key.KeyMapping

View File

@@ -3,12 +3,11 @@ package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.NumberOption
import com.maddyhome.idea.vim.option.NumberOption
import com.maddyhome.idea.vim.options.Option
import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.options.StringOption
import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper
import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper
@@ -16,6 +15,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
import com.maddyhome.idea.vim.vimscript.model.datatypes.parseNumber
import com.maddyhome.idea.vim.vimscript.services.OptionService
abstract class VimOptionServiceBase : OptionService {
private val localOptionsKey = Key<MutableMap<String, VimDataType>>("localOptions")
@@ -253,6 +253,14 @@ abstract class VimOptionServiceBase : OptionService {
setOptionValue(scope, optionName, VimInt.ONE, token)
}
override fun setOption(scope: OptionService.Scope, optionName: String, token: String) {
val newScope = when (scope) {
is OptionService.Scope.GLOBAL -> OptionScope.GLOBAL
is OptionService.Scope.LOCAL -> OptionScope.LOCAL(scope.editor)
}
this.setOption(newScope, optionName, token)
}
/**
* Unsets the option (false)
*/

View File

@@ -19,10 +19,10 @@
package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.common.CurrentCommandState
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase

View File

@@ -65,12 +65,16 @@ enum class MappingMode {
val S: EnumSet<MappingMode> = EnumSet.of(SELECT)
val V: EnumSet<MappingMode> = EnumSet.of(VISUAL, SELECT)
val NO: EnumSet<MappingMode> = EnumSet.of(NORMAL, OP_PENDING)
@JvmField
val XO: EnumSet<MappingMode> = EnumSet.of(VISUAL, OP_PENDING)
val NX: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL)
val IC: EnumSet<MappingMode> = EnumSet.of(INSERT, CMD_LINE)
val NV: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, SELECT)
@JvmField
val NXO: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, OP_PENDING)
@JvmField
val NVO: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, OP_PENDING, SELECT)
val ALL: EnumSet<MappingMode> = EnumSet.allOf(MappingMode::class.java)

View File

@@ -20,7 +20,7 @@ package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.common.DigraphResult
import com.maddyhome.idea.vim.common.DigraphSequence
import com.maddyhome.idea.vim.diagnostic.debug

View File

@@ -95,7 +95,7 @@ abstract class VimMachineBase : VimMachine {
val operatedText = editor.deleteDryRun(range) ?: return null
val normalizedRange = operatedText.toNormalizedTextRange(editor)
injector.registerGroup.storeText(editor, normalizedRange, operatedText.toType(), true)
caret.registerStorage.storeText(editor, normalizedRange, operatedText.toType(), true)
(editor as MutableVimEditor).delete(range)
val start = normalizedRange.startOffset

View File

@@ -16,10 +16,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.common
package com.maddyhome.idea.vim.key
import javax.swing.KeyStroke
/**
* COMPATIBILITY-LAYER: Moved from common package to this one
*/
/**
* All the commands are stored into the tree where the key is either a complete command (for `x`, `j`, `l`, etc.),
* or a part of a command (e.g. `g` for `gg`).

View File

@@ -0,0 +1,42 @@
package com.maddyhome.idea.vim.option
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.options.Option
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.datatypes.parseNumber
/**
* COMPATIBILITY-LAYER: Moved out of class and to a different package
*/
open class NumberOption(name: String, abbrev: String, defaultValue: VimInt) :
Option<VimInt>(name, abbrev, defaultValue) {
constructor(name: String, abbrev: String, defaultValue: Int) : this(name, abbrev, VimInt(defaultValue))
override fun checkIfValueValid(value: VimDataType, token: String) {
if (value !is VimInt) {
throw ExException("E521: Number required after =: $token")
}
}
override fun getValueIfAppend(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value + valueToAdd)
}
override fun getValueIfPrepend(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value * valueToAdd)
}
override fun getValueIfRemove(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value - valueToAdd)
}
fun value(): Int {
return injector.optionService.getOptionValue(OptionScope.GLOBAL, name).asDouble().toInt()
}
}

View File

@@ -37,4 +37,15 @@ class ToggleOption(name: String, abbrev: String, defaultValue: VimInt) : Option<
fun isSet(): Boolean {
return injector.optionService.getOptionValue(OptionScope.GLOBAL, name).asBoolean()
}
/**
* COMPATIBILITY-LAYER: Method added
*/
@Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
override val value: java.lang.Boolean
get() = if (injector.optionService.getOptionValue(OptionScope.GLOBAL, name).asBoolean()) {
java.lang.Boolean(true)
} else {
java.lang.Boolean(false)
}
}

View File

@@ -20,9 +20,7 @@ package com.maddyhome.idea.vim.options
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
import com.maddyhome.idea.vim.vimscript.model.datatypes.parseNumber
import java.util.*
/**
@@ -59,6 +57,13 @@ import java.util.*
}
}
/**
* COMPATIBILITY-LAYER: Method added
*/
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
open val value: java.lang.Boolean
get() = TODO()
// todo 1.9 should return Result with exceptions
abstract fun checkIfValueValid(value: VimDataType, token: String)
@@ -67,31 +72,6 @@ import java.util.*
abstract fun getValueIfRemove(currentValue: VimDataType, value: String, token: String): T
}
open class NumberOption(name: String, abbrev: String, defaultValue: VimInt) : Option<VimInt>(name, abbrev, defaultValue) {
constructor(name: String, abbrev: String, defaultValue: Int) : this(name, abbrev, VimInt(defaultValue))
override fun checkIfValueValid(value: VimDataType, token: String) {
if (value !is VimInt) {
throw ExException("E521: Number required after =: $token")
}
}
override fun getValueIfAppend(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value + valueToAdd)
}
override fun getValueIfPrepend(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value * valueToAdd)
}
override fun getValueIfRemove(currentValue: VimDataType, value: String, token: String): VimInt {
val valueToAdd = parseNumber(token) ?: throw ExException("E521: Number required after =: $token")
return VimInt((currentValue as VimInt).value - valueToAdd)
}
}
open class StringOption(name: String, abbrev: String, defaultValue: VimString, private val isList: Boolean = false, private val boundedValues: Collection<String>? = null) : Option<VimString>(name, abbrev, defaultValue) {
constructor(name: String, abbrev: String, defaultValue: String, isList: Boolean = false, boundedValues: Collection<String>? = null) : this(name, abbrev, VimString(defaultValue), isList, boundedValues)

View File

@@ -23,5 +23,5 @@ interface VimPut {
updateVisualMarks: Boolean = false,
): Boolean
fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean
fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean = false): Boolean
}

View File

@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.register
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import org.jetbrains.annotations.TestOnly
import javax.swing.KeyStroke
interface VimRegisterGroup {
@@ -30,6 +31,7 @@ interface VimRegisterGroup {
* @return The register, null if no such register
*/
val lastRegister: Register?
val lastRegisterChar: Char
val currentRegister: Char
val defaultRegister: Char
@@ -53,6 +55,13 @@ interface VimRegisterGroup {
*/
fun storeText(register: Char, text: String): Boolean
/**
* Stores text to any writable register (used for multicaret tests)
*/
@TestOnly
// todo better tests
fun storeText(register: Char, text: String, selectionType: SelectionType): Boolean
/**
* Stores text, character wise, in the given special register
*

View File

@@ -36,8 +36,7 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
@JvmField
protected var defaultRegisterChar = UNNAMED_REGISTER
@JvmField
protected var lastRegisterChar = defaultRegisterChar
override var lastRegisterChar = defaultRegisterChar
/**
* Gets the last register name selected by the user
@@ -293,7 +292,7 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
return true
}
override fun storeText(register: Char, text: String): Boolean {
override fun storeText(register: Char, text: String, selectionType: SelectionType): Boolean {
if (!WRITABLE_REGISTERS.contains(register)) {
return false
}
@@ -303,7 +302,7 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
} else {
text
}
val reg = Register(register, SelectionType.CHARACTER_WISE, textToStore, ArrayList())
val reg = Register(register, selectionType, textToStore, ArrayList())
saveRegister(register, reg)
if (register == '/') {
injector.searchGroup.lastSearchPattern = text // todo we should not have this field if we have the "/" register
@@ -311,6 +310,10 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
return true
}
override fun storeText(register: Char, text: String): Boolean {
return storeText(register, text, SelectionType.CHARACTER_WISE)
}
private fun guessSelectionType(text: String): SelectionType {
return if (text.endsWith("\n")) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
}

View File

@@ -16,11 +16,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.options
package com.maddyhome.idea.vim.vimscript.services
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.options.Option
import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
/**
* COMPATIBILITY-LAYER: Moved to a different package
*/
interface OptionService {
/**
@@ -30,7 +36,7 @@ interface OptionService {
* @param token used in exception messages
* @throws ExException("E518: Unknown option: $token")
*/
fun getOptionValue(scope: OptionScope, optionName: String, token: String = optionName): VimDataType
fun getOptionValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName): VimDataType
/**
* Sets option value.
@@ -40,7 +46,7 @@ interface OptionService {
* @param token used in exception messages
* @throws ExException("E518: Unknown option: $token")
*/
fun setOptionValue(scope: OptionScope, optionName: String, value: VimDataType, token: String = optionName)
fun setOptionValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: VimDataType, token: String = optionName)
/**
* Checks if the [value] is contained in string option.
@@ -50,7 +56,7 @@ interface OptionService {
* @param optionName option name or alias
* @param value option value
*/
fun contains(scope: OptionScope, optionName: String, value: String): Boolean
fun contains(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: String): Boolean
/**
* Splits a string option into flags
@@ -61,7 +67,7 @@ interface OptionService {
* @param scope global/local option scope
* @param optionName option name or alias
*/
fun getValues(scope: OptionScope, optionName: String): List<String>?
fun getValues(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String): List<String>?
/**
* Same as [setOptionValue], but automatically casts [value] to the required [VimDataType]
@@ -72,7 +78,7 @@ interface OptionService {
* @throws ExException("E518: Unknown option: $token") in case the option is not found
* @throws ExException("E474: Invalid argument: $token") in case the cast to VimDataType is impossible
*/
fun setOptionValue(scope: OptionScope, optionName: String, value: String, token: String = optionName)
fun setOptionValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: String, token: String = optionName)
/**
* Same as `set {option}+={value}` in Vim documentation.
@@ -85,7 +91,7 @@ interface OptionService {
* @throws ExException("E474: Invalid argument: $token") in case the method was called for the [StringOption] and the argument is invalid (does not satisfy the option bounded values)
* @throws ExException("E521: Number required after =: $token") in case the cast to VimInt is impossible
*/
fun appendValue(scope: OptionScope, optionName: String, value: String, token: String = optionName)
fun appendValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: String, token: String = optionName)
/**
* Same as `set {option}^={value}` in Vim documentation.
@@ -98,7 +104,7 @@ interface OptionService {
* @throws ExException("E474: Invalid argument: $token") in case the method was called for the [StringOption] and the argument is invalid (does not satisfy the option bounded values)
* @throws ExException("E521: Number required after =: $token") in case the cast to VimInt is impossible
*/
fun prependValue(scope: OptionScope, optionName: String, value: String, token: String = optionName)
fun prependValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: String, token: String = optionName)
/**
* Same as `set {option}-={value}` in Vim documentation.
@@ -111,7 +117,7 @@ interface OptionService {
* @throws ExException("E474: Invalid argument: $token") in case the method was called for the [StringOption] and the argument is invalid (does not satisfy the option bounded values)
* @throws ExException("E521: Number required after =: $token") in case the cast to VimInt is impossible
*/
fun removeValue(scope: OptionScope, optionName: String, value: String, token: String = optionName)
fun removeValue(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, value: String, token: String = optionName)
/**
* Checks if the toggle option on.
@@ -122,7 +128,7 @@ interface OptionService {
* @param token used in exception messages
* @throws ExException("E518: Unknown option: $token") in case the option is not found
*/
fun isSet(scope: OptionScope, optionName: String, token: String = optionName): Boolean
fun isSet(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName): Boolean
/**
* Checks if the option's value set to default.
@@ -132,7 +138,7 @@ interface OptionService {
* @param token used in exception messages
* @throws ExException("E518: Unknown option: $token") in case the option is not found
*/
fun isDefault(scope: OptionScope, optionName: String, token: String = optionName): Boolean
fun isDefault(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName): Boolean
/**
* Resets option's value to default.
@@ -142,7 +148,7 @@ interface OptionService {
* @param token used in exception messages
* @throws ExException("E518: Unknown option: $token") in case the option is not found
*/
fun resetDefault(scope: OptionScope, optionName: String, token: String = optionName)
fun resetDefault(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName)
/**
* Resets all options back to default values.
@@ -163,7 +169,12 @@ interface OptionService {
* @throws ExException("E518: Unknown option: $token") in case the option is not found
* @throws ExException("E474: Invalid argument: $token") in case the option is not a [ToggleOption]
*/
fun setOption(scope: OptionScope, optionName: String, token: String = optionName)
fun setOption(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName)
/**
* COMPATIBILITY-LAYER: New method added
*/
fun setOption(scope: Scope, optionName: String, token: String = optionName)
/**
* Unsets the option (false).
@@ -173,7 +184,7 @@ interface OptionService {
* @throws ExException("E518: Unknown option: $token") in case the option is not found
* @throws ExException("E474: Invalid argument: $token") in case the option is not a [ToggleOption]
*/
fun unsetOption(scope: OptionScope, optionName: String, token: String = optionName)
fun unsetOption(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName)
/**
* Inverts boolean option value true -> false / false -> true.
@@ -183,7 +194,7 @@ interface OptionService {
* @throws ExException("E518: Unknown option: $token") in case the option is not found
* @throws ExException("E474: Invalid argument: $token") in case the option is not a [ToggleOption]
*/
fun toggleOption(scope: OptionScope, optionName: String, token: String = optionName)
fun toggleOption(scope: com.maddyhome.idea.vim.options.OptionScope, optionName: String, token: String = optionName)
/**
* @return list of all option names
@@ -221,4 +232,12 @@ interface OptionService {
* @param listener option listener
*/
fun removeListener(optionName: String, listener: OptionChangeListener<VimDataType>)
/**
* COMPATIBILITY-LAYER: Added this class
*/
sealed class Scope {
object GLOBAL : Scope()
class LOCAL(val editor: VimEditor) : Scope()
}
}

View File

@@ -26,7 +26,11 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
import org.jetbrains.annotations.TestOnly
interface VimVariableService {
/**
* COMPATIBILITY-LAYER: Renamed from VimVariableService
*/
interface VariableService {
/**
* Stores variable.
*

View File

@@ -13,7 +13,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
abstract class VimVariableServiceBase : VimVariableService {
abstract class VimVariableServiceBase : VariableService {
private var globalVariables: MutableMap<String, VimDataType> = mutableMapOf()
private val windowVariablesKey = Key<MutableMap<String, VimDataType>>("TabVariables")
private val bufferVariablesKey = Key<MutableMap<String, VimDataType>>("BufferVariables")