1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-03-07 21:32:52 +01:00

Refactor put group

This commit is contained in:
Alex Plate 2019-05-30 11:52:45 +03:00
parent cbc5e8aea1
commit 1bb6345fcb
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F
16 changed files with 327 additions and 406 deletions

View File

@ -23,19 +23,27 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*/
public class PutTextAfterCursorAction extends EditorAction {
public PutTextAfterCursorAction() {
super(new ChangeEditorActionHandler() {
@Override
public boolean execute(@NotNull Editor editor, @NotNull DataContext context, int count, int rawCount,
public boolean execute(@NotNull Editor editor,
@NotNull DataContext context,
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, true, false, false);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, false, true, false, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -23,11 +23,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public class PutTextAfterCursorActionMoveCursor extends EditorAction {
public PutTextAfterCursorActionMoveCursor() {
@ -38,7 +41,12 @@ public class PutTextAfterCursorActionMoveCursor extends EditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, true, true, false);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, false, true, true, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -23,11 +23,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public class PutTextAfterCursorNoIndentAction extends EditorAction {
public PutTextAfterCursorNoIndentAction() {
@ -38,7 +41,12 @@ public class PutTextAfterCursorNoIndentAction extends EditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, false, false, false);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, false, false, false, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -23,11 +23,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public class PutTextBeforeCursorAction extends EditorAction {
public PutTextBeforeCursorAction() {
@ -38,7 +41,12 @@ public class PutTextBeforeCursorAction extends EditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, true, false, true);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, true, true, false, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -23,11 +23,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public class PutTextBeforeCursorActionMoveCursor extends EditorAction {
public PutTextBeforeCursorActionMoveCursor() {
@ -38,7 +41,12 @@ public class PutTextBeforeCursorActionMoveCursor extends EditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, true, true, true);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, true, true, true, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -23,11 +23,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.Argument;
import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.group.copy.PutData;
import com.maddyhome.idea.vim.handler.ChangeEditorActionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public class PutTextBeforeCursorNoIndentAction extends EditorAction {
public PutTextBeforeCursorNoIndentAction() {
@ -38,7 +41,12 @@ public class PutTextBeforeCursorNoIndentAction extends EditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
return VimPlugin.getPut().putText(editor, context, count, false, false, true);
final Register lastRegister = VimPlugin.getRegister().getLastRegister();
final PutData.TextData textData =
lastRegister != null ? new PutData.TextData(lastRegister.getText(), lastRegister.getType()) : null;
final PutData putData = new PutData(textData, null, count, true, false, false, -1);
return VimPlugin.getPut().putText(editor, context, putData);
}
});
}

View File

@ -26,10 +26,9 @@ import com.maddyhome.idea.vim.action.VimCommandAction
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import java.util.*
import javax.swing.KeyStroke
@ -39,22 +38,15 @@ private object PutVisualTextActionHandler : VisualOperatorActionHandler.SingleEx
context: DataContext,
cmd: Command,
caretsAndSelections: Map<Caret, VimSelection>): Boolean {
val register = VimPlugin.getRegister().lastRegister
VimPlugin.getRegister().resetRegister()
if (register != null && register.type == SelectionType.LINE_WISE && editor.isOneLineMode) return false
if (caretsAndSelections.isEmpty()) return false
val textData = VimPlugin.getRegister().lastRegister?.let { PutData.TextData(it.text, it.type) }
VimPlugin.getRegister().resetRegister()
val range = caretsAndSelections.values.first()
val insertTextBeforeCaret = cmd.keys[0].keyChar == 'P'
val selection = PutData.VisualSelection(caretsAndSelections, caretsAndSelections.values.first().type)
val putData = PutData(textData, selection, cmd.count, insertTextBeforeCaret, _indent = true, caretAfterInsertedText = false)
return if (range.type == SelectionType.BLOCK_WISE) {
val isBigP = cmd.keys[0] == parseKeys("P")[0]
VimPlugin.getPut()
.putVisualRangeBlockwise(editor, context, range, cmd.count, true, false, register, isBigP)
} else {
VimPlugin.getPut()
.putVisualRangeCaL(editor, context, caretsAndSelections, cmd.count, true, false, register)
}
return VimPlugin.getPut().putText(editor, context, putData)
}
}

View File

@ -26,31 +26,23 @@ import com.maddyhome.idea.vim.action.VimCommandAction
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import java.util.*
import javax.swing.KeyStroke
private object PutVisualTextMoveCursorActionHandler : VisualOperatorActionHandler.SingleExecution() {
override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map<Caret, VimSelection>): Boolean {
val register = VimPlugin.getRegister().lastRegister
if (caretsAndSelections.isEmpty()) return false
val textData = VimPlugin.getRegister().lastRegister?.let { PutData.TextData(it.text, it.type) }
VimPlugin.getRegister().resetRegister()
if (register == null) return false
if (register.type == SelectionType.LINE_WISE && editor.isOneLineMode) return false
if (register.text == null) return false
val range = caretsAndSelections.values.first()
return if (range.type == SelectionType.BLOCK_WISE) {
val isBigP = cmd.keys[1] == parseKeys("P")[0]
val insertTextBeforeCaret = cmd.keys[1].keyChar == 'P'
val selection = PutData.VisualSelection(caretsAndSelections, caretsAndSelections.values.first().type)
val putData = PutData(textData, selection, cmd.count, insertTextBeforeCaret, _indent = true, caretAfterInsertedText = true)
VimPlugin.getPut()
.putVisualRangeBlockwise(editor, context, range, cmd.count, true, true, register, isBigP)
} else {
VimPlugin.getPut()
.putVisualRangeCaL(editor, context, caretsAndSelections, cmd.count, true, true, register)
}
return VimPlugin.getPut().putText(editor, context, putData)
}
}

View File

@ -26,31 +26,23 @@ import com.maddyhome.idea.vim.action.VimCommandAction
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import java.util.*
import javax.swing.KeyStroke
private object PutVisualTextNoIndentActionHandler : VisualOperatorActionHandler.SingleExecution() {
override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map<Caret, VimSelection>): Boolean {
val register = VimPlugin.getRegister().lastRegister
if (caretsAndSelections.isEmpty()) return false
val textData = VimPlugin.getRegister().lastRegister?.let { PutData.TextData(it.text, it.type) }
VimPlugin.getRegister().resetRegister()
if (register == null) return false
if (register.type == SelectionType.LINE_WISE && editor.isOneLineMode) return false
if (register.text == null) return false
val range = caretsAndSelections.values.first()
return if (range.type == SelectionType.BLOCK_WISE) {
val isBigP = cmd.keys[1] == parseKeys("P")[0]
val insertBeforeCaret = cmd.keys[1].keyChar == 'P'
val selection = PutData.VisualSelection(caretsAndSelections, caretsAndSelections.values.first().type)
val putData = PutData(textData, selection, cmd.count, insertBeforeCaret, _indent = false, caretAfterInsertedText = false)
VimPlugin.getPut()
.putVisualRangeBlockwise(editor, context, range, cmd.count, false, false, register, isBigP)
} else {
VimPlugin.getPut()
.putVisualRangeCaL(editor, context, caretsAndSelections, cmd.count, false, false, register)
}
return VimPlugin.getPut().putText(editor, context, putData)
}
}

View File

@ -22,13 +22,8 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.handler.CaretOrder;
import com.maddyhome.idea.vim.helper.EditorHelper;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
@ -47,16 +42,6 @@ public class ExCommand {
return ranges.getLine(editor, caret, context);
}
public List<Integer> getOrderedLines(@NotNull Editor editor, @NotNull DataContext context,
@NotNull CaretOrder caretOrder) {
final ArrayList<Integer> lines = new ArrayList<>(editor.getCaretModel().getCaretCount());
for (Caret caret : EditorHelper.getOrderedCaretsList(editor, caretOrder)) {
final int line = getLine(editor, caret, context);
lines.add(line);
}
return lines;
}
public int getCount(@NotNull Editor editor, DataContext context, int defaultCount, boolean checkCount) {
int count = -1;
if (checkCount) {

View File

@ -21,14 +21,10 @@ package com.maddyhome.idea.vim.ex.handler
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.ex.*
import com.maddyhome.idea.vim.ex.CommandHandler.Flag.WRITABLE
import com.maddyhome.idea.vim.ex.CommandParser
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.commands
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.handler.CaretOrder
import com.maddyhome.idea.vim.helper.EditorHelper
@ -44,10 +40,10 @@ class CopyTextHandler : CommandHandler(
val arg = CommandParser.getInstance().parse(cmd.argument)
val line = arg.ranges.getFirstLine(editor, caret, context)
val offset = VimPlugin.getMotion().moveCaretToLineStart(editor, line + 1)
VimPlugin.getPut().putText(editor, caret, context, text, SelectionType.LINE_WISE, CommandState.SubMode.NONE,
offset, 1, true, false)
val textData = PutData.TextData(text, SelectionType.LINE_WISE)
val putData = PutData(textData, null, 1, insertTextBeforeCaret = false, _indent = true, caretAfterInsertedText = false, putToLine = line)
VimPlugin.getPut().putTextForCaret(editor, caret, context, putData)
}
return true
}

View File

@ -22,11 +22,11 @@ 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.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.*
import com.maddyhome.idea.vim.ex.CommandHandler.Flag.WRITABLE
import com.maddyhome.idea.vim.group.copy.PutData
import com.maddyhome.idea.vim.handler.CaretOrder
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper
@ -62,17 +62,15 @@ class MoveTextHandler : CommandHandler(
}
}
for (range in ranges) {
editor.document.deleteString(range.startOffset, range.endOffset)
}
ranges.forEach { editor.document.deleteString(it.startOffset, it.endOffset) }
for (i in 0 until caretCount) {
val caret = carets[i]
val text = texts[i]
val offset = VimPlugin.getMotion().moveCaretToLineStart(editor, line + 1)
VimPlugin.getPut().putText(editor, caret, context, text, SelectionType.LINE_WISE, CommandState.SubMode.NONE,
offset, 1, true, false)
val textData = PutData.TextData(text, SelectionType.LINE_WISE)
val putData = PutData(textData, null, 1, insertTextBeforeCaret = false, _indent = true, caretAfterInsertedText = false, putToLine = line)
VimPlugin.getPut().putTextForCaret(editor, caret, context, putData)
}
return true

View File

@ -21,21 +21,19 @@ package com.maddyhome.idea.vim.ex.handler
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.*
import com.maddyhome.idea.vim.ex.CommandHandler
import com.maddyhome.idea.vim.ex.CommandHandler.Flag.WRITABLE
import com.maddyhome.idea.vim.group.MarkGroup
import com.maddyhome.idea.vim.handler.CaretOrder
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.ex.ExCommand
import com.maddyhome.idea.vim.ex.commands
import com.maddyhome.idea.vim.ex.flags
import com.maddyhome.idea.vim.group.copy.PutData
class PutLinesHandler : CommandHandler(
commands("pu[t]"),
flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, WRITABLE)
) {
@Throws(ExException::class)
override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean {
if (editor.isOneLineMode) return false
@ -47,33 +45,9 @@ class PutLinesHandler : CommandHandler(
registerGroup.selectRegister(registerGroup.defaultRegister)
}
val register = registerGroup.lastRegister ?: return false
val text = register.text
val lines = cmd.getOrderedLines(editor, context, CaretOrder.DECREASING_OFFSET)
val carets = EditorHelper.getOrderedCaretsList(editor, CaretOrder.DECREASING_OFFSET)
for (i in carets.indices) {
val caret = carets[i]
val line = lines[i]
var startOffset = minOf(editor.document.textLength,
VimPlugin.getMotion().moveCaretToLineEnd(editor, line, true) + 1)
if (startOffset > 0 && startOffset == editor.document.textLength &&
editor.document.charsSequence[startOffset - 1] != '\n') {
editor.document.insertString(startOffset, "\n")
startOffset++
}
if (text == null) {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
continue
}
VimPlugin.getPut().putText(editor, caret, context, text, SelectionType.LINE_WISE, CommandState.SubMode.NONE,
startOffset, 1, false, false)
}
return true
val line = if (cmd.ranges.size() == 0) -1 else cmd.getLine(editor, context)
val textData = registerGroup.lastRegister?.let { PutData.TextData(it.text, SelectionType.LINE_WISE) }
val putData = PutData(textData, null, 1, false, false, false, line)
return VimPlugin.getPut().putText(editor, context, putData)
}
}

View File

@ -22,223 +22,187 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.text.StringUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.Register
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MarkGroup
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.CaretOrder.DECREASING_OFFSET
import com.maddyhome.idea.vim.handler.CaretOrder.INCREASING_OFFSET
import com.maddyhome.idea.vim.helper.EditorHelper
import java.util.*
import kotlin.math.abs
import kotlin.math.min
/**
* [putToLine] has affect only of [insertTextBeforeCaret] is false and [visualSelection] is null
*/
data class PutData(
val textData: TextData?,
val visualSelection: VisualSelection?,
val count: Int,
val insertTextBeforeCaret: Boolean,
private val _indent: Boolean,
val caretAfterInsertedText: Boolean,
val putToLine: Int = -1
) {
val indent: Boolean =
if (_indent && textData?.typeInRegister != SelectionType.LINE_WISE && visualSelection?.typeInEditor != SelectionType.LINE_WISE) false else _indent
data class VisualSelection(
val caretsAndSelections: Map<Caret, VimSelection>,
val typeInEditor: SelectionType
)
data class TextData(
val rawText: String?,
val typeInRegister: SelectionType
)
}
class PutGroup {
fun putVisualRangeCaL(
editor: Editor,
context: DataContext,
caretsAndSelections: Map<Caret, VimSelection>,
count: Int,
indent: Boolean,
cursorAfter: Boolean,
register: Register?
): Boolean {
caretsAndSelections.entries.sortedByDescending { it.key.logicalPosition }.forEach { (caret, selection) ->
putVisualRangeCaLEx(editor, context, caret, selection, count, indent, cursorAfter, register)
}
fun putText(editor: Editor, context: DataContext, data: PutData): Boolean {
val additionalData = collectPreModificationData(editor, data)
deleteSelectedText(editor, data)
val (text, typeInRegister) = getText(editor, data) ?: return false
putTextAndSetCaretPosition(editor, context, text, typeInRegister, data, additionalData)
return true
}
private fun putVisualRangeCaLEx(
editor: Editor,
context: DataContext,
caret: Caret,
selection: VimSelection,
count: Int,
indent: Boolean,
cursorAfter: Boolean,
register: Register?
): Boolean {
val range = selection.toVimTextRange(false).normalize()
VimPlugin.getChange().deleteRange(editor, caret, range, selection.type, false)
var startOffset = range.startOffset
caret.moveToOffset(startOffset)
if (register == null) return false
var text = register.text ?: run {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
return false
}
val type = register.type
if (type == SelectionType.LINE_WISE) {
if (selection.type != SelectionType.LINE_WISE) {
editor.document.insertString(startOffset, "\n")
startOffset += 1
}
} else if (type == SelectionType.CHARACTER_WISE) {
if (selection.type == SelectionType.LINE_WISE) {
text += "\n"
}
}
putText(editor, caret, context, text, type, selection.type.toSubMode(), startOffset,
count, indent && type == SelectionType.LINE_WISE, cursorAfter)
fun putTextForCaret(editor: Editor, caret: Caret, context: DataContext, data: PutData): Boolean {
val additionalData = collectPreModificationData(editor, data)
val (text, typeInRegister) = getText(editor, data) ?: return false
putForCaret(editor, caret, typeInRegister, data, additionalData, context, text)
return true
}
fun putVisualRangeBlockwise(
editor: Editor,
context: DataContext,
selection: VimSelection,
count: Int,
indent: Boolean,
cursorAfter: Boolean,
register: Register?,
insertBefore: Boolean
): Boolean {
val res = Ref.create(true)
val caret = editor.caretModel.primaryCaret
val range = selection.toVimTextRange(false).normalize()
val line = if (insertBefore) {
editor.offsetToLogicalPosition(range.startOffset).line
private fun collectPreModificationData(editor: Editor, data: PutData): Map<String, Any> {
return if (data.visualSelection != null && data.visualSelection.typeInEditor == SelectionType.BLOCK_WISE) {
val vimSelection = data.visualSelection.caretsAndSelections.getValue(editor.caretModel.primaryCaret)
val selStart = editor.offsetToLogicalPosition(vimSelection.vimStart)
val selEnd = editor.offsetToLogicalPosition(vimSelection.vimEnd)
mapOf(
"startColumnOfSelection" to min(selStart.column, selEnd.column),
"selectedLines" to abs(selStart.line - selEnd.line),
"firstSelectedLine" to min(selStart.line, selEnd.line)
)
} else mutableMapOf()
}
private fun deleteSelectedText(editor: Editor, data: PutData) {
if (data.visualSelection == null) return
data.visualSelection.caretsAndSelections.entries.sortedByDescending { it.key.logicalPosition }.forEach { (caret, selection) ->
if (!caret.isValid) return@forEach
val range = selection.toVimTextRange(false).normalize()
VimPlugin.getChange().deleteRange(editor, caret, range, selection.type, false)
caret.moveToOffset(range.startOffset)
}
}
private fun getText(editor: Editor, data: PutData): Pair<String, SelectionType>? {
var text = data.textData?.rawText ?: run {
if (data.visualSelection != null) {
val offset = editor.caretModel.primaryCaret.offset
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, offset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(offset, offset))
}
return null
}
if (data.visualSelection?.typeInEditor == SelectionType.LINE_WISE && data.textData.typeInRegister == SelectionType.CHARACTER_WISE) text += "\n"
if (data.textData.typeInRegister == SelectionType.LINE_WISE && text.isNotEmpty() && text.last() != '\n') text += '\n'
return text to data.textData.typeInRegister
}
private fun putTextAndSetCaretPosition(editor: Editor, context: DataContext, text: String, typeInRegister: SelectionType, data: PutData, additionalData: Map<String, Any>) {
val myCarets = if (data.visualSelection != null) {
data.visualSelection.caretsAndSelections.keys.sortedByDescending { it.logicalPosition }
} else {
editor.offsetToLogicalPosition(range.endOffset).line
EditorHelper.getOrderedCaretsList(editor, DECREASING_OFFSET)
}
myCarets.forEach { caret -> putForCaret(editor, caret, typeInRegister, data, additionalData, context, text) }
}
private fun putForCaret(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map<String, Any>, context: DataContext, text: String) {
if (data.visualSelection?.typeInEditor == SelectionType.LINE_WISE && editor.isOneLineMode) return
val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, typeInRegister, data, additionalData)
VimPlugin.getChange().deleteRange(editor, caret, range, SelectionType.BLOCK_WISE, false)
startOffsets.forEach { startOffset ->
val subMode = data.visualSelection?.typeInEditor?.toSubMode() ?: CommandState.SubMode.NONE
val endOffset = putTextInternal(editor, caret, context, text, typeInRegister, subMode,
startOffset, data.count, data.indent, data.caretAfterInsertedText)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
moveCaretToEndPosition(editor, caret, startOffset, endOffset, typeInRegister, subMode, data.caretAfterInsertedText)
}
}
val type = register?.type ?: return false
val lineWiseInsert = type == SelectionType.LINE_WISE
when (type) {
SelectionType.CHARACTER_WISE -> {
selection.forEachLine { startOffset, _ ->
caret.moveToOffset(startOffset)
if (!lineWiseInsert) {
val text = register.text ?: run {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
res.set(false)
return@forEachLine
private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map<String, Any>): List<Int> {
if (data.visualSelection != null) {
return when {
data.visualSelection.typeInEditor == SelectionType.CHARACTER_WISE && typeInRegister == SelectionType.LINE_WISE -> {
editor.document.insertString(caret.offset, "\n")
listOf(caret.offset + 1)
}
data.visualSelection.typeInEditor == SelectionType.BLOCK_WISE -> {
val firstSelectedLine = additionalData["firstSelectedLine"] as Int
val selectedLines = additionalData["selectedLines"] as Int
val startColumnOfSelection = additionalData["startColumnOfSelection"] as Int
val line = if (data.insertTextBeforeCaret) firstSelectedLine else firstSelectedLine + selectedLines
when (typeInRegister) {
SelectionType.LINE_WISE -> when {
data.insertTextBeforeCaret -> listOf(EditorHelper.getLineStartOffset(editor, line))
else -> {
val pos = EditorHelper.getLineEndOffset(editor, line, true)
editor.document.insertString(pos, "\n")
listOf(pos + 1)
}
}
SelectionType.CHARACTER_WISE -> (firstSelectedLine + selectedLines downTo firstSelectedLine)
.map { editor.logicalPositionToOffset(LogicalPosition(it, startColumnOfSelection)) }
SelectionType.BLOCK_WISE -> listOf(editor.logicalPositionToOffset(LogicalPosition(firstSelectedLine, startColumnOfSelection)))
}
}
else -> listOf(caret.offset)
}
} else {
if (data.insertTextBeforeCaret) {
return when (typeInRegister) {
SelectionType.LINE_WISE -> listOf(VimPlugin.getMotion().moveCaretToLineStart(editor, caret))
else -> listOf(caret.offset)
}
}
putText(editor, caret, context, text, type, CommandState.SubMode.VISUAL_BLOCK, startOffset,
count, indent && type == SelectionType.LINE_WISE, cursorAfter)
var startOffset: Int
val line = if (data.putToLine < 0) caret.visualPosition.line else data.putToLine
when (typeInRegister) {
SelectionType.LINE_WISE -> {
startOffset = min(editor.document.textLength, VimPlugin.getMotion().moveCaretToLineEnd(editor, line, true) + 1)
if (startOffset > 0 && startOffset == editor.document.textLength &&
editor.document.charsSequence[startOffset - 1] != '\n') {
editor.document.insertString(startOffset, "\n")
startOffset++
}
}
else -> {
startOffset = caret.offset
if (!EditorHelper.isLineEmpty(editor, line, false)) {
startOffset++
}
}
}
SelectionType.LINE_WISE -> {
val startOffset = if (insertBefore) {
EditorHelper.getLineStartOffset(editor, line)
} else {
EditorHelper.getLineEndOffset(editor, line, true)
}
var text = register.text ?: run {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
return false
}
if (!insertBefore) text = "\n" + text
putText(editor, editor.caretModel.primaryCaret, context, text, type, CommandState.SubMode.VISUAL_BLOCK, startOffset,
count, indent && type == SelectionType.LINE_WISE, cursorAfter)
}
SelectionType.BLOCK_WISE -> {
val startOffset = range.startOffset
caret.moveToOffset(startOffset)
if (!lineWiseInsert) {
val text = register.text ?: run {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
res.set(false)
return false
}
putText(editor, caret, context, text, type, CommandState.SubMode.VISUAL_BLOCK, startOffset,
count, indent && type == SelectionType.LINE_WISE, cursorAfter)
}
}
return if (startOffset > editor.document.textLength) listOf(editor.document.textLength) else listOf(startOffset)
}
return res.get()
}
/**
* Pastes text from the last register into the editor.
*
* @param editor The editor to paste into
* @param context The data context
* @param count The number of times to perform the paste
* @return true if able to paste, false if not
*/
fun putText(editor: Editor, context: DataContext, count: Int, indent: Boolean,
cursorAfter: Boolean, beforeCursor: Boolean): Boolean {
val register = VimPlugin.getRegister().lastRegister ?: return false
val selectionType = register.type
if (selectionType == SelectionType.LINE_WISE && editor.isOneLineMode) return false
val text = register.text
val carets = EditorHelper.getOrderedCaretsList(editor, if (beforeCursor) INCREASING_OFFSET else DECREASING_OFFSET)
for (caret in carets) {
val startOffset = getStartOffset(editor, caret, selectionType, beforeCursor)
if (text == null) {
VimPlugin.getMark().setMark(editor, MarkGroup.MARK_CHANGE_POS, startOffset)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, startOffset))
continue
}
putText(editor, caret, context, text, selectionType, CommandState.SubMode.NONE, startOffset, count, indent,
cursorAfter)
}
return true
}
/**
* This performs the actual insert of the paste
*
* @param editor The editor to paste into
* @param context The data context
* @param startOffset The location within the file to paste the text
* @param text The text to paste
* @param type The type of paste
* @param count The number of times to paste the text
* @param indent True if pasted lines should be autoindented, false if not
* @param cursorAfter If true move cursor to just after pasted text
* @param mode The type of highlight prior to the put.
* @param caret The caret to insert to
*/
fun putText(editor: Editor, caret: Caret, context: DataContext, text: String,
type: SelectionType, mode: CommandState.SubMode, startOffset: Int, count: Int,
indent: Boolean, cursorAfter: Boolean) {
var actualText = text
var actualIndent = indent
if (mode == CommandState.SubMode.VISUAL_LINE && editor.isOneLineMode) return
if (actualIndent && type != SelectionType.LINE_WISE && mode != CommandState.SubMode.VISUAL_LINE) actualIndent = false
if (type == SelectionType.LINE_WISE && actualText.isNotEmpty() && actualText[actualText.length - 1] != '\n') {
actualText += '\n'
}
val endOffset = putTextInternal(editor, caret, context, actualText, type, mode, startOffset, count, actualIndent, cursorAfter)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
}
private fun putTextInternal(editor: Editor, caret: Caret, context: DataContext,
text: String, type: SelectionType, mode: CommandState.SubMode,
startOffset: Int, count: Int, indent: Boolean, cursorAfter: Boolean): Int =
@ -327,7 +291,7 @@ class PutGroup {
}
if (indent) endOffset = doIndent(editor, caret, context, startOffset, endOffset)
moveCaret(editor, caret, type, mode, startOffset, endOffset, cursorAfter)
moveCaretToEndPosition(editor, caret, startOffset, endOffset, type, mode, cursorAfter)
return endOffset
}
@ -344,64 +308,41 @@ class PutGroup {
doIndent(editor, caret, context, startOffset, startOffset + insertedText.length)
else
startOffset + insertedText.length
moveCaret(editor, caret, type, mode, startOffset, endOffset, cursorAfter)
moveCaretToEndPosition(editor, caret, startOffset, endOffset, type, mode, cursorAfter)
return endOffset
}
private fun getStartOffset(editor: Editor, caret: Caret, type: SelectionType, beforeCursor: Boolean): Int {
if (beforeCursor) {
return if (type == SelectionType.LINE_WISE)
VimPlugin.getMotion().moveCaretToLineStart(editor, caret)
else
caret.offset
}
var startOffset: Int
if (type == SelectionType.LINE_WISE) {
startOffset = Math.min(editor.document.textLength,
VimPlugin.getMotion().moveCaretToLineEnd(editor, caret) + 1)
if (startOffset > 0 && startOffset == editor.document.textLength &&
editor.document.charsSequence[startOffset - 1] != '\n') {
editor.document.insertString(startOffset, "\n")
startOffset++
private fun moveCaretToEndPosition(
editor: Editor,
caret: Caret,
startOffset: Int,
endOffset: Int,
typeInRegister: SelectionType,
modeInEditor: CommandState.SubMode,
caretAfterInsertedText: Boolean
) {
val cursorMode = when (typeInRegister) {
SelectionType.BLOCK_WISE -> when (modeInEditor) {
CommandState.SubMode.VISUAL_LINE -> if (caretAfterInsertedText) "postEndOffset" else "startOffset"
else -> if (caretAfterInsertedText) "preLineEndOfEndOffset" else "startOffset"
}
} else {
startOffset = caret.offset
if (!EditorHelper.isLineEmpty(editor, caret.logicalPosition.line, false)) {
startOffset++
}
}
return if (startOffset > 0 && startOffset > editor.document.textLength) startOffset - 1 else startOffset
}
private fun moveCaret(editor: Editor, caret: Caret, type: SelectionType,
mode: CommandState.SubMode, startOffset: Int, endOffset: Int, cursorAfter: Boolean) {
val cursorMode = when (type) {
SelectionType.BLOCK_WISE -> if (mode == CommandState.SubMode.VISUAL_LINE) {
if (cursorAfter) 4 else 1
} else {
if (cursorAfter) 5 else 1
}
SelectionType.LINE_WISE -> if (cursorAfter) 4 else 3
else -> if (mode == CommandState.SubMode.VISUAL_LINE) {
if (cursorAfter) 4 else 1
} else {
if (cursorAfter) 5 else 2
SelectionType.LINE_WISE -> if (caretAfterInsertedText) "postEndOffset" else "startOffsetSkipLeading"
SelectionType.CHARACTER_WISE -> when (modeInEditor) {
CommandState.SubMode.VISUAL_LINE -> if (caretAfterInsertedText) "postEndOffset" else "startOffset"
else -> if (caretAfterInsertedText) "preLineEndOfEndOffset" else "preEndOffset"
}
}
when (cursorMode) {
1 -> MotionGroup.moveCaret(editor, caret, startOffset)
2 -> MotionGroup.moveCaret(editor, caret, endOffset - 1)
3 -> {
"startOffset" -> MotionGroup.moveCaret(editor, caret, startOffset)
"preEndOffset" -> MotionGroup.moveCaret(editor, caret, endOffset - 1)
"startOffsetSkipLeading" -> {
MotionGroup.moveCaret(editor, caret, startOffset)
MotionGroup.moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, caret))
}
4 -> MotionGroup.moveCaret(editor, caret, endOffset + 1)
5 -> {
"postEndOffset" -> MotionGroup.moveCaret(editor, caret, endOffset + 1)
"preLineEndOfEndOffset" -> {
val pos = Math.min(endOffset, EditorHelper.getLineEndForOffset(editor, endOffset - 1) - 1)
MotionGroup.moveCaret(editor, caret, pos)
}

View File

@ -50,14 +50,6 @@ sealed class VimSelection {
abstract fun toVimTextRange(skipNewLineForLineMode: Boolean = false): TextRange
/**
* Execute [action] for each line of selection.
* Action will be executed in bottom-up direction if [vimStart] > [vimEnd]
*
* [action#start] and [action#end] are offsets in current line
*/
abstract fun forEachLine(action: (start: Int, end: Int) -> Unit)
abstract fun getNativeStartAndEnd(): Pair<Int, Int>
companion object {
@ -106,17 +98,6 @@ sealed class VimSimpleSelection : VimSelection() {
abstract val normNativeStart: Int
abstract val normNativeEnd: Int
override fun forEachLine(action: (start: Int, end: Int) -> Unit) {
val logicalStart = editor.offsetToLogicalPosition(nativeStart)
val logicalEnd = editor.offsetToLogicalPosition(nativeEnd)
val lineRange = if (logicalStart.line > logicalEnd.line) logicalStart.line downTo logicalEnd.line else logicalStart.line..logicalEnd.line
lineRange.map { line ->
val start = editor.logicalPositionToOffset(LogicalPosition(line, logicalStart.column))
val end = editor.logicalPositionToOffset(LogicalPosition(line, logicalEnd.column))
action(start, end)
}
}
override fun getNativeStartAndEnd() = normNativeStart to normNativeEnd
companion object {
@ -185,7 +166,7 @@ class VimBlockSelection(
return TextRange(starts.toIntArray(), ends.toIntArray()).also { it.normalize(editor.document.textLength) }
}
override fun forEachLine(action: (start: Int, end: Int) -> Unit) {
private fun forEachLine(action: (start: Int, end: Int) -> Unit) {
val offsets = toNativeSelection(editor, vimStart, vimEnd, CommandState.Mode.VISUAL, type.toSubMode())
val logicalStart = editor.offsetToLogicalPosition(min(offsets.first, offsets.second))
val logicalEnd = editor.offsetToLogicalPosition(max(offsets.first, offsets.second))

View File

@ -991,15 +991,6 @@ class PutVisualTextActionTest : VimTestCase() {
myFixture.checkResult(after)
}
@VimBehaviourDiffers(originalVimAfter = """
A Discovery
I Discover${c}y it in a legendary land
alDiscoveryks and lavender and tufted grass,
whDiscoveryt was settled on some sodden sand
hard by the torrent of a mountain pass.
""", description = "Different cursor position")
@Test
fun `test put visual text character to block`() {
val before = """
@ -1016,22 +1007,38 @@ class PutVisualTextActionTest : VimTestCase() {
val after = """
A Discovery
I Discovery it in a legendary land
I Discover${c}y it in a legendary land
alDiscoveryks and lavender and tufted grass,
whDiscover${c}yt was settled on some sodden sand
whDiscoveryt was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
myFixture.checkResult(after)
}
@VimBehaviourDiffers(originalVimAfter = """
@Test
fun `test put visual text character to block motion up`() {
val before = """
A Discovery
I DiscoveryDiscover${c}y it in a legendary land
alDiscoveryDiscoveryks and lavender and tufted grass,
whDiscoveryDiscoveryt was settled on some sodden sand
I |found| it in a legendary land
al|l roc|ks and lavender and tufted grass,
wh$c|ere i|t was settled on some sodden sand
hard by the torrent of a mountain pass.
""", description = "Different cursor position")
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor, before rangeOf "Discovery", SelectionType.CHARACTER_WISE, false)
typeText(parseKeys("<C-V>3e2k", "p"))
val after = """
A Discovery
I Discover${c}y it in a legendary land
alDiscoveryks and lavender and tufted grass,
whDiscoveryt was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
myFixture.checkResult(after)
}
@Test
fun `test put visual text character to block twice`() {
val before = """
@ -1048,22 +1055,14 @@ class PutVisualTextActionTest : VimTestCase() {
val after = """
A Discovery
I DiscoveryDiscovery it in a legendary land
I DiscoveryDiscover${c}y it in a legendary land
alDiscoveryDiscoveryks and lavender and tufted grass,
whDiscoveryDiscover${c}yt was settled on some sodden sand
whDiscoveryDiscoveryt was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
myFixture.checkResult(after)
}
@VimBehaviourDiffers(originalVimAfter = """
A Discovery
I Discover${c}y
alDiscovery
whDiscovery
haDiscovery
""", description = "Different cursor position")
@Test
fun `test put visual text character to block with dollar motion`() {
val before = """
@ -1080,10 +1079,10 @@ class PutVisualTextActionTest : VimTestCase() {
val after = """
A Discovery
I Discovery
I Discover${c}y
alDiscovery
whDiscovery
haDiscover${c}y
haDiscovery
""".trimIndent()
myFixture.checkResult(after)
}
@ -1117,9 +1116,34 @@ class PutVisualTextActionTest : VimTestCase() {
I it in a legendary land
alks and lavender and tufted grass,
${c}wht was settled on some sodden sand
wht was settled on some sodden sand
${c}A Discovery
hard by the torrent of a mountain pass.
""".trimIndent()
myFixture.checkResult(after)
}
@Test
fun `test put visual text line to block before caret`() {
val before = """
A Discovery
I $c|found| it in a legendary land
al|l roc|ks and lavender and tufted grass,
wh|ere i|t was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
val editor = configureByText(before)
VimPlugin.getRegister().storeText(editor, before rangeOf "A Discovery\n", SelectionType.LINE_WISE, false)
typeText(parseKeys("<C-V>2e2j", "P"))
val after = """
A Discovery
${c}A Discovery
I it in a legendary land
alks and lavender and tufted grass,
wht was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent()
myFixture.checkResult(after)
@ -1153,9 +1177,8 @@ class PutVisualTextActionTest : VimTestCase() {
I it in a legendary land
alks and lavender and tufted grass,
${c}wht was settled on some sodden sand
A Discovery
wht was settled on some sodden sand
${c}A Discovery
A Discovery
hard by the torrent of a mountain pass.
@ -1163,7 +1186,6 @@ class PutVisualTextActionTest : VimTestCase() {
myFixture.checkResult(after)
}
@VimBehaviourDiffers(originalVimAfter = """
A Discovery
@ -1192,8 +1214,8 @@ class PutVisualTextActionTest : VimTestCase() {
I it in a legendary land
alks and lavender and tufted grass,
wht was settled on some sodden sand
${c}ha the torrent of a mountain pass.
A Discovery
ha the torrent of a mountain pass.
${c}A Discovery
""".trimIndent()
myFixture.checkResult(after)
@ -1226,8 +1248,8 @@ class PutVisualTextActionTest : VimTestCase() {
I
a
${c}w
A Discovery
w
${c}A Discovery
hard by the torrent of a mountain pass.
""".trimIndent()