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

Compare commits

..

10 Commits

Author SHA1 Message Date
edb9b194bb Set plugin version to chylex-12 2022-07-06 01:15:57 +02:00
Alex Plate
eae7ed95e2 Revert "Fix(VIM-308) Undo requires one more step if the cursor is not at the position where it was after undo"
This reverts commit 9dbe3c33
2022-07-06 01:15:56 +02:00
a1e2ae0eb9 Change matchit plugin to use HTML patterns in unrecognized files 2022-07-06 01:15:56 +02:00
eae2e3b6b8 Fix put command not working with multiple cursors 2022-07-06 01:15:56 +02:00
c2d997a520 Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2022-07-06 01:15:56 +02:00
e2a8a3c21a Add VimScript 'renaming()' function 2022-07-06 01:08:14 +02:00
9b7fee6163 Add support for repeatable actions with ':raction' 2022-07-06 01:08:14 +02:00
d0f9d3dc70 Implement partial code completion support in macros
Works ok with insertions (Enter, Ctrl+Enter) but not with replacements (Tab)
2022-07-06 01:08:14 +02:00
8d3a69b338 Disable taking over arrow keys and Home/End 2022-07-06 01:08:14 +02:00
3c530474a1 Set custom plugin version 2022-07-06 01:08:14 +02:00
95 changed files with 2546 additions and 3714 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.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang 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.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.* import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/* /*
@@ -17,33 +17,17 @@ create(DslContext.projectId, BuildType({
name = "IdeaVim compatibility with external plugins" name = "IdeaVim compatibility with external plugins"
vcs { vcs {
root(DslContext.settingsRoot) root(RelativeId("HttpsGithubComAlexPl292IdeaVimCompatibilityRefsHeadsMaster"))
} }
steps { steps {
script { script {
name = "Check" scriptContent = "go run test.go"
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 { triggers {
schedule { vcs {
schedulingPolicy = daily {
hour = 4
}
branchFilter = ""
triggerBuild = always()
withPendingChangesOnly = false
} }
} }

View File

@@ -1,9 +1,9 @@
# suppress inspection "UnusedProperty" for whole file # suppress inspection "UnusedProperty" for whole file
ideaVersion=LATEST-EAP-SNAPSHOT ideaVersion=2022.1.2
downloadIdeaSources=true downloadIdeaSources=true
instrumentPluginCode=true instrumentPluginCode=true
version=SNAPSHOT version=chylex-12
javaVersion=11 javaVersion=11
remoteRobotVersion=0.11.10 remoteRobotVersion=0.11.10
antlrVersion=4.10.1 antlrVersion=4.10.1

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

View File

@@ -148,6 +148,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false
if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false
if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT) return false
if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) return false
if (keyCode == KeyEvent.VK_HOME || keyCode == KeyEvent.VK_END) return false
if (editor.inInsertMode) { if (editor.inInsertMode) {
if (keyCode == KeyEvent.VK_TAB) { if (keyCode == KeyEvent.VK_TAB) {

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.VimActionHandler
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import java.util.* import java.util.*

View File

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

View File

@@ -23,7 +23,6 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.change.Extension 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.MappingMode
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.CommandAlias import com.maddyhome.idea.vim.common.CommandAlias
@@ -60,8 +59,8 @@ object VimExtensionFacade {
} }
/** /**
* COMPATIBILITY-LAYER: Additional method * COMPATIBILITY-LAYER: Additional method
*/ */
/** The 'map' command for mapping keys to handlers defined in extensions. */ /** The 'map' command for mapping keys to handlers defined in extensions. */
@JvmStatic @JvmStatic
fun putExtensionHandlerMapping( fun putExtensionHandlerMapping(
@@ -183,24 +182,12 @@ object VimExtensionFacade {
return reg.keys 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 */ /** Set the current contents of the given register */
@JvmStatic @JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?) { fun setRegister(register: Char, keys: List<KeyStroke?>?) {
VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList()) 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 */ /** Set the current contents of the given register */
@JvmStatic @JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) { 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.api.injector
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.OptionChangeListener import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.OptionScope 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.statistic.PluginState
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType

View File

@@ -34,14 +34,13 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.TextObjectVisualType 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.common.CommandAliasHandler
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.ranges.Ranges 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.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
@@ -49,6 +48,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction 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.handler.TextObjectActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper import com.maddyhome.idea.vim.helper.PsiHelper

View File

@@ -31,11 +31,10 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
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.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange 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.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
@@ -43,6 +42,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister 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.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition 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.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags 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.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Direction import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing 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.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotionOrError import com.maddyhome.idea.vim.handler.toMotionOrError
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import java.util.* import java.util.*
@@ -233,7 +233,7 @@ private object FileTypePatterns {
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") { } else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
this.cMakePatterns this.cMakePatterns
} else { } else {
return null this.htmlPatterns
} }
} }

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.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector 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
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension 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.api.injector
import com.maddyhome.idea.vim.common.CommandAlias import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.key.CommandNode import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.key.Node import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.key.RootNode import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.key.addLeafs import com.maddyhome.idea.vim.common.addLeafs
import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.group.KeyGroup 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.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode 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.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing 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.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.SearchHelper import com.maddyhome.idea.vim.helper.SearchHelper

View File

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

View File

@@ -22,7 +22,7 @@ import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimChangeGroup
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
@@ -32,21 +32,22 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegisterForCaret import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.editorMode import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
import com.maddyhome.idea.vim.key.OperatorFunction import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimCaret import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
import com.maddyhome.idea.vim.put.PutData
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import javax.swing.KeyStroke import javax.swing.KeyStroke
@@ -85,22 +86,20 @@ class VimSurroundExtension : VimExtension {
override val isRepeatable = true override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {
setOperatorFunction(Operator()) setOperatorFunction(Operator(supportsMultipleCursors = false)) // TODO
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij) executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
} }
} }
private class VSurroundHandler : ExtensionHandler { private class VSurroundHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) { override fun execute(editor: VimEditor, context: ExecutionContext) {
val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart
// NB: Operator ignores SelectionType anyway // NB: Operator ignores SelectionType anyway
if (!Operator().apply(editor.ij, context.ij, SelectionType.CHARACTER_WISE)) { if (!Operator(supportsMultipleCursors = true).apply(editor.ij, context.ij, SelectionType.CHARACTER_WISE)) {
return return
} }
runWriteAction { runWriteAction {
// Leave visual mode // Leave visual mode
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij) executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
editor.ij.caretModel.moveToOffset(selectionStart)
} }
} }
} }
@@ -116,70 +115,37 @@ class VimSurroundExtension : VimExtension {
if (charTo.code == 0) return if (charTo.code == 0) return
val newSurround = getOrInputPair(charTo, editor.ij) ?: return val newSurround = getOrInputPair(charTo, editor.ij) ?: return
runWriteAction { change(editor, context, charFrom, newSurround) } runWriteAction { change(editor.ij, charFrom, newSurround) }
} }
companion object { companion object {
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) { fun change(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets editor.runWithEveryCaretAndRestore { changeAtCaret(editor, charFrom, newSurround) }
val surroundings = editor.sortedCarets() }
.map {
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it) fun changeAtCaret(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
setRegisterForCaret(REGISTER, it, null) // We take over the " register, so preserve it
SurroundingInfo(it, null, oldValue, null) val oldValue: List<KeyStroke>? = getRegister(REGISTER)
} // Empty the " register
setRegister(REGISTER, null)
// Delete surrounding's content // Extract the inner value
perform("di" + pick(charFrom), editor.ij) perform("di" + pick(charFrom), editor)
val innerValue: MutableList<KeyStroke> = getRegister(REGISTER)?.toMutableList() ?: mutableListOf()
// Add info about surrounding's inner text and location // If the surrounding characters were not found, the register will be empty
surroundings.forEach { if (innerValue.isNotEmpty()) {
val registerValue = getRegisterForCaret(REGISTER, it.caret) // Delete the surrounding
val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue perform("da" + pick(charFrom), editor)
it.innerText = innerValue // Insert the surrounding characters and paste
if (newSurround != null) {
val lineEndOffset = injector.engineEditorHelper.getLineEndOffset(editor, it.caret.getLine().line, false) innerValue.addAll(0, injector.parser.parseKeys(newSurround.first))
if (lineEndOffset == it.caret.offset.point) { innerValue.addAll(injector.parser.parseKeys(newSurround.second))
it.isLineEnd = true
} }
pasteSurround(innerValue, editor)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
} }
// Restore the old value
// Remove surrounding setRegister(REGISTER, oldValue)
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()
}
} }
private fun perform(sequence: String, editor: Editor) { private fun perform(sequence: String, editor: Editor) {
@@ -187,6 +153,21 @@ class VimSurroundExtension : VimExtension {
.use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) } .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) { private fun pick(charFrom: Char) = when (charFrom) {
'a' -> '>' 'a' -> '>'
'r' -> ']' 'r' -> ']'
@@ -195,18 +176,6 @@ 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 { private class DSurroundHandler : ExtensionHandler {
override val isRepeatable = true override val isRepeatable = true
@@ -215,29 +184,47 @@ class VimSurroundExtension : VimExtension {
val charFrom = getChar(editor.ij) val charFrom = getChar(editor.ij)
if (charFrom.code == 0) return if (charFrom.code == 0) return
runWriteAction { CSurroundHandler.change(editor, context, charFrom, null) } runWriteAction { CSurroundHandler.change(editor.ij, charFrom, null) }
} }
} }
private class Operator : OperatorFunction { private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction {
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val c = getChar(editor) val c = getChar(editor)
if (c.code == 0) return true if (c.code == 0) return true
val pair = getOrInputPair(c, editor) ?: return false val pair = getOrInputPair(c, editor) ?: return false
// XXX: Will it work with line-wise or block-wise selections?
val range = getSurroundRange(editor) ?: return false
runWriteAction { runWriteAction {
val change = VimPlugin.getChange() val change = VimPlugin.getChange()
val leftSurround = pair.first if (supportsMultipleCursors) {
val primaryCaret = editor.caretModel.primaryCaret editor.runWithEveryCaretAndRestore {
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, leftSurround) applyOnce(editor, change, pair)
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + leftSurround.length, pair.second) }
// Jump back to start }
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor) else {
applyOnce(editor, change, pair)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
}
} }
return true return true
} }
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>) {
// XXX: Will it work with line-wise or block-wise selections?
val range = getSurroundRange(editor)
if (range != null) {
val primaryCaret = editor.caretModel.primaryCaret
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, pair.first)
change.insertText(
IjVimEditor(editor),
IjVimCaret(primaryCaret),
range.endOffset + pair.first.length,
pair.second
)
}
}
private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) { private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) {
VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim) VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim)

View File

@@ -50,7 +50,10 @@ import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.key.KeyHandlerKeeper; import com.maddyhome.idea.vim.key.KeyHandlerKeeper;
import com.maddyhome.idea.vim.listener.VimInsertListener; import com.maddyhome.idea.vim.listener.VimInsertListener;
import com.maddyhome.idea.vim.newapi.*; import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjExecutionContextKt;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.OptionConstants; import com.maddyhome.idea.vim.options.OptionConstants;
import com.maddyhome.idea.vim.options.OptionScope; import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString; import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString;
@@ -200,6 +203,61 @@ public class ChangeGroup extends VimChangeGroupBase {
return new Pair<>(range, type); return new Pair<>(range, type);
} }
/**
* Delete the range of text.
*
* @param editor The editor to delete the text from
* @param caret The caret to be moved after deletion
* @param range The range to delete
* @param type The type of deletion
* @param isChange Is from a change action
* @return true if able to delete the text, false if not
*/
@Override
public boolean deleteRange(@NotNull VimEditor editor,
@NotNull VimCaret caret,
@NotNull TextRange range,
@Nullable SelectionType type,
boolean isChange,
boolean noYank) {
// Update the last column before we delete, or we might be retrieving the data for a line that no longer exists
UserDataManager.setVimLastColumn(((IjVimCaret) caret).getCaret(), InlayHelperKt.getInlayAwareVisualColumn(((IjVimCaret) caret).getCaret()));
boolean removeLastNewLine = removeLastNewLine(editor, range, type);
final boolean res = deleteText(editor, range, type, noYank);
if (removeLastNewLine) {
int textLength = ((IjVimEditor) editor).getEditor().getDocument().getTextLength();
((IjVimEditor) editor).getEditor().getDocument().deleteString(textLength - 1, textLength);
}
if (res) {
int pos = EditorHelper.normalizeOffset(((IjVimEditor) editor).getEditor(), range.getStartOffset(), isChange);
if (type == SelectionType.LINE_WISE) {
pos = VimPlugin.getMotion()
.moveCaretToLineWithStartOfLineOption(editor, editor.offsetToLogicalPosition(pos).getLine(),
caret);
}
injector.getMotion().moveCaret(editor, caret, pos);
}
return res;
}
private boolean removeLastNewLine(@NotNull VimEditor editor, @NotNull TextRange range, @Nullable SelectionType type) {
int endOffset = range.getEndOffset();
int fileSize = EditorHelperRt.getFileSize(((IjVimEditor) editor).getEditor());
if (endOffset > fileSize) {
if (injector.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, OptionConstants.ideastrictmodeName, OptionConstants.ideastrictmodeName)) {
throw new IllegalStateException("Incorrect offset. File size: " + fileSize + ", offset: " + endOffset);
}
endOffset = fileSize;
}
return type == SelectionType.LINE_WISE &&
range.getStartOffset() != 0 &&
((IjVimEditor) editor).getEditor().getDocument().getCharsSequence().charAt(endOffset - 1) != '\n' &&
endOffset == fileSize;
}
@Override @Override
public void insertLineAround(@NotNull VimEditor editor, @NotNull ExecutionContext context, int shift) { public void insertLineAround(@NotNull VimEditor editor, @NotNull ExecutionContext context, int shift) {
com.maddyhome.idea.vim.newapi.ChangeGroupKt.insertLineAround(editor, context, shift); com.maddyhome.idea.vim.newapi.ChangeGroupKt.insertLineAround(editor, context, shift);
@@ -228,7 +286,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret, @NotNull VimCaret caret,
@NotNull ExecutionContext context, @NotNull ExecutionContext context,
@NotNull Argument argument, @NotNull Argument argument,
@NotNull OperatorArguments operatorArguments) { @NotNull OperatorArguments operatorArguments,
boolean noYank) {
int count0 = operatorArguments.getCount0(); int count0 = operatorArguments.getCount0();
// Vim treats cw as ce and cW as cE if cursor is on a non-blank character // Vim treats cw as ce and cW as cE if cursor is on a non-blank character
final Command motion = argument.getMotion(); final Command motion = argument.getMotion();
@@ -306,7 +365,7 @@ public class ChangeGroup extends VimChangeGroupBase {
Pair<TextRange, SelectionType> deleteRangeAndType = Pair<TextRange, SelectionType> deleteRangeAndType =
getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0)); getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0));
if (deleteRangeAndType == null) return false; if (deleteRangeAndType == null) return false;
return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context); return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context, noYank);
} }
} }
@@ -436,7 +495,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret, @NotNull VimCaret caret,
@NotNull TextRange range, @NotNull TextRange range,
@NotNull SelectionType type, @NotNull SelectionType type,
ExecutionContext context) { @Nullable ExecutionContext context,
boolean noYank) {
int col = 0; int col = 0;
int lines = 0; int lines = 0;
if (type == SelectionType.BLOCK_WISE) { if (type == SelectionType.BLOCK_WISE) {
@@ -450,7 +510,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret)); final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret));
boolean res = deleteRange(editor, caret, range, type, true); boolean res = deleteRange(editor, caret, range, type, true, noYank);
if (res) { if (res) {
if (type == SelectionType.LINE_WISE) { if (type == SelectionType.LINE_WISE) {
// Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String // Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String
@@ -675,7 +735,7 @@ public class ChangeGroup extends VimChangeGroupBase {
} }
} }
if (pos > wsoff) { if (pos > wsoff) {
deleteText(editor, new TextRange(wsoff, pos), null, caret); deleteText(editor, new TextRange(wsoff, pos), null, false);
} }
} }
} }

View File

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

View File

@@ -92,7 +92,7 @@ public class ProcessGroup extends VimProcessGroupBase {
String initText = getRange(((IjVimEditor) editor).getEditor(), cmd); String initText = getRange(((IjVimEditor) editor).getEditor(), cmd);
VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE); VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE);
ExEntryPanel panel = ExEntryPanel.getInstance(); ExEntryPanel panel = ExEntryPanel.getInstance();
panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, 1); panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, cmd.getCount());
} }
@Override @Override
@@ -123,7 +123,7 @@ public class ProcessGroup extends VimProcessGroupBase {
logger.debug("processing command"); logger.debug("processing command");
final String text = panel.getText(); String text = panel.getText();
if (!panel.getLabel().equals(":")) { if (!panel.getLabel().equals(":")) {
// Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for // Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for
@@ -134,7 +134,15 @@ public class ProcessGroup extends VimProcessGroupBase {
if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread());
VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE); int repeat = 1;
if (text.contains("raction ")) {
text = text.replace("raction ", "action ");
repeat = panel.getCount();
}
for (int i = 0; i < repeat; i++) {
VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE);
}
} }
catch (ExException e) { catch (ExException e) {
VimPlugin.showMessage(e.getMessage()); VimPlugin.showMessage(e.getMessage());

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.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.isBlock import com.maddyhome.idea.vim.command.isBlock
import com.maddyhome.idea.vim.command.isChar import com.maddyhome.idea.vim.command.isChar
import com.maddyhome.idea.vim.command.isLine import com.maddyhome.idea.vim.command.isLine
@@ -60,14 +60,10 @@ import java.awt.datatransfer.DataFlavor
import kotlin.math.min import kotlin.math.min
class PutGroup : VimPutBase() { class PutGroup : VimPutBase() {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean): Boolean { override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean {
val additionalData = collectPreModificationData(editor, data) val additionalData = collectPreModificationData(editor, data)
data.visualSelection?.let { deleteSelectedText(editor, data) }
val processedText = processText(editor, data) ?: return false val processedText = processText(editor, data) ?: return false
putForCaret(editor, caret, data, additionalData, context, processedText) putForCaret(editor, caret, data, additionalData, context, processedText)
if (editor.primaryCaret() == caret && updateVisualMarks) {
wrapInsertedTextWithVisualMarks(editor, data, processedText)
}
return true return true
} }
@@ -101,7 +97,22 @@ class PutGroup : VimPutBase() {
EditorHelper.getOrderedCaretsList(editor.ij).map { IjVimCaret(it) } EditorHelper.getOrderedCaretsList(editor.ij).map { IjVimCaret(it) }
} }
injector.application.runWriteAction { injector.application.runWriteAction {
myCarets.forEach { caret -> putForCaret(editor, caret, data, additionalData, context, text) } val singleCaret = myCarets.singleOrNull()
if (singleCaret != null) {
putForCaret(editor, singleCaret, data, additionalData, context, text)
}
else {
val lines = text.text.split('\n')
if (lines.size != myCarets.size) {
myCarets.forEach { caret -> putForCaret(editor, caret, data, additionalData, context, text) }
}
else {
myCarets.asReversed().forEachIndexed { index, caret ->
val line = ProcessedTextData(lines[index], text.typeInRegister, text.transferableData)
putForCaret(editor, caret, data, additionalData, context, line)
}
}
}
} }
} }
@@ -122,9 +133,7 @@ class PutGroup : VimPutBase() {
editor, caret, context, text.text, text.typeInRegister, subMode, editor, caret, context, text.text, text.typeInRegister, subMode,
startOffset, data.count, data.indent, data.caretAfterInsertedText startOffset, data.count, data.indent, data.caretAfterInsertedText
) )
if (caret == editor.primaryCaret()) { VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
}
moveCaretToEndPosition( moveCaretToEndPosition(
editor, editor,
caret, caret,
@@ -235,13 +244,13 @@ class PutGroup : VimPutBase() {
} }
private fun putTextViaIde( private fun putTextViaIde(
pasteProvider: PasteProvider, pasteProvider: PasteProvider,
vimEditor: VimEditor, vimEditor: VimEditor,
vimContext: ExecutionContext, vimContext: ExecutionContext,
text: ProcessedTextData, text: ProcessedTextData,
subMode: VimStateMachine.SubMode, subMode: VimStateMachine.SubMode,
data: PutData, data: PutData,
additionalData: Map<String, Any>, additionalData: Map<String, Any>,
) { ) {
val editor = (vimEditor as IjVimEditor).editor val editor = (vimEditor as IjVimEditor).editor
val context = vimContext.context as DataContext val context = vimContext.context as DataContext

View File

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

View File

@@ -22,6 +22,7 @@ package com.maddyhome.idea.vim.helper
import com.intellij.codeWithMe.ClientId import com.intellij.codeWithMe.ClientId
import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.CaretState
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.util.EditorUtil import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
@@ -106,3 +107,41 @@ val Caret.vimLine: Int
*/ */
val Editor.vimLine: Int val Editor.vimLine: Int
get() = this.caretModel.currentCaret.vimLine get() = this.caretModel.currentCaret.vimLine
inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) {
val caretModel = this.caretModel
val carets = if (this.inBlockSubMode) null else caretModel.allCarets
if (carets == null || carets.size == 1) {
action()
}
else {
var initialDocumentSize = this.document.textLength
var documentSizeDifference = 0
val caretOffsets = carets.map { it.selectionStart to it.selectionEnd }
val restoredCarets = mutableListOf<CaretState>()
caretModel.removeSecondaryCarets()
for ((selectionStart, selectionEnd) in caretOffsets) {
if (selectionStart == selectionEnd) {
caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference)
}
else {
caretModel.primaryCaret.setSelection(
selectionStart + documentSizeDifference,
selectionEnd + documentSizeDifference
)
}
action()
restoredCarets.add(caretModel.caretsAndSelections.single())
val documentLength = this.document.textLength
documentSizeDifference += documentLength - initialDocumentSize
initialDocumentSize = documentLength
}
caretModel.caretsAndSelections = restoredCarets
}
}

View File

@@ -25,9 +25,9 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor 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.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType 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.common.TextRange
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjExecutionContext import com.maddyhome.idea.vim.newapi.IjExecutionContext

View File

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

@@ -25,9 +25,7 @@ import com.intellij.openapi.command.undo.UndoManager
import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.ChangesListener
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
@@ -49,7 +47,7 @@ class UndoRedoHelper : UndoRedoBase() {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) } SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
} else { } else {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) }) undoManager.undo(fileEditor)
editor?.carets()?.forEach { editor?.carets()?.forEach {
val ijCaret = it.ij val ijCaret = it.ij
val hasSelection = ijCaret.hasSelection() val hasSelection = ijCaret.hasSelection()
@@ -75,30 +73,14 @@ class UndoRedoHelper : UndoRedoBase() {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) } SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
} else { } else {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) }) undoManager.redo(fileEditor)
if (editor?.primaryCaret()?.ij?.hasSelection() == true) {
undoManager.redo(fileEditor)
}
editor?.carets()?.forEach { it.ij.removeSelection() } editor?.carets()?.forEach { it.ij.removeSelection() }
} }
return true return true
} }
return false return false
} }
private fun performUntilFileChanges(editor: IjVimEditor?, check: () -> Boolean, action: Runnable) {
if (editor == null) return
val vimDocument = editor.document
val changeListener = object : ChangesListener {
var hasChanged = false
override fun documentChanged(change: ChangesListener.Change) {
hasChanged = true
}
}
vimDocument.addChangeListener(changeListener)
while (check() && !changeListener.hasChanged) {
action.run()
}
vimDocument.removeChangeListener(changeListener)
}
} }

View File

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

View File

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

View File

@@ -19,8 +19,10 @@
package com.maddyhome.idea.vim.listener package com.maddyhome.idea.vim.listener
import com.intellij.codeInsight.lookup.Lookup import com.intellij.codeInsight.lookup.Lookup
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.LookupManagerListener import com.intellij.codeInsight.lookup.LookupManagerListener
import com.intellij.codeInsight.lookup.impl.LookupImpl import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction
import com.intellij.codeInsight.template.Template import com.intellij.codeInsight.template.Template
import com.intellij.codeInsight.template.TemplateEditingAdapter import com.intellij.codeInsight.template.TemplateEditingAdapter
import com.intellij.codeInsight.template.TemplateManagerListener import com.intellij.codeInsight.template.TemplateManagerListener
@@ -35,20 +37,22 @@ import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.project.DumbAwareToggleAction
import com.intellij.openapi.util.TextRange
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.VimStateMachine 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.EditorDataContext
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.inNormalMode import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere 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.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.options.helpers.IdeaRefactorModeHelper import com.maddyhome.idea.vim.vimscript.model.options.helpers.IdeaRefactorModeHelper
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
/** /**
* @author Alex Plate * @author Alex Plate
@@ -60,6 +64,8 @@ object IdeaSpecifics {
private val surrounderAction = private val surrounderAction =
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction" "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null private var editor: Editor? = null
private var completionPrevDocumentLength: Int? = null
private var completionPrevDocumentOffset: Int? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
@@ -68,19 +74,52 @@ object IdeaSpecifics {
editor = hostEditor editor = hostEditor
} }
//region Track action id
if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) { if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) {
if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) { val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) }
if (hostEditor != null && action is ChooseItemAction && hostEditor.vimStateMachine?.isRecording == true) {
val lookup = LookupManager.getActiveLookup(hostEditor)
if (lookup != null) {
val charsToRemove = hostEditor.caretModel.primaryCaret.offset - lookup.lookupStart
val register = VimPlugin.getRegister()
val backSpace = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
repeat(charsToRemove) {
register.recordKeyStroke(backSpace)
}
completionPrevDocumentLength = hostEditor.document.textLength - charsToRemove
completionPrevDocumentOffset = lookup.lookupStart
} }
} }
//endregion
} }
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return if (!VimPlugin.isEnabled()) return
val editor = editor
if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
val prevDocumentLength = completionPrevDocumentLength
val prevDocumentOffset = completionPrevDocumentOffset
if (prevDocumentLength != null && prevDocumentOffset != null) {
val register = VimPlugin.getRegister()
val addedTextLength = editor.document.textLength - prevDocumentLength
val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
repeat(caretShift.coerceAtLeast(0)) {
register.recordKeyStroke(leftArrow)
}
}
this.completionPrevDocumentLength = null
this.completionPrevDocumentOffset = null
}
//region Enter insert mode after surround with if //region Enter insert mode after surround with if
if (surrounderAction == action.javaClass.name && surrounderItems.any { if (surrounderAction == action.javaClass.name && surrounderItems.any {
action.templatePresentation.text.endsWith( action.templatePresentation.text.endsWith(
@@ -99,7 +138,7 @@ object IdeaSpecifics {
} }
//endregion //endregion
editor = null this.editor = null
} }
} }

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.VimEditor
import com.maddyhome.idea.vim.api.VimMotionGroupBase import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.EditorLine import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.IndentConfig import com.maddyhome.idea.vim.common.IndentConfig
import com.maddyhome.idea.vim.common.OperatedRange import com.maddyhome.idea.vim.common.OperatedRange

View File

@@ -22,10 +22,7 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.LogicalPosition import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin 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.VimCaret
import com.maddyhome.idea.vim.api.VimCaretBase
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimVisualPosition import com.maddyhome.idea.vim.api.VimVisualPosition
@@ -41,23 +38,13 @@ import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection
import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset 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.vimInsertStart
import com.maddyhome.idea.vim.helper.vimLastColumn import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
import com.maddyhome.idea.vim.helper.vimLine import com.maddyhome.idea.vim.helper.vimLine
import com.maddyhome.idea.vim.helper.vimSelectionStart import com.maddyhome.idea.vim.helper.vimSelectionStart
class IjVimCaret(val caret: Caret) : VimCaretBase() { class IjVimCaret(val caret: Caret) : VimCaret {
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 override val editor: VimEditor
get() = IjVimEditor(caret.editor) get() = IjVimEditor(caret.editor)
override val offset: Offset 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.VimSelectionModel
import com.maddyhome.idea.vim.api.VimVisualPosition import com.maddyhome.idea.vim.api.VimVisualPosition
import com.maddyhome.idea.vim.api.VirtualFile 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.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType 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.EditorLine
import com.maddyhome.idea.vim.common.LiveRange import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset 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.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.vimscript.services.OptionService import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.put.VimPut import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.ui.VimRcFileState 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.Executor
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.PatternService import com.maddyhome.idea.vim.vimscript.services.PatternService
import com.maddyhome.idea.vim.vimscript.services.VariableService import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.yank.VimYankGroup import com.maddyhome.idea.vim.yank.VimYankGroup
class IjVimInjector : VimInjectorBase() { class IjVimInjector : VimInjectorBase() {
@@ -161,7 +161,7 @@ class IjVimInjector : VimInjectorBase() {
override val functionService: VimscriptFunctionService override val functionService: VimscriptFunctionService
get() = FunctionStorage get() = FunctionStorage
override val variableService: VariableService override val variableService: VimVariableService
get() = service() get() = service()
override val vimrcFileState: VimrcFileState override val vimrcFileState: VimrcFileState
get() = VimRcFileState get() = VimRcFileState

View File

@@ -22,8 +22,6 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionConstants.Companion.ignorecaseName 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.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.OptionScope
import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper import com.maddyhome.idea.vim.options.helpers.KeywordOptionHelper
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
@@ -36,10 +34,6 @@ object OptionsManager {
get() = (injector.optionService as IjVimOptionService).getRawOption(ignorecaseName) as ToggleOption get() = (injector.optionService as IjVimOptionService).getRawOption(ignorecaseName) as ToggleOption
val smartcase: ToggleOption val smartcase: ToggleOption
get() = (injector.optionService as IjVimOptionService).getRawOption(smartcaseName) as 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 val iskeyword: KeywordOption
get() = KeywordOption(KeywordOptionHelper) 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.KeyHandler
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.isCloseKeyStroke
import java.awt.KeyEventDispatcher import java.awt.KeyEventDispatcher
import java.awt.KeyboardFocusManager import java.awt.KeyboardFocusManager
import java.awt.Toolkit import java.awt.Toolkit

View File

@@ -0,0 +1,48 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2021 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.vimscript.model.functions.handlers
import com.intellij.refactoring.rename.inplace.InplaceRefactoring
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.vimscript.model.VimLContext
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.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
object RenamingFunctionHandler : FunctionHandler() {
override val name = "renaming"
override val minimumNumberOfArguments = 0
override val maximumNumberOfArguments = 0
override fun doFunction(
argumentValues: List<Expression>,
editor: VimEditor,
context: ExecutionContext,
vimContext: VimLContext,
): VimDataType {
return if (InplaceRefactoring.getActiveInplaceRenamer(editor.ij) == null)
VimInt.ZERO
else
VimInt.ONE
}
}

View File

@@ -25,9 +25,9 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.template.impl.TemplateManagerImpl import com.intellij.codeInsight.template.impl.TemplateManagerImpl
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin 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.hasBlockOrUnderscoreCaret
import com.maddyhome.idea.vim.helper.hasVisualSelection 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.helper.subMode
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim

View File

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

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.Scope
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
class IjVariableService : VimVariableServiceBase() { internal class VimVariableServiceImpl : VimVariableServiceBase() {
override fun storeVariable(variable: Variable, value: VimDataType, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) { override fun storeVariable(variable: Variable, value: VimDataType, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) {
super.storeVariable(variable, value, editor, context, vimContext) super.storeVariable(variable, value, editor, context, vimContext)

View File

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

View File

@@ -14,5 +14,6 @@
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler" name="tolower"/> <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler" name="tolower"/>
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler" name="toupper"/> <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler" name="toupper"/>
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/> <vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler" name="join"/>
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.RenamingFunctionHandler" name="renaming"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@@ -1,4 +1,4 @@
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude"> <idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
<name>IdeaVim</name> <name>IdeaVim</name>
<id>IdeaVIM</id> <id>IdeaVIM</id>
<change-notes><![CDATA[ <change-notes><![CDATA[
@@ -65,7 +65,7 @@
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li> <li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
</ul> </ul>
]]></description> ]]></description>
<version>SNAPSHOT</version> <version>chylex</version>
<vendor>JetBrains</vendor> <vendor>JetBrains</vendor>
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version --> <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->

View File

@@ -31,8 +31,9 @@ import com.maddyhome.idea.vim.helper.RunnableHelper;
import com.maddyhome.idea.vim.helper.TestInputModel; import com.maddyhome.idea.vim.helper.TestInputModel;
import com.maddyhome.idea.vim.newapi.IjExecutionContext; import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimEditor; import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel; import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceImpl;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -62,7 +63,7 @@ public abstract class JavaVimTestCase extends JavaCodeInsightFixtureTestCase {
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
ExEntryPanel.getInstance().deactivate(false); ExEntryPanel.getInstance().deactivate(false);
VimPlugin.getVariableService().clear(); ((VimVariableServiceImpl) VimPlugin.getVariableService()).clear();
Timer swingTimer = VimVisualTimer.INSTANCE.getSwingTimer(); Timer swingTimer = VimVisualTimer.INSTANCE.getSwingTimer();
if (swingTimer != null) { if (swingTimer != null) {
swingTimer.stop(); 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.RegisterActions.VIM_ACTIONS_EP
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector 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
import com.maddyhome.idea.vim.key.CommandNode import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.handler.ActionBeanClass import com.maddyhome.idea.vim.handler.ActionBeanClass
import junit.framework.TestCase import junit.framework.TestCase
import javax.swing.KeyStroke import javax.swing.KeyStroke

View File

@@ -76,9 +76,9 @@ inline fun waitAndAssert(timeInMillis: Int = 1000, condition: () -> Boolean) {
} }
fun waitAndAssertMode( fun waitAndAssertMode(
fixture: CodeInsightTestFixture, fixture: CodeInsightTestFixture,
mode: VimStateMachine.Mode, mode: VimStateMachine.Mode,
timeInMillis: Int = (VimPlugin.getOptionService().getOptionValue(OptionScope.GLOBAL, OptionConstants.visualdelayName) as VimInt).value + 1000, timeInMillis: Int = (VimPlugin.getOptionService().getOptionValue(OptionScope.GLOBAL, OptionConstants.visualdelayName) as VimInt).value + 1000,
) { ) {
waitAndAssert(timeInMillis) { fixture.editor.editorMode == mode } waitAndAssert(timeInMillis) { fixture.editor.editorMode == mode }
} }

View File

@@ -50,9 +50,9 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.VimShortcutKeyAction import com.maddyhome.idea.vim.action.VimShortcutKeyAction
import com.maddyhome.idea.vim.api.injector 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
import com.maddyhome.idea.vim.command.VimStateMachine.SubMode 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.ExException
import com.maddyhome.idea.vim.ex.ExOutputModel.Companion.getInstance import com.maddyhome.idea.vim.ex.ExOutputModel.Companion.getInstance
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.swingTimer 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.GuicursorChangeListener
import com.maddyhome.idea.vim.helper.RunnableHelper.runWriteCommand import com.maddyhome.idea.vim.helper.RunnableHelper.runWriteCommand
import com.maddyhome.idea.vim.helper.TestInputModel 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.getGuiCursorMode
import com.maddyhome.idea.vim.helper.inBlockSubMode 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.helper.subMode
import com.maddyhome.idea.vim.key.MappingOwner import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.ToKeysMappingInfo import com.maddyhome.idea.vim.key.ToKeysMappingInfo
@@ -77,6 +77,7 @@ 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.VimFuncref
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.parser.errors.IdeavimErrorListener 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.assertj.core.api.Assertions
import org.junit.Assert import org.junit.Assert
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
@@ -136,7 +137,7 @@ abstract class VimTestCase : UsefulTestCase() {
} }
SelectionVimListenerSuppressor.lock().use { myFixture.tearDown() } SelectionVimListenerSuppressor.lock().use { myFixture.tearDown() }
ExEntryPanel.getInstance().deactivate(false) ExEntryPanel.getInstance().deactivate(false)
VimPlugin.getVariableService().clear() (VimPlugin.getVariableService() as VimVariableServiceImpl).clear()
VimFuncref.lambdaCounter = 0 VimFuncref.lambdaCounter = 0
VimFuncref.anonymousCounter = 0 VimFuncref.anonymousCounter = 0
IdeavimErrorListener.testLogger.clear() IdeavimErrorListener.testLogger.clear()
@@ -508,21 +509,21 @@ abstract class VimTestCase : UsefulTestCase() {
} }
fun doTest( fun doTest(
keys: List<String>, keys: List<String>,
before: String, before: String,
after: String, after: String,
modeAfter: VimStateMachine.Mode, modeAfter: VimStateMachine.Mode,
subModeAfter: SubMode, subModeAfter: SubMode,
) { ) {
doTest(keys.joinToString(separator = ""), before, after, modeAfter, subModeAfter) doTest(keys.joinToString(separator = ""), before, after, modeAfter, subModeAfter)
} }
fun doTest( fun doTest(
keys: String, keys: String,
before: String, before: String,
after: String, after: String,
modeAfter: VimStateMachine.Mode, modeAfter: VimStateMachine.Mode,
subModeAfter: SubMode, subModeAfter: SubMode,
) { ) {
configureByText(before) configureByText(before)
@@ -532,12 +533,12 @@ abstract class VimTestCase : UsefulTestCase() {
} }
fun doTest( fun doTest(
keys: String, keys: String,
before: String, before: String,
after: String, after: String,
modeAfter: VimStateMachine.Mode, modeAfter: VimStateMachine.Mode,
subModeAfter: SubMode, subModeAfter: SubMode,
fileType: FileType, fileType: FileType,
) { ) {
configureByText(fileType, before) configureByText(fileType, before)
@@ -550,12 +551,12 @@ abstract class VimTestCase : UsefulTestCase() {
} }
fun doTest( fun doTest(
keys: String, keys: String,
before: String, before: String,
after: String, after: String,
modeAfter: VimStateMachine.Mode, modeAfter: VimStateMachine.Mode,
subModeAfter: SubMode, subModeAfter: SubMode,
fileName: String, fileName: String,
) { ) {
configureByText(fileName, before) configureByText(fileName, before)
@@ -576,12 +577,12 @@ abstract class VimTestCase : UsefulTestCase() {
} }
fun doTest( fun doTest(
keys: List<KeyStroke>, keys: List<KeyStroke>,
before: String, before: String,
after: String?, after: String?,
modeAfter: VimStateMachine.Mode, modeAfter: VimStateMachine.Mode,
subModeAfter: SubMode, subModeAfter: SubMode,
afterEditorInitialized: (Editor) -> Unit, afterEditorInitialized: (Editor) -> Unit,
) { ) {
configureByText(before) configureByText(before)
afterEditorInitialized(myFixture.editor) afterEditorInitialized(myFixture.editor)

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.VimPlugin
import com.maddyhome.idea.vim.api.injector 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
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.key.MappingOwner import com.maddyhome.idea.vim.key.MappingOwner
import junit.framework.TestCase import junit.framework.TestCase
import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.SkipNeovimReason

View File

@@ -75,28 +75,6 @@ class UndoActionTest : VimTestCase() {
assertFalse(hasSelection()) assertFalse(hasSelection())
} }
fun `test cursor movements do not require additional undo`() {
val keys = listOf("a1<Esc>ea2<Esc>ea3<Esc>", "uu")
val before = """
A Discovery
${c}I found it in a legendary land
all rocks and lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
val after = """
A Discovery
I1 found$c it in a legendary land
all rocks and lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE)
assertFalse(hasSelection())
}
private fun hasSelection(): Boolean { private fun hasSelection(): Boolean {
val editor = myFixture.editor val editor = myFixture.editor
return editor.caretModel.primaryCaret.hasSelection() return editor.caretModel.primaryCaret.hasSelection()

View File

@@ -20,8 +20,8 @@ package org.jetbrains.plugins.ideavim.action.copy
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase

View File

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

View File

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

View File

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

View File

@@ -221,9 +221,11 @@ class MultipleCaretsTest : VimTestCase() {
val after = """qwe val after = """qwe
|rty |rty
|${c}rty |${c}rty
|fgh
|asd |asd
|fgh |fgh
|${c}fgh |${c}rty
|fgh
|zxc |zxc
|vbn |vbn
""".trimMargin() """.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.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector 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
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.Alias import com.maddyhome.idea.vim.extension.Alias
import com.maddyhome.idea.vim.extension.ExtensionBeanClass 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.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing 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.extension.VimExtensionRegistrar
import com.maddyhome.idea.vim.group.MotionGroup import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.isEndAllowed 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.VimPlugin
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.register.RegisterConstants.UNNAMED_REGISTER import com.maddyhome.idea.vim.register.RegisterConstants.UNNAMED_REGISTER
@@ -367,7 +367,9 @@ class ReplaceWithRegisterTest : VimTestCase() {
I found it in a legendary land I found it in a legendary land
where it was settled on some sodden sand where it was settled on some sodden sand
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() """.trimIndent()
) )
} }

View File

@@ -541,32 +541,4 @@ class VimSurroundExtensionTest : VimTestCase() {
val keys = ":map gw ds)<CR>" + "qqgwqj@q" val keys = ":map gw ds)<CR>" + "qqgwqj@q"
doTest(keys, before, after, VimStateMachine.Mode.COMMAND, VimStateMachine.SubMode.NONE) 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.openapi.editor.Editor
import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.PlatformTestUtil
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.key.CommandNode import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.helper.vimStateMachine import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim 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.VimStateMachine.Companion.getInstance
import com.maddyhome.idea.vim.command.MappingState import com.maddyhome.idea.vim.command.MappingState
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.key.CommandNode import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.CurrentCommandState import com.maddyhome.idea.vim.common.CurrentCommandState
import com.maddyhome.idea.vim.common.DigraphResult import com.maddyhome.idea.vim.common.DigraphResult
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.key.Node import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.argumentCaptured import com.maddyhome.idea.vim.common.argumentCaptured
import com.maddyhome.idea.vim.diagnostic.VimLogger import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.diagnostic.debug import com.maddyhome.idea.vim.diagnostic.debug

View File

@@ -17,6 +17,7 @@
*/ */
package com.maddyhome.idea.vim.action.change.change package com.maddyhome.idea.vim.action.change.change
import com.maddyhome.idea.vim.action.copy.YankMotionAction
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
@@ -34,6 +35,19 @@ class ChangeMotionAction : ChangeEditorActionHandler.ForEachCaret(), DuplicableO
override val duplicateWith: Char = 'c' override val duplicateWith: Char = 'c'
private var isMultiCaret = false
override fun baseExecute(
editor: VimEditor,
caret: VimCaret,
context: ExecutionContext,
cmd: Command,
operatorArguments: OperatorArguments
): Boolean {
isMultiCaret = YankMotionAction().yankIfMultiCaret(cmd, editor, context, operatorArguments)
return super.baseExecute(editor, caret, context, cmd, operatorArguments)
}
override fun execute( override fun execute(
editor: VimEditor, editor: VimEditor,
caret: VimCaret, caret: VimCaret,
@@ -46,7 +60,8 @@ class ChangeMotionAction : ChangeEditorActionHandler.ForEachCaret(), DuplicableO
caret, caret,
context, context,
argument, argument,
operatorArguments operatorArguments,
noYank = isMultiCaret
) )
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package com.maddyhome.idea.vim.action.change.change package com.maddyhome.idea.vim.action.change.change
import com.maddyhome.idea.vim.action.copy.YankVisualAction
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
@@ -37,6 +38,18 @@ class ChangeVisualAction : VisualOperatorActionHandler.ForEachCaret() {
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_MULTIKEY_UNDO, CommandFlags.FLAG_EXIT_VISUAL) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_MULTIKEY_UNDO, CommandFlags.FLAG_EXIT_VISUAL)
private var isMultiCaret = false
override fun beforeExecution(
editor: VimEditor,
context: ExecutionContext,
cmd: Command,
caretsAndSelections: Map<VimCaret, VimSelection>
): Boolean {
isMultiCaret = YankVisualAction().yankIfMultiCaret(editor, caretsAndSelections)
return super.beforeExecution(editor, context, cmd, caretsAndSelections)
}
override fun executeAction( override fun executeAction(
editor: VimEditor, editor: VimEditor,
caret: VimCaret, caret: VimCaret,
@@ -50,7 +63,8 @@ class ChangeVisualAction : VisualOperatorActionHandler.ForEachCaret() {
caret, caret,
range.toVimTextRange(false), range.toVimTextRange(false),
range.type, range.type,
context context,
noYank = isMultiCaret
) )
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package com.maddyhome.idea.vim.action.change.delete package com.maddyhome.idea.vim.action.change.delete
import com.maddyhome.idea.vim.action.copy.YankMotionAction
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
@@ -36,6 +37,19 @@ class DeleteMotionAction : ChangeEditorActionHandler.ForEachCaret(), DuplicableO
override val duplicateWith: Char = 'd' override val duplicateWith: Char = 'd'
private var isMultiCaret = false
override fun baseExecute(
editor: VimEditor,
caret: VimCaret,
context: ExecutionContext,
cmd: Command,
operatorArguments: OperatorArguments
): Boolean {
isMultiCaret = YankMotionAction().yankIfMultiCaret(cmd, editor, context, operatorArguments)
return super.baseExecute(editor, caret, context, cmd, operatorArguments)
}
override fun execute( override fun execute(
editor: VimEditor, editor: VimEditor,
caret: VimCaret, caret: VimCaret,
@@ -53,7 +67,7 @@ class DeleteMotionAction : ChangeEditorActionHandler.ForEachCaret(), DuplicableO
val (first, second) = injector.changeGroup val (first, second) = injector.changeGroup
.getDeleteRangeAndType(editor, caret, context, argument, false, operatorArguments) .getDeleteRangeAndType(editor, caret, context, argument, false, operatorArguments)
?: return false ?: return false
return injector.changeGroup.deleteRange(editor, caret, first, second, false) return injector.changeGroup.deleteRange(editor, caret, first, second, false, noYank = isMultiCaret)
} }
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package com.maddyhome.idea.vim.action.change.delete package com.maddyhome.idea.vim.action.change.delete
import com.maddyhome.idea.vim.action.copy.YankVisualAction
import com.maddyhome.idea.vim.api.ExecutionContext import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
@@ -37,6 +38,18 @@ class DeleteVisualAction : VisualOperatorActionHandler.ForEachCaret() {
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_EXIT_VISUAL) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_EXIT_VISUAL)
private var isMultiCaret = false
override fun beforeExecution(
editor: VimEditor,
context: ExecutionContext,
cmd: Command,
caretsAndSelections: Map<VimCaret, VimSelection>,
): Boolean {
isMultiCaret = YankVisualAction().yankIfMultiCaret(editor, caretsAndSelections)
return super.beforeExecution(editor, context, cmd, caretsAndSelections)
}
override fun executeAction( override fun executeAction(
editor: VimEditor, editor: VimEditor,
caret: VimCaret, caret: VimCaret,
@@ -45,7 +58,13 @@ class DeleteVisualAction : VisualOperatorActionHandler.ForEachCaret() {
range: VimSelection, range: VimSelection,
operatorArguments: OperatorArguments, operatorArguments: OperatorArguments,
): Boolean { ): Boolean {
val selectionType = range.type return injector.changeGroup.deleteRange(
return injector.changeGroup.deleteRange(editor, caret, range.toVimTextRange(false), selectionType, false) editor,
caret,
range.toVimTextRange(false),
range.type,
false,
noYank = isMultiCaret
)
} }
} }

View File

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

View File

@@ -38,8 +38,27 @@ class YankMotionAction : VimActionHandler.SingleExecution(), DuplicableOperatorA
context: ExecutionContext, context: ExecutionContext,
cmd: Command, cmd: Command,
operatorArguments: OperatorArguments, operatorArguments: OperatorArguments,
): Boolean {
return executeYank(cmd, editor, context, operatorArguments)
}
private fun executeYank(
cmd: Command,
editor: VimEditor,
context: ExecutionContext,
operatorArguments: OperatorArguments,
): Boolean { ): Boolean {
val argument = cmd.argument ?: return false val argument = cmd.argument ?: return false
return injector.yank.yankMotion(editor, context, argument, operatorArguments) return injector.yank.yankMotion(editor, context, argument, operatorArguments)
} }
fun yankIfMultiCaret(cmd: Command, editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): Boolean {
if (editor.nativeCarets().size > 1) {
executeYank(cmd, editor, context, operatorArguments)
return true
}
else {
return false
}
}
} }

View File

@@ -44,6 +44,13 @@ class YankVisualAction : VisualOperatorActionHandler.SingleExecution() {
cmd: Command, cmd: Command,
caretsAndSelections: Map<VimCaret, VimSelection>, caretsAndSelections: Map<VimCaret, VimSelection>,
operatorArguments: OperatorArguments, operatorArguments: OperatorArguments,
): Boolean {
return executeYank(editor, caretsAndSelections)
}
private fun executeYank(
editor: VimEditor,
caretsAndSelections: Map<VimCaret, VimSelection>,
): Boolean { ): Boolean {
val selections = caretsAndSelections.values val selections = caretsAndSelections.values
val starts: MutableList<Int> = ArrayList() val starts: MutableList<Int> = ArrayList()
@@ -58,4 +65,14 @@ class YankVisualAction : VisualOperatorActionHandler.SingleExecution() {
val endsArray = ends.toIntArray() val endsArray = ends.toIntArray()
return injector.yank.yankRange(editor, TextRange(startsArray, endsArray), vimSelection.type, true) return injector.yank.yankRange(editor, TextRange(startsArray, endsArray), vimSelection.type, true)
} }
fun yankIfMultiCaret(editor: VimEditor, caretsAndSelections: Map<VimCaret, VimSelection>): Boolean {
if (caretsAndSelections.size > 1) {
executeYank(editor, caretsAndSelections)
return true
}
else {
return false
}
}
} }

View File

@@ -1,17 +1,12 @@
package com.maddyhome.idea.vim.api 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.EditorLine
import com.maddyhome.idea.vim.common.LiveRange import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset 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.group.visual.VisualChange
import com.maddyhome.idea.vim.register.Register
import javax.swing.KeyStroke
// TODO: 29.12.2021 Split interface to mutable and immutable // TODO: 29.12.2021 Split interface to mutable and immutable
interface VimCaret { interface VimCaret {
val registerStorage: CaretRegisterStorage
val editor: VimEditor val editor: VimEditor
val offset: Offset val offset: Offset
var vimLastColumn: Int var vimLastColumn: Int
@@ -40,20 +35,4 @@ interface VimCaret {
fun moveToVisualPosition(position: VimVisualPosition) fun moveToVisualPosition(position: VimVisualPosition)
fun setNativeSelection(start: Offset, end: Offset) fun setNativeSelection(start: Offset, end: Offset)
fun removeNativeSelection() 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

@@ -1,56 +0,0 @@
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,14 +83,14 @@ interface VimChangeGroup {
fun getDeleteRangeAndType2(editor: VimEditor, caret: VimCaret, context: ExecutionContext, argument: Argument, isChange: Boolean, operatorArguments: OperatorArguments): Pair<TextRange, SelectionType>? fun getDeleteRangeAndType2(editor: VimEditor, caret: VimCaret, context: ExecutionContext, argument: Argument, isChange: Boolean, operatorArguments: OperatorArguments): Pair<TextRange, SelectionType>?
fun deleteRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType?, isChange: Boolean): Boolean fun deleteRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType?, isChange: Boolean, noYank: Boolean = false): Boolean
fun deleteRange2(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType): Boolean fun deleteRange2(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType): Boolean
fun changeCharacters(editor: VimEditor, caret: VimCaret, count: Int): Boolean fun changeCharacters(editor: VimEditor, caret: VimCaret, count: Int): Boolean
fun changeEndOfLine(editor: VimEditor, caret: VimCaret, count: Int): Boolean fun changeEndOfLine(editor: VimEditor, caret: VimCaret, count: Int): Boolean
fun changeMotion(editor: VimEditor, caret: VimCaret, context: ExecutionContext, argument: Argument, operatorArguments: OperatorArguments): Boolean fun changeMotion(editor: VimEditor, caret: VimCaret, context: ExecutionContext, argument: Argument, operatorArguments: OperatorArguments, noYank: Boolean = false): Boolean
fun changeCaseToggleCharacter(editor: VimEditor, caret: VimCaret, count: Int): Boolean fun changeCaseToggleCharacter(editor: VimEditor, caret: VimCaret, count: Int): Boolean
@@ -98,7 +98,7 @@ interface VimChangeGroup {
fun changeCaseRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: Char): Boolean fun changeCaseRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: Char): Boolean
fun changeRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType, context: ExecutionContext?): Boolean fun changeRange(editor: VimEditor, caret: VimCaret, range: TextRange, type: SelectionType, context: ExecutionContext?, noYank: Boolean = false): Boolean
fun changeCaseMotion(editor: VimEditor, caret: VimCaret, context: ExecutionContext?, type: Char, argument: Argument, operatorArguments: OperatorArguments): Boolean fun changeCaseMotion(editor: VimEditor, caret: VimCaret, context: ExecutionContext?, type: Char, argument: Argument, operatorArguments: OperatorArguments): Boolean

View File

@@ -4,10 +4,10 @@ import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.command.Argument import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.VimStateMachine.Companion.getInstance
import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.VimStateMachine.Companion.getInstance
import com.maddyhome.idea.vim.common.ChangesListener import com.maddyhome.idea.vim.common.ChangesListener
import com.maddyhome.idea.vim.common.Offset import com.maddyhome.idea.vim.common.Offset
import com.maddyhome.idea.vim.common.OperatedRange import com.maddyhome.idea.vim.common.OperatedRange
@@ -17,10 +17,10 @@ import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.group.visual.VimSelection import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.helper.inInsertMode import com.maddyhome.idea.vim.helper.inInsertMode
import com.maddyhome.idea.vim.helper.inSingleCommandMode import com.maddyhome.idea.vim.helper.inSingleCommandMode
import com.maddyhome.idea.vim.helper.usesVirtualSpace import com.maddyhome.idea.vim.helper.usesVirtualSpace
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_END import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_END
import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS
@@ -83,7 +83,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
override fun deleteCharacter(editor: VimEditor, caret: VimCaret, count: Int, isChange: Boolean): Boolean { override fun deleteCharacter(editor: VimEditor, caret: VimCaret, count: Int, isChange: Boolean): Boolean {
val endOffset = injector.motion.getOffsetOfHorizontalMotion(editor, caret, count, true) val endOffset = injector.motion.getOffsetOfHorizontalMotion(editor, caret, count, true)
if (endOffset != -1) { if (endOffset != -1) {
val res = deleteText(editor, TextRange(caret.offset.point, endOffset), SelectionType.CHARACTER_WISE, caret) val res = deleteText(editor, TextRange(caret.offset.point, endOffset), SelectionType.CHARACTER_WISE)
val pos = caret.offset.point val pos = caret.offset.point
val norm = injector.engineEditorHelper.normalizeOffset(editor, caret.getLogicalPosition().line, pos, isChange) val norm = injector.engineEditorHelper.normalizeOffset(editor, caret.getLogicalPosition().line, pos, isChange)
if (norm != pos || if (norm != pos ||
@@ -132,7 +132,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
editor: VimEditor, editor: VimEditor,
range: TextRange, range: TextRange,
type: SelectionType?, type: SelectionType?,
caret: VimCaret, noYank: Boolean = false
): Boolean { ): Boolean {
var updatedRange = range var updatedRange = range
// Fix for https://youtrack.jetbrains.net/issue/VIM-35 // Fix for https://youtrack.jetbrains.net/issue/VIM-35
@@ -146,7 +146,8 @@ abstract class VimChangeGroupBase : VimChangeGroup {
} }
} }
if (type == null || if (type == null ||
editor.inInsertMode || caret.registerStorage.storeText(editor, updatedRange, type, true) noYank ||
editor.inInsertMode || injector.registerGroup.storeText(editor, updatedRange, type, true)
) { ) {
val startOffsets = updatedRange.startOffsets val startOffsets = updatedRange.startOffsets
val endOffsets = updatedRange.endOffsets val endOffsets = updatedRange.endOffsets
@@ -155,10 +156,8 @@ abstract class VimChangeGroupBase : VimChangeGroup {
} }
if (type != null) { if (type != null) {
val start = updatedRange.startOffset val start = updatedRange.startOffset
if (editor.primaryCaret() == caret) { injector.markGroup.setMark(editor, MARK_CHANGE_POS, start)
injector.markGroup.setMark(editor, MARK_CHANGE_POS, start) injector.markGroup.setChangeMarks(editor, TextRange(start, start + 1))
injector.markGroup.setChangeMarks(editor, TextRange(start, start + 1))
}
} }
return true return true
} }
@@ -634,7 +633,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
val rangeToDelete = TextRange(startOffset, offset) val rangeToDelete = TextRange(startOffset, offset)
editor.nativeCarets().filter { it != caret && rangeToDelete.contains(it.offset.point) } editor.nativeCarets().filter { it != caret && rangeToDelete.contains(it.offset.point) }
.forEach { editor.removeCaret(it) } .forEach { editor.removeCaret(it) }
val res = deleteText(editor, rangeToDelete, SelectionType.CHARACTER_WISE, caret) val res = deleteText(editor, rangeToDelete, SelectionType.CHARACTER_WISE)
if (usesVirtualSpace) { if (usesVirtualSpace) {
injector.motion.moveCaret(editor, caret, startOffset) injector.motion.moveCaret(editor, caret, startOffset)
} else { } else {
@@ -729,7 +728,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
logger.debug("offset=$offset") logger.debug("offset=$offset")
} }
if (offset != -1) { if (offset != -1) {
val res = deleteText(editor, TextRange(start, offset), SelectionType.LINE_WISE, caret) val res = deleteText(editor, TextRange(start, offset), SelectionType.LINE_WISE)
if (res && caret.offset.point >= editor.fileSize() && caret.offset.point != 0) { if (res && caret.offset.point >= editor.fileSize() && caret.offset.point != 0) {
injector.motion.moveCaret( injector.motion.moveCaret(
editor, caret, injector.motion.moveCaretToLineStartSkipLeadingOffset( editor, caret, injector.motion.moveCaretToLineStartSkipLeadingOffset(
@@ -854,12 +853,13 @@ abstract class VimChangeGroupBase : VimChangeGroup {
range: TextRange, range: TextRange,
type: SelectionType?, type: SelectionType?,
isChange: Boolean, isChange: Boolean,
noYank: Boolean
): Boolean { ): Boolean {
// Update the last column before we delete, or we might be retrieving the data for a line that no longer exists // 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 caret.vimLastColumn = caret.inlayAwareVisualColumn
val removeLastNewLine = removeLastNewLine(editor, range, type) val removeLastNewLine = removeLastNewLine(editor, range, type)
val res = deleteText(editor, range, type, caret) val res = deleteText(editor, range, type)
if (removeLastNewLine) { if (removeLastNewLine) {
val textLength = editor.fileSize().toInt() val textLength = editor.fileSize().toInt()
editor.deleteString(TextRange(textLength - 1, textLength)) editor.deleteString(TextRange(textLength - 1, textLength))
@@ -978,7 +978,7 @@ abstract class VimChangeGroupBase : VimChangeGroup {
} else { } else {
injector.motion.moveCaretToLineStart(editor, caret.getLogicalPosition().line + 1) injector.motion.moveCaretToLineStart(editor, caret.getLogicalPosition().line + 1)
} }
deleteText(editor, TextRange(caret.offset.point, offset), null, caret) deleteText(editor, TextRange(caret.offset.point, offset), null)
if (spaces && !hasTrailingWhitespace) { if (spaces && !hasTrailingWhitespace) {
insertText(editor, caret, " ") insertText(editor, caret, " ")
injector.motion.moveCaret( 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.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.vimscript.services.OptionService import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.put.VimPut import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.undo.VimUndoRedo import com.maddyhome.idea.vim.undo.VimUndoRedo
import com.maddyhome.idea.vim.vimscript.services.VariableService import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.yank.VimYankGroup import com.maddyhome.idea.vim.yank.VimYankGroup
interface VimInjector { interface VimInjector {
@@ -117,7 +117,7 @@ interface VimInjector {
// Can't be fully moved to vim-engine. // Can't be fully moved to vim-engine.
val vimscriptParser: VimscriptParser val vimscriptParser: VimscriptParser
// !! in progress // !! in progress
val variableService: VariableService val variableService: VimVariableService
// !! in progress // !! in progress
val functionService: VimscriptFunctionService val functionService: VimscriptFunctionService
// Can't be fully moved to vim-engine. // 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.VimMachine
import com.maddyhome.idea.vim.common.VimMachineBase import com.maddyhome.idea.vim.common.VimMachineBase
import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.diagnostic.vimLogger
import com.maddyhome.idea.vim.vimscript.services.OptionService import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.register.VimRegisterGroup import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.register.VimRegisterGroupBase import com.maddyhome.idea.vim.register.VimRegisterGroupBase
import com.maddyhome.idea.vim.vimscript.services.VariableService import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceBase import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceBase
abstract class VimInjectorBase : VimInjector { abstract class VimInjectorBase : VimInjector {
@@ -23,7 +23,7 @@ abstract class VimInjectorBase : VimInjector {
override val parser: VimStringParser = object : VimStringParserBase() {} override val parser: VimStringParser = object : VimStringParserBase() {}
override val vimMachine: VimMachine = object : VimMachineBase() {} override val vimMachine: VimMachine = object : VimMachineBase() {}
override val optionService: OptionService by lazy { object : VimOptionServiceBase(){} } override val optionService: OptionService by lazy { object : VimOptionServiceBase(){} }
override val variableService: VariableService by lazy { object : VimVariableServiceBase(){} } override val variableService: VimVariableService by lazy { object : VimVariableServiceBase(){} }
override val registerGroup: VimRegisterGroup by lazy { registerGroupStub } override val registerGroup: VimRegisterGroup by lazy { registerGroupStub }
override val registerGroupIfCreated: VimRegisterGroup? by lazy { registerGroupStub } override val registerGroupIfCreated: VimRegisterGroup? by lazy { registerGroupStub }

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,58 +25,54 @@ import java.util.*
* COMPATIBILITY-LAYER: Do not move this class to a different package * COMPATIBILITY-LAYER: Do not move this class to a different package
*/ */
enum class MappingMode { enum class MappingMode {
/** /**
* Indicates this key mapping applies to Normal mode * Indicates this key mapping applies to Normal mode
*/ */
NORMAL, NORMAL,
/** /**
* Indicates this key mapping applies to Visual mode * Indicates this key mapping applies to Visual mode
*/ */
VISUAL, VISUAL,
/** /**
* Indicates this key mapping applies to Select mode * Indicates this key mapping applies to Select mode
*/ */
SELECT, SELECT,
/** /**
* Indicates this key mapping applies to Operator Pending mode * Indicates this key mapping applies to Operator Pending mode
*/ */
OP_PENDING, OP_PENDING,
/** /**
* Indicates this key mapping applies to Insert mode * Indicates this key mapping applies to Insert mode
*/ */
INSERT, INSERT,
/** /**
* Indicates this key mapping applies to Command Line mode * Indicates this key mapping applies to Command Line mode
*/ */
CMD_LINE; CMD_LINE;
companion object { companion object {
@JvmField @JvmField
val N: EnumSet<MappingMode> = EnumSet.of(NORMAL) val N: EnumSet<MappingMode> = EnumSet.of(NORMAL)
val X: EnumSet<MappingMode> = EnumSet.of(VISUAL) val X: EnumSet<MappingMode> = EnumSet.of(VISUAL)
val O: EnumSet<MappingMode> = EnumSet.of(OP_PENDING) val O: EnumSet<MappingMode> = EnumSet.of(OP_PENDING)
val I: EnumSet<MappingMode> = EnumSet.of(INSERT) val I: EnumSet<MappingMode> = EnumSet.of(INSERT)
val C: EnumSet<MappingMode> = EnumSet.of(CMD_LINE) val C: EnumSet<MappingMode> = EnumSet.of(CMD_LINE)
val S: EnumSet<MappingMode> = EnumSet.of(SELECT) val S: EnumSet<MappingMode> = EnumSet.of(SELECT)
val V: EnumSet<MappingMode> = EnumSet.of(VISUAL, SELECT) val V: EnumSet<MappingMode> = EnumSet.of(VISUAL, SELECT)
val NO: EnumSet<MappingMode> = EnumSet.of(NORMAL, OP_PENDING) val NO: EnumSet<MappingMode> = EnumSet.of(NORMAL, OP_PENDING)
@JvmField
@JvmField val XO: EnumSet<MappingMode> = EnumSet.of(VISUAL, OP_PENDING)
val XO: EnumSet<MappingMode> = EnumSet.of(VISUAL, OP_PENDING) val NX: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL)
val NX: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL) val IC: EnumSet<MappingMode> = EnumSet.of(INSERT, CMD_LINE)
val IC: EnumSet<MappingMode> = EnumSet.of(INSERT, CMD_LINE) val NV: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, SELECT)
val NV: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, SELECT) val NXO: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, OP_PENDING)
@JvmField
@JvmField val NVO: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, OP_PENDING, SELECT)
val NXO: EnumSet<MappingMode> = EnumSet.of(NORMAL, VISUAL, OP_PENDING) val ALL: EnumSet<MappingMode> = EnumSet.allOf(MappingMode::class.java)
}
@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.VimActionsInitiator
import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.key.CommandPartNode import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.DigraphResult import com.maddyhome.idea.vim.common.DigraphResult
import com.maddyhome.idea.vim.common.DigraphSequence import com.maddyhome.idea.vim.common.DigraphSequence
import com.maddyhome.idea.vim.diagnostic.debug import com.maddyhome.idea.vim.diagnostic.debug

View File

@@ -16,14 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.maddyhome.idea.vim.key package com.maddyhome.idea.vim.common
import javax.swing.KeyStroke 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.), * 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`). * or a part of a command (e.g. `g` for `gg`).

View File

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

View File

@@ -66,7 +66,7 @@ sealed class ChangeEditorActionHandler : EditorActionHandlerBase(false) {
): Boolean ): Boolean
} }
final override fun baseExecute( override fun baseExecute(
editor: VimEditor, editor: VimEditor,
caret: VimCaret, caret: VimCaret,
context: ExecutionContext, context: ExecutionContext,

View File

@@ -1,42 +0,0 @@
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,15 +37,4 @@ class ToggleOption(name: String, abbrev: String, defaultValue: VimInt) : Option<
fun isSet(): Boolean { fun isSet(): Boolean {
return injector.optionService.getOptionValue(OptionScope.GLOBAL, name).asBoolean() 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,7 +20,9 @@ package com.maddyhome.idea.vim.options
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType 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.VimString
import com.maddyhome.idea.vim.vimscript.model.datatypes.parseNumber
import java.util.* import java.util.*
/** /**
@@ -57,13 +59,6 @@ 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 // todo 1.9 should return Result with exceptions
abstract fun checkIfValueValid(value: VimDataType, token: String) abstract fun checkIfValueValid(value: VimDataType, token: String)
@@ -72,6 +67,31 @@ import java.util.*
abstract fun getValueIfRemove(currentValue: VimDataType, value: String, token: String): T 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) { 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) constructor(name: String, abbrev: String, defaultValue: String, isList: Boolean = false, boundedValues: Collection<String>? = null) : this(name, abbrev, VimString(defaultValue), isList, boundedValues)

View File

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

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

View File

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

View File

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

View File

@@ -26,11 +26,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
interface VimVariableService {
/**
* COMPATIBILITY-LAYER: Renamed from VimVariableService
*/
interface VariableService {
/** /**
* Stores variable. * 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.FunctionDeclaration
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
abstract class VimVariableServiceBase : VariableService { abstract class VimVariableServiceBase : VimVariableService {
private var globalVariables: MutableMap<String, VimDataType> = mutableMapOf() private var globalVariables: MutableMap<String, VimDataType> = mutableMapOf()
private val windowVariablesKey = Key<MutableMap<String, VimDataType>>("TabVariables") private val windowVariablesKey = Key<MutableMap<String, VimDataType>>("TabVariables")
private val bufferVariablesKey = Key<MutableMap<String, VimDataType>>("BufferVariables") private val bufferVariablesKey = Key<MutableMap<String, VimDataType>>("BufferVariables")