1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-07-26 17:59:02 +02:00

Move some base classes to vim-engine

This commit is contained in:
Alex Plate 2022-03-22 15:44:33 +03:00
parent 96dc9af1e3
commit db87b51784
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F
54 changed files with 327 additions and 245 deletions

View File

@ -19,6 +19,7 @@ package com.maddyhome.idea.vim
import com.maddyhome.idea.vim.action.change.VimRepeater.Extension.argumentCaptured
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
@ -43,7 +44,6 @@ import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.helper.inSingleNormalMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.key.KeyMappingLayer
import com.maddyhome.idea.vim.newapi.VimActionsInitiator
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.injector
import com.maddyhome.idea.vim.newapi.vimLogger

View File

@ -37,6 +37,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.SystemInfo;
import com.maddyhome.idea.vim.api.VimInjectorBaseKt;
import com.maddyhome.idea.vim.api.VimKeyGroup;
import com.maddyhome.idea.vim.config.VimState;
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar;
@ -153,7 +154,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
}
public static @NotNull MarkGroup getMark() {
return ApplicationManager.getApplication().getService(MarkGroup.class);
return ((MarkGroup)VimInjectorBaseKt.getInjectorBase().getMarkGroup());
}
public static @NotNull RegisterGroup getRegister() {

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ package com.maddyhome.idea.vim.action.change.change
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -22,7 +22,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags

View File

@ -22,7 +22,7 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags

View File

@ -20,7 +20,7 @@ package com.maddyhome.idea.vim.action.copy
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.DuplicableOperatorAction
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments

View File

@ -826,7 +826,7 @@ public class ChangeGroup implements VimChangeGroup {
.forEach(c -> editor.getCaretModel().removeCaret(c));
boolean res = deleteText(editor, rangeToDelete, SelectionType.CHARACTER_WISE);
if (CommandStateHelper.getUsesVirtualSpace()) {
if (EngineHelperKt.getUsesVirtualSpace()) {
MotionGroup.moveCaret(editor, caret, startOffset);
}
else {
@ -1666,7 +1666,7 @@ public class ChangeGroup implements VimChangeGroup {
MotionGroup.getMotionRange(editor, caret, context, argument, operatorArguments);
if (range != null) {
autoIndentRange(editor, caret, context,
new TextRange(range.getStartOffset(), HelperKt.getEndOffsetInclusive(range)));
new TextRange(range.getStartOffset(), EngineHelperKt.getEndOffsetInclusive(range)));
}
}

View File

@ -36,6 +36,7 @@ import com.maddyhome.idea.vim.EventFacade;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.action.ComplicatedKeysAction;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.api.VimKeyGroup;
import com.maddyhome.idea.vim.common.*;
import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
@ -44,7 +45,7 @@ import com.maddyhome.idea.vim.helper.HelperKt;
import com.maddyhome.idea.vim.helper.StringHelper;
import com.maddyhome.idea.vim.key.*;
import com.maddyhome.idea.vim.newapi.IjVimActionsInitiator;
import com.maddyhome.idea.vim.newapi.VimActionsInitiator;
import com.maddyhome.idea.vim.api.VimActionsInitiator;
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression;
import kotlin.Pair;
import kotlin.text.StringsKt;

View File

@ -40,6 +40,8 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimMarkGroup;
import com.maddyhome.idea.vim.command.Command;
import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.common.*;
@ -63,7 +65,7 @@ import java.util.stream.Collectors;
@State(name = "VimMarksSettings", storages = {
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)
})
public class MarkGroup implements PersistentStateComponent<Element> {
public class MarkGroup implements PersistentStateComponent<Element>, VimMarkGroup {
public static final char MARK_VISUAL_START = '<';
public static final char MARK_VISUAL_END = '>';
public static final char MARK_CHANGE_START = '[';
@ -81,6 +83,11 @@ public class MarkGroup implements PersistentStateComponent<Element> {
*
* @param editor The editor the jump will occur in
*/
@Override
public void saveJumpLocation(@NotNull VimEditor editor) {
saveJumpLocation(((IjVimEditor)editor).getEditor());
}
public void saveJumpLocation(@NotNull Editor editor) {
addJump(editor, true);
setMark(editor, '\'');

View File

@ -22,8 +22,6 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
@ -33,7 +31,6 @@ import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.sort
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
import com.maddyhome.idea.vim.helper.vimLastColumn
@ -135,50 +132,6 @@ val Caret.vimLeadSelectionOffset: Int
return caretOffset
}
fun charToNativeSelection(editor: VimEditor, start: Int, end: Int, mode: CommandState.Mode): Pair<Int, Int> {
val (nativeStart, nativeEnd) = sort(start, end)
val lineEnd = editor.lineEndForOffset(nativeEnd)
val adj =
if (VimPlugin.getVisualMotion().exclusiveSelection || nativeEnd == lineEnd || mode == CommandState.Mode.SELECT) 0 else 1
val adjEnd = (nativeEnd + adj).coerceAtMost(editor.fileSize().toInt())
return nativeStart to adjEnd
}
/**
* Convert vim's selection start and end to corresponding native selection.
*
* Adds caret adjustment or extends to line start / end in case of linewise selection
*/
fun lineToNativeSelection(editor: VimEditor, start: Int, end: Int): Pair<Int, Int> {
val (nativeStart, nativeEnd) = sort(start, end)
val lineStart = editor.lineStartForOffset(nativeStart)
// Extend to \n char of line to fill full line with selection
val lineEnd = (editor.lineEndForOffset(nativeEnd) + 1).coerceAtMost(editor.fileSize().toInt())
return lineStart to lineEnd
}
fun blockToNativeSelection(
editor: VimEditor,
start: Int,
end: Int,
mode: CommandState.Mode,
): Pair<VimLogicalPosition, VimLogicalPosition> {
var blockStart = editor.offsetToLogicalPosition(start)
var blockEnd = editor.offsetToLogicalPosition(end)
if (!VimPlugin.getVisualMotion().exclusiveSelection && mode != CommandState.Mode.SELECT) {
if (blockStart.column > blockEnd.column) {
if (blockStart.column < editor.lineLength(blockStart.line)) {
blockStart = VimLogicalPosition(blockStart.line, blockStart.column + 1)
}
} else {
if (blockEnd.column < editor.lineLength(blockEnd.line)) {
blockEnd = VimLogicalPosition(blockEnd.line, blockEnd.column + 1)
}
}
}
return blockStart to blockEnd
}
fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: CommandState.Mode) {
if (predictedMode != CommandState.Mode.VISUAL) {
if (!predictedMode.isEndAllowed) {

View File

@ -26,6 +26,7 @@ import com.intellij.openapi.editor.ScrollType
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimVisualMotionGroup
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange

View File

@ -29,23 +29,6 @@ import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@get:VimNlsSafe
val usesVirtualSpace
get() = (VimPlugin.getOptionService().getOptionValue(OptionScope.GLOBAL, OptionConstants.virtualeditName) as VimString).value == "onemore"
/**
* Please use `isEndAllowed` based on `Editor` (another extension function)
* It takes "single command" into account.
*/
val CommandState.Mode.isEndAllowed: Boolean
get() = when (this) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING -> usesVirtualSpace
CommandState.Mode.INSERT_NORMAL -> usesVirtualSpace
CommandState.Mode.INSERT_VISUAL -> usesVirtualSpace
CommandState.Mode.INSERT_SELECT -> usesVirtualSpace
}
val Editor.isEndAllowed: Boolean
get() = when (this.mode) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT, CommandState.Mode.INSERT_VISUAL, CommandState.Mode.INSERT_SELECT -> true
@ -76,21 +59,12 @@ val CommandState.Mode.hasVisualSelection
val Editor.mode
get() = this.vim.commandState.mode
val VimEditor.mode
get() = this.commandState.mode
var Editor.subMode
get() = this.vim.commandState.subMode
set(value) {
this.vim.commandState.subMode = value
}
var VimEditor.subMode
get() = this.commandState.subMode
set(value) {
this.commandState.subMode = value
}
@get:JvmName("inNormalMode")
val Editor.inNormalMode
get() = this.mode.inNormalMode
@ -111,9 +85,6 @@ val Editor.inRepeatMode
val Editor.inVisualMode
get() = this.mode.inVisualMode
val VimEditor.inVisualMode
get() = this.mode.inVisualMode
@get:JvmName("inVisualMode")
val CommandState.Mode.inVisualMode
get() = this == CommandState.Mode.VISUAL || this == CommandState.Mode.INSERT_VISUAL
@ -147,9 +118,6 @@ val CommandState.Mode.inSingleNormalMode: Boolean
else -> false
}
val VimEditor.commandState
get() = CommandState.getInstance(this)
fun CommandState.pushVisualMode(subMode: CommandState.SubMode, prevMode: CommandState.Mode = this.mode) {
if (prevMode.inSingleMode) {
popModes()

View File

@ -29,21 +29,21 @@ internal fun getCaretVisualAttributes(color: Color?, weight: CaretVisualAttribut
}
@Suppress("UNCHECKED_CAST")
internal fun getShape(shape: String): Any {
fun getShape(shape: String): Any {
val shapeClass = CaretVisualAttributes::class.java.classLoader.loadClass("com.intellij.openapi.editor.CaretVisualAttributes\$Shape")
return java.lang.Enum.valueOf(shapeClass as Class<Enum<*>>, shape)
}
internal fun Caret.shape(): Any? {
fun Caret.shape(): Any? {
val method = CaretVisualAttributes::class.java.getMethod("getShape")
return method.invoke(this.visualAttributes)
}
internal fun Caret.thickness(): Any? {
fun Caret.thickness(): Any? {
val method = CaretVisualAttributes::class.java.getMethod("getThickness")
return method.invoke(this.visualAttributes)
}
internal fun buildGreater212(): Boolean {
fun buildGreater212(): Boolean {
return ApplicationInfo.getInstance().build.baselineVersion >= 212
}

View File

@ -28,7 +28,6 @@ import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import java.util.*
@ -161,9 +160,6 @@ annotation class RWLockLabel {
annotation class NoLockRequired
}
val TextRange.endOffsetInclusive
get() = if (this.endOffset > 0 && this.endOffset > this.startOffset) this.endOffset - 1 else this.endOffset
fun vimEnabled(editor: Editor?): Boolean {
if (!VimPlugin.isEnabled()) return false
if (editor != null && editor.isIdeaVimDisabledHere) return false

View File

@ -0,0 +1,13 @@
package com.maddyhome.idea.vim.helper
import com.intellij.openapi.components.Service
import com.maddyhome.idea.vim.api.EngineEditorHelper
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.newapi.IjVimEditor
@Service
class IjEditorHelper : EngineEditorHelper {
override fun normalizeOffset(editor: VimEditor, offset: Int, allowEnd: Boolean): Int {
return EditorHelper.normalizeOffset((editor as IjVimEditor).editor, offset, allowEnd)
}
}

View File

@ -27,13 +27,11 @@ import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.UserDataHolder
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.ui.ExOutputPanel
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@ -59,14 +57,6 @@ var Caret.vimSelectionStart: Int
_vimSelectionStart = value
}
var VimCaret.vimSelectionStart: Int
get() {
return (this as IjVimCaret).caret.vimSelectionStart
}
set(value) {
(this as IjVimCaret).caret.vimSelectionStart = value
}
fun Caret.vimSelectionStartClear() {
this._vimSelectionStart = null
}

View File

@ -0,0 +1,12 @@
package com.maddyhome.idea.vim.newapi
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.handler.ActionBeanClass
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
class IjVimActionsInitiator(val bean: ActionBeanClass) : VimActionsInitiator {
override fun getInstance(): EditorActionHandlerBase = bean.instance
}
val VimActionsInitiator.ij: ActionBeanClass
get() = (this as IjVimActionsInitiator).bean

View File

@ -30,6 +30,7 @@ import com.maddyhome.idea.vim.group.visual.vimSetSelection
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.helper.vimSelectionStart
class IjVimCaret(val caret: Caret) : VimCaret {
override val editor: VimEditor
@ -40,6 +41,13 @@ class IjVimCaret(val caret: Caret) : VimCaret {
get() = caret.vimLastColumn
override val selectionStart: Int
get() = caret.selectionStart
override val selectionEnd: Int
get() = caret.selectionEnd
override var vimSelectionStart: Int
get() = this.caret.vimSelectionStart
set(value) {
this.caret.vimSelectionStart = value
}
override fun moveToOffset(offset: Int) {
// TODO: 17.12.2021 Unpack internal actions

View File

@ -21,9 +21,12 @@ package com.maddyhome.idea.vim.newapi
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.event.CaretEvent
import com.intellij.openapi.editor.event.CaretListener
import com.maddyhome.idea.vim.api.LineDeleteShift
import com.maddyhome.idea.vim.api.MutableLinearEditor
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimCaretListener
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.common.EditorLine
@ -206,6 +209,23 @@ class IjVimEditor(editor: Editor) : MutableLinearEditor() {
return EditorHelper.getLineEndOffset(editor, line, allowEnd)
}
val listenersMap: MutableMap<VimCaretListener, CaretListener> = mutableMapOf()
override fun addCaretListener(listener: VimCaretListener) {
val caretListener = object : CaretListener {
override fun caretRemoved(event: CaretEvent) {
listener.caretRemoved(event.caret?.vim)
}
}
listenersMap[listener] = caretListener
editor.caretModel.addCaretListener(caretListener)
}
override fun removeCaretListener(listener: VimCaretListener) {
val caretListener = listenersMap.remove(listener) ?: error("Existing listener expected")
editor.caretModel.removeCaretListener(caretListener)
}
private fun Pair<Offset, Offset>.noGuard(editor: Editor): Boolean {
return editor.document.getRangeGuard(this.first.point, this.second.point) == null
}

View File

@ -3,22 +3,26 @@ package com.maddyhome.idea.vim.newapi
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceIfCreated
import com.intellij.openapi.diagnostic.Logger
import com.maddyhome.idea.vim.api.EngineEditorHelper
import com.maddyhome.idea.vim.api.ExecutionContextManager
import com.maddyhome.idea.vim.api.VimApplication
import com.maddyhome.idea.vim.api.VimDigraphGroup
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimEnabler
import com.maddyhome.idea.vim.api.VimKeyGroup
import com.maddyhome.idea.vim.api.VimMarkGroup
import com.maddyhome.idea.vim.api.VimMessages
import com.maddyhome.idea.vim.api.VimProcessGroup
import com.maddyhome.idea.vim.api.VimRegisterGroup
import com.maddyhome.idea.vim.api.VimStringParser
import com.maddyhome.idea.vim.api.VimVisualMotionGroup
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.common.VimMachine
import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.group.MarkGroup
import com.maddyhome.idea.vim.group.VimChangeGroup
import com.maddyhome.idea.vim.group.VimKeyGroup
import com.maddyhome.idea.vim.group.visual.VimVisualMotionGroup
import com.maddyhome.idea.vim.helper.IjActionExecutor
import com.maddyhome.idea.vim.helper.IjEditorHelper
import com.maddyhome.idea.vim.helper.IjVimStringParser
import com.maddyhome.idea.vim.helper.VimActionExecutor
import com.maddyhome.idea.vim.helper.vimCommandState
@ -43,6 +47,8 @@ class IjVimInjector : VimInjector {
get() = service()
override val keyGroup: VimKeyGroup
get() = service()
override val markGroup: VimMarkGroup
get() = service<MarkGroup>()
override val application: VimApplication
get() = service<IjVimApplication>()
override val executionContextManager: ExecutionContextManager
@ -69,4 +75,7 @@ class IjVimInjector : VimInjector {
}
return res
}
override val engineEditorHelper: EngineEditorHelper
get() = service<IjEditorHelper>()
}

View File

@ -18,22 +18,14 @@
package com.maddyhome.idea.vim.newapi
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimInjectorBase
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.group.VimChangeGroup
import com.maddyhome.idea.vim.group.VimKeyGroup
import com.maddyhome.idea.vim.group.visual.VimVisualMotionGroup
import com.maddyhome.idea.vim.helper.VimActionExecutor
interface VimInjector : VimInjectorBase {
val actionExecutor: VimActionExecutor
val changeGroup: VimChangeGroup
val keyGroup: VimKeyGroup
val visualMotionGroup: VimVisualMotionGroup
fun commandStateFor(editor: VimEditor): CommandState
}
// We should inject logger here somehow

View File

@ -16,13 +16,13 @@
serviceInterface="com.maddyhome.idea.vim.api.VimDigraphGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.HistoryGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.KeyGroup"
serviceInterface="com.maddyhome.idea.vim.group.VimKeyGroup"/>
serviceInterface="com.maddyhome.idea.vim.api.VimKeyGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.WindowGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.TabServiceImpl"
serviceInterface="com.maddyhome.idea.vim.group.TabService"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.EditorGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.group.visual.VisualMotionGroup"
serviceInterface="com.maddyhome.idea.vim.group.visual.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.PutGroup"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.vimscript.services.VariableServiceImpl"

View File

@ -84,7 +84,6 @@ import com.maddyhome.idea.vim.vimscript.model.options.helpers.GuiCursorType
import com.maddyhome.idea.vim.vimscript.parser.errors.IdeavimErrorListener
import com.maddyhome.idea.vim.vimscript.services.VariableServiceImpl
import org.assertj.core.api.Assertions
import org.jdesktop.swingx.plaf.UIManagerExt.getShape
import org.junit.Assert
import java.awt.event.KeyEvent
import java.util.*

View File

@ -312,7 +312,7 @@ public class KeyHandler {
}
/**
* See the description for {@link com.maddyhome.idea.vim.action.DuplicableOperatorAction}
* See the description for {@link com.maddyhome.idea.vim.command.DuplicableOperatorAction}
*/
private Node mapOpCommand(KeyStroke key, Node node, @NotNull CommandState editorState) {
if (editorState.isDuplicateOperatorKeyStroke(key)) {

View File

@ -0,0 +1,5 @@
package com.maddyhome.idea.vim.api
interface EngineEditorHelper {
fun normalizeOffset(editor: VimEditor, offset: Int, allowEnd: Boolean): Int
}

View File

@ -16,18 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.newapi
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.handler.ActionBeanClass
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
interface VimActionsInitiator {
fun getInstance(): EditorActionHandlerBase
}
class IjVimActionsInitiator(val bean: ActionBeanClass) : VimActionsInitiator {
override fun getInstance(): EditorActionHandlerBase = bean.instance
}
val VimActionsInitiator.ij: ActionBeanClass
get() = (this as IjVimActionsInitiator).bean

View File

@ -9,6 +9,8 @@ interface VimCaret {
val offset: Offset
val vimLastColumn: Int
val selectionStart: Int
val selectionEnd: Int
var vimSelectionStart: Int
fun moveToOffset(offset: Int)
fun offsetForLineStartSkipLeading(line: Int): Int
fun getLine(): EditorLine.Pointer

View File

@ -0,0 +1,5 @@
package com.maddyhome.idea.vim.api
interface VimCaretListener {
fun caretRemoved(caret: VimCaret?)
}

View File

@ -173,6 +173,9 @@ interface VimEditor {
fun vimSetSystemBlockSelectionSilently(start: VimLogicalPosition, end: VimLogicalPosition)
fun getLineEndOffset(line: Int, allowEnd: Boolean): Int
fun addCaretListener(listener: VimCaretListener)
fun removeCaretListener(listener: VimCaretListener)
}
interface MutableVimEditor : VimEditor {

View File

@ -1,5 +1,6 @@
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.common.VimMachine
import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.newapi.NativeActionManager
@ -20,7 +21,12 @@ interface VimInjectorBase {
// TODO We should somehow state that [OptionServiceImpl] can be used from any implementation
val optionService: OptionService
val nativeActionManager: NativeActionManager
val keyGroup: VimKeyGroup
val markGroup: VimMarkGroup
val visualMotionGroup: VimVisualMotionGroup
fun <T : Any> getLogger(clazz: Class<T>): VimLogger
fun commandStateFor(editor: VimEditor): CommandState
val engineEditorHelper: EngineEditorHelper
}
lateinit var injectorBase: VimInjectorBase

View File

@ -15,17 +15,13 @@
* 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.api
package com.maddyhome.idea.vim.group;
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.key.KeyMappingLayer
import com.maddyhome.idea.vim.common.MappingMode;
import com.maddyhome.idea.vim.common.CommandPartNode;
import com.maddyhome.idea.vim.key.KeyMappingLayer;
import com.maddyhome.idea.vim.newapi.VimActionsInitiator;
import org.jetbrains.annotations.NotNull;
public interface VimKeyGroup {
@NotNull CommandPartNode<VimActionsInitiator> getKeyRoot(@NotNull MappingMode mappingMode);
@NotNull KeyMappingLayer getKeyMappingLayer(@NotNull MappingMode mode);
interface VimKeyGroup {
fun getKeyRoot(mappingMode: MappingMode): CommandPartNode<VimActionsInitiator>
fun getKeyMappingLayer(mode: MappingMode): KeyMappingLayer
}

View File

@ -0,0 +1,5 @@
package com.maddyhome.idea.vim.api
interface VimMarkGroup {
fun saveJumpLocation(editor: VimEditor)
}

View File

@ -16,9 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.group.visual
package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.CommandState
interface VimVisualMotionGroup {

View File

@ -1,21 +1,3 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2022 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.command
import com.maddyhome.idea.vim.api.ExecutionContext
@ -31,17 +13,17 @@ import java.util.*
* an argument if appropriate for the command. The command has a count and a type.
*/
data class Command(
var rawCount: Int,
var action: EditorActionHandlerBase,
val type: Type,
var flags: EnumSet<CommandFlags>,
var rawCount: Int,
var action: EditorActionHandlerBase,
val type: Type,
var flags: EnumSet<CommandFlags>,
) {
constructor(rawCount: Int, register: Char) : this(
rawCount,
NonExecutableActionHandler,
Type.SELECT_REGISTER,
EnumSet.of(CommandFlags.FLAG_EXPECT_MORE)
EnumSet.of(CommandFlags.FLAG_EXPECT_MORE)
) {
this.register = register
}

View File

@ -18,18 +18,14 @@
package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.action.DuplicableOperatorAction
import com.maddyhome.idea.vim.action.ResetModeAction
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedDigraphAction
import com.maddyhome.idea.vim.action.change.insert.InsertCompletedLiteralAction
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.CurrentCommandState
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
import com.maddyhome.idea.vim.newapi.VimActionsInitiator
import com.maddyhome.idea.vim.newapi.vimLogger
import org.jetbrains.annotations.TestOnly
import java.util.*
import javax.swing.KeyStroke
@ -139,7 +135,7 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode<VimActi
}
fun isPuttingLiteral(): Boolean {
return !commandParts.isEmpty() && commandParts.last.action is InsertCompletedLiteralAction
return !commandParts.isEmpty() && commandParts.last.action.id == "VimInsertCompletedLiteralAction"
}
fun isDone(): Boolean {
@ -161,7 +157,7 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode<VimActi
}
fun buildCommand(): Command {
if (commandParts.last.action is InsertCompletedDigraphAction || commandParts.last.action is ResetModeAction) {
if (commandParts.last.action.id == "VimInsertCompletedDigraphAction" || commandParts.last.action.id == "VimResetModeAction") {
expectedArgumentType = prevExpectedArgumentType
prevExpectedArgumentType = null
return commandParts.removeLast()
@ -207,6 +203,6 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode<VimActi
fun getCurrentTrie(): CommandPartNode<VimActionsInitiator> = currentCommandPartNode
companion object {
private val LOG = vimLogger<CommandBuilder>()
private val LOG = injectorBase.getLogger(CommandBuilder::class.java)
}
}

View File

@ -17,17 +17,15 @@
*/
package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.api.VimActionsInitiator
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.DigraphResult
import com.maddyhome.idea.vim.common.DigraphSequence
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.diagnostic.debug
import com.maddyhome.idea.vim.common.DigraphSequence
import com.maddyhome.idea.vim.helper.noneOfEnum
import com.maddyhome.idea.vim.newapi.VimActionsInitiator
import com.maddyhome.idea.vim.newapi.injector
import com.maddyhome.idea.vim.newapi.vimLogger
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import org.jetbrains.annotations.Contract
@ -311,7 +309,7 @@ class CommandState(private val editor: VimEditor?) {
injectorBase.messages.showMode(msg.toString())
}
internal fun getStatusString(): String {
fun getStatusString(): String {
val pos = modeStates.size - 1
val modeState = if (pos >= 0) {
modeStates[pos]
@ -381,7 +379,7 @@ class CommandState(private val editor: VimEditor?) {
}
companion object {
private val logger = vimLogger<CommandState>()
private val logger = injectorBase.getLogger(CommandState::class.java)
private val defaultModeState = ModeState(Mode.COMMAND, SubMode.NONE)
private val globalState = CommandState(null)
@ -390,12 +388,12 @@ class CommandState(private val editor: VimEditor?) {
return if (editor == null || injectorBase.optionService.isSet(OptionScope.GLOBAL, OptionConstants.ideaglobalmodeName)) {
globalState
} else {
injector.commandStateFor(editor)
injectorBase.commandStateFor(editor)
}
}
private fun getKeyRootNode(mappingMode: MappingMode): CommandPartNode<VimActionsInitiator> {
return injector.keyGroup.getKeyRoot(mappingMode)
return injectorBase.keyGroup.getKeyRoot(mappingMode)
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.action
package com.maddyhome.idea.vim.command
/**
* There are some double-character commands like `cc`, `dd`, `yy`.

View File

@ -18,10 +18,9 @@
package com.maddyhome.idea.vim.command
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.diagnostic.trace
import com.maddyhome.idea.vim.newapi.injector
import com.maddyhome.idea.vim.newapi.vimLogger
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
@ -35,7 +34,7 @@ class MappingState {
var mappingMode = MappingMode.NORMAL
private val timer = Timer((injector.optionService.getOptionValue(OptionScope.GLOBAL, OptionConstants.timeoutlenName) as VimInt).value, null)
private val timer = Timer((injectorBase.optionService.getOptionValue(OptionScope.GLOBAL, OptionConstants.timeoutlenName) as VimInt).value, null)
private var keyList = mutableListOf<KeyStroke>()
init {
@ -43,7 +42,7 @@ class MappingState {
}
fun startMappingTimer(actionListener: ActionListener) {
timer.initialDelay = (injector.optionService.getOptionValue(OptionScope.GLOBAL, OptionConstants.timeoutlenName) as VimInt).value
timer.initialDelay = (injectorBase.optionService.getOptionValue(OptionScope.GLOBAL, OptionConstants.timeoutlenName) as VimInt).value
timer.actionListeners.forEach { timer.removeActionListener(it) }
timer.addActionListener(actionListener)
timer.start()
@ -73,6 +72,6 @@ class MappingState {
}
companion object {
private val LOG = vimLogger<MappingState>()
private val LOG = injectorBase.getLogger(MappingState::class.java)
}
}

View File

@ -0,0 +1,62 @@
package com.maddyhome.idea.vim.group.visual
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
fun charToNativeSelection(editor: VimEditor, start: Int, end: Int, mode: CommandState.Mode): Pair<Int, Int> {
val (nativeStart, nativeEnd) = sort(start, end)
val lineEnd = editor.lineEndForOffset(nativeEnd)
val adj =
if (isExclusiveSelection() || nativeEnd == lineEnd || mode == CommandState.Mode.SELECT) 0 else 1
val adjEnd = (nativeEnd + adj).coerceAtMost(editor.fileSize().toInt())
return nativeStart to adjEnd
}
/**
* Convert vim's selection start and end to corresponding native selection.
*
* Adds caret adjustment or extends to line start / end in case of linewise selection
*/
fun lineToNativeSelection(editor: VimEditor, start: Int, end: Int): Pair<Int, Int> {
val (nativeStart, nativeEnd) = sort(start, end)
val lineStart = editor.lineStartForOffset(nativeStart)
// Extend to \n char of line to fill full line with selection
val lineEnd = (editor.lineEndForOffset(nativeEnd) + 1).coerceAtMost(editor.fileSize().toInt())
return lineStart to lineEnd
}
fun <T : Comparable<T>> sort(a: T, b: T) = if (a > b) b to a else a to b
private fun isExclusiveSelection(): Boolean {
return (injectorBase.optionService.getOptionValue(
OptionScope.GLOBAL,
OptionConstants.selectionName
) as VimString).value == "exclusive"
}
fun blockToNativeSelection(
editor: VimEditor,
start: Int,
end: Int,
mode: CommandState.Mode,
): Pair<VimLogicalPosition, VimLogicalPosition> {
var blockStart = editor.offsetToLogicalPosition(start)
var blockEnd = editor.offsetToLogicalPosition(end)
if (!isExclusiveSelection() && mode != CommandState.Mode.SELECT) {
if (blockStart.column > blockEnd.column) {
if (blockStart.column < editor.lineLength(blockStart.line)) {
blockStart = VimLogicalPosition(blockStart.line, blockStart.column + 1)
}
} else {
if (blockEnd.column < editor.lineLength(blockEnd.line)) {
blockEnd = VimLogicalPosition(blockEnd.line, blockEnd.column + 1)
}
}
}
return blockStart to blockEnd
}

View File

@ -21,15 +21,13 @@ package com.maddyhome.idea.vim.handler
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.injectorBase
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.helper.StringHelper
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.noneOfEnum
import com.maddyhome.idea.vim.newapi.injector
import com.maddyhome.idea.vim.newapi.vimLogger
import org.jetbrains.annotations.NonNls
import java.util.*
import javax.swing.KeyStroke
@ -85,23 +83,23 @@ abstract class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
}
private fun doExecute(editor: VimEditor, caret: VimCaret, context: ExecutionContext, operatorArguments: OperatorArguments) {
if (!injector.enabler.isEnabled()) return
if (!injectorBase.enabler.isEnabled()) return
logger.debug("Execute command with handler: " + this.javaClass.name)
val cmd = editor.commandState.executingCommand ?: run {
injector.messages.indicateError()
val cmd = CommandState.getInstance(editor).executingCommand ?: run {
injectorBase.messages.indicateError()
return
}
if (!baseExecute(
editor,
caret,
injector.executionContextManager.onCaret(caret, context),
injectorBase.executionContextManager.onCaret(caret, context),
cmd,
operatorArguments
)
) injector.messages.indicateError()
) injectorBase.messages.indicateError()
}
open fun process(cmd: Command) {
@ -109,13 +107,13 @@ abstract class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
}
companion object {
private val logger = vimLogger<EditorActionHandlerBase>()
private val logger = injectorBase.getLogger(EditorActionHandlerBase::class.java)
fun parseKeysSet(keyStrings: List<String>) = keyStrings.map { StringHelper.parseKeys(it) }.toSet()
fun parseKeysSet(keyStrings: List<String>) = keyStrings.map { injectorBase.parser.parseKeys(it) }.toSet()
@JvmStatic
fun parseKeysSet(@NonNls vararg keyStrings: String): Set<List<KeyStroke>> = List(keyStrings.size) {
StringHelper.parseKeys(keyStrings[it])
injectorBase.parser.parseKeys(keyStrings[it])
}.toSet()
@NonNls

View File

@ -18,25 +18,19 @@
package com.maddyhome.idea.vim.handler
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.editor.event.CaretEvent
import com.intellij.openapi.editor.event.CaretListener
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimCaretListener
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
/**
* @author Alex Plate
@ -153,7 +147,7 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
cmd: Command,
operatorArguments: OperatorArguments,
): Boolean {
val blockSubmodeActive = editor.ij.inBlockSubMode
val blockSubmodeActive = editor.inBlockSubMode
when (this) {
is SingleExecution -> run {
@ -165,42 +159,42 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
is Motion.AbsoluteOffset -> {
var resultOffset = offset.offset
if (resultOffset < 0) {
logger<MotionActionHandler>().error("Offset is less than 0. $resultOffset. ${this.javaClass.name}")
logger.error("Offset is less than 0. $resultOffset. ${this.javaClass.name}")
}
if (CommandFlags.FLAG_SAVE_JUMP in cmd.flags) {
VimPlugin.getMark().saveJumpLocation(editor.ij)
injectorBase.markGroup.saveJumpLocation(editor)
}
if (!editor.ij.isEndAllowed) {
resultOffset = EditorHelper.normalizeOffset(editor.ij, resultOffset, false)
if (!editor.isEndAllowed) {
resultOffset = injectorBase.engineEditorHelper.normalizeOffset(editor, resultOffset, false)
}
preMove(editor, context, cmd)
editor.primaryCaret().moveToOffset(resultOffset)
postMove(editor, context, cmd)
}
is Motion.Error -> VimPlugin.indicateError()
is Motion.Error -> injectorBase.messages.indicateError()
is Motion.NoMotion -> Unit
}
}
is ForEachCaret -> run {
when {
blockSubmodeActive || editor.ij.caretModel.caretCount == 1 -> {
blockSubmodeActive || editor.carets().size == 1 -> {
val primaryCaret = editor.primaryCaret()
doExecuteForEach(editor, primaryCaret, context, cmd, operatorArguments)
}
else -> {
try {
editor.ij.caretModel.addCaretListener(CaretMergingWatcher)
editor.ij.caretModel.runForEachCaret { caret ->
editor.addCaretListener(CaretMergingWatcher)
editor.forEachCaret { caret ->
doExecuteForEach(
editor,
caret.vim,
caret,
context,
cmd,
operatorArguments
)
}
} finally {
editor.ij.caretModel.removeCaretListener(CaretMergingWatcher)
editor.removeCaretListener(CaretMergingWatcher)
}
}
}
@ -226,43 +220,48 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
is Motion.AbsoluteOffset -> {
var resultMotion = offset.offset
if (resultMotion < 0) {
logger<MotionActionHandler>().error("Offset is less than 0. $resultMotion. ${this.javaClass.name}")
logger.error("Offset is less than 0. $resultMotion. ${this.javaClass.name}")
}
if (CommandFlags.FLAG_SAVE_JUMP in cmd.flags) {
VimPlugin.getMark().saveJumpLocation(editor.ij)
injectorBase.markGroup.saveJumpLocation(editor)
}
if (!editor.ij.isEndAllowed) {
resultMotion = EditorHelper.normalizeOffset(editor.ij, resultMotion, false)
if (!editor.isEndAllowed) {
resultMotion = injectorBase.engineEditorHelper.normalizeOffset(editor, resultMotion, false)
}
preMove(editor, caret, context, cmd)
caret.moveToOffset(resultMotion)
val postMoveCaret = if (editor.ij.inBlockSubMode) editor.primaryCaret() else caret
val postMoveCaret = if (editor.inBlockSubMode) editor.primaryCaret() else caret
postMove(editor, postMoveCaret, context, cmd)
}
is Motion.Error -> VimPlugin.indicateError()
is Motion.Error -> injectorBase.messages.indicateError()
is Motion.NoMotion -> Unit
}
}
private object CaretMergingWatcher : CaretListener {
override fun caretRemoved(event: CaretEvent) {
val editor = event.editor
val caretToDelete = event.caret ?: return
private object CaretMergingWatcher : VimCaretListener {
override fun caretRemoved(caret: VimCaret?) {
caret ?: return
val editor = caret.editor
val caretToDelete = caret
if (editor.inVisualMode) {
for (caret in editor.caretModel.allCarets) {
val curCaretStart = caret.selectionStart
val curCaretEnd = caret.selectionEnd
for (vimCaret in editor.carets()) {
val curCaretStart = vimCaret.selectionStart
val curCaretEnd = vimCaret.selectionEnd
val caretStartBetweenCur = caretToDelete.selectionStart in curCaretStart until curCaretEnd
val caretEndBetweenCur = caretToDelete.selectionEnd in curCaretStart + 1..curCaretEnd
if (caretStartBetweenCur || caretEndBetweenCur) {
// Okay, caret is being removed because of merging
val vimSelectionStart = caretToDelete.vimSelectionStart
caret.vimSelectionStart = vimSelectionStart
vimCaret.vimSelectionStart = vimSelectionStart
}
}
}
}
}
companion object {
val logger = injectorBase.getLogger(MotionActionHandler::class.java)
}
}
sealed class Motion {

View File

@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.handler
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.injectorBase
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
@ -31,8 +32,6 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.endOffsetInclusive
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.newapi.injector
/**
* @author Alex Plate
@ -84,9 +83,9 @@ abstract class TextObjectActionHandler : EditorActionHandlerBase(true) {
}
if (visualType == TextObjectVisualType.LINE_WISE && editor.subMode != CommandState.SubMode.VISUAL_LINE) {
injector.visualMotionGroup.toggleVisual(editor, 1, 0, CommandState.SubMode.VISUAL_LINE)
injectorBase.visualMotionGroup.toggleVisual(editor, 1, 0, CommandState.SubMode.VISUAL_LINE)
} else if (visualType != TextObjectVisualType.LINE_WISE && editor.subMode == CommandState.SubMode.VISUAL_LINE) {
injector.visualMotionGroup.toggleVisual(editor, 1, 0, CommandState.SubMode.VISUAL_CHARACTER)
injectorBase.visualMotionGroup.toggleVisual(editor, 1, 0, CommandState.SubMode.VISUAL_CHARACTER)
}
caret.moveToOffset(newend)

View File

@ -1,5 +1,71 @@
package com.maddyhome.idea.vim.helper
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injectorBase
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
import java.util.*
inline fun <reified T : Enum<T>> noneOfEnum(): EnumSet<T> = EnumSet.noneOf(T::class.java)
val TextRange.endOffsetInclusive
get() = if (this.endOffset > 0 && this.endOffset > this.startOffset) this.endOffset - 1 else this.endOffset
val VimEditor.mode
get() = this.commandState.mode
val VimEditor.inVisualMode
get() = this.mode.inVisualMode
var VimEditor.subMode
get() = this.commandState.subMode
set(value) {
this.commandState.subMode = value
}
val VimEditor.commandState
get() = CommandState.getInstance(this)
val CommandState.Mode.inVisualMode
get() = this == CommandState.Mode.VISUAL || this == CommandState.Mode.INSERT_VISUAL
val VimEditor.inBlockSubMode
get() = this.subMode == CommandState.SubMode.VISUAL_BLOCK
/**
* Please use `isEndAllowed` based on `Editor` (another extension function)
* It takes "single command" into account.
*/
val CommandState.Mode.isEndAllowed: Boolean
get() = when (this) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING -> usesVirtualSpace
CommandState.Mode.INSERT_NORMAL -> usesVirtualSpace
CommandState.Mode.INSERT_VISUAL -> usesVirtualSpace
CommandState.Mode.INSERT_SELECT -> usesVirtualSpace
}
val usesVirtualSpace
get() = (injectorBase.optionService.getOptionValue(
OptionScope.GLOBAL,
OptionConstants.virtualeditName
) as VimString).value == "onemore"
val VimEditor.isEndAllowed: Boolean
get() = when (this.mode) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT, CommandState.Mode.INSERT_VISUAL, CommandState.Mode.INSERT_SELECT -> true
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING, CommandState.Mode.INSERT_NORMAL -> {
// One day we'll use a proper insert_normal mode
if (this.mode.inSingleMode) true else usesVirtualSpace
}
}
val CommandState.Mode.inSingleMode: Boolean
get() = when (this) {
CommandState.Mode.INSERT_NORMAL, CommandState.Mode.INSERT_SELECT, CommandState.Mode.INSERT_VISUAL -> true
else -> false
}