1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-08-13 06:16:58 +02:00

Define main caret for visual block selection

This commit is contained in:
Alex Plate
2019-03-20 21:33:42 +03:00
parent f528269bc6
commit 8370248390
11 changed files with 78 additions and 38 deletions

@@ -25,7 +25,6 @@ import com.maddyhome.idea.vim.VimPlugin;
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.CommandState;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.command.SelectionType;
import com.maddyhome.idea.vim.common.TextRange;
@@ -51,7 +50,7 @@ public class DeleteVisualLinesEndAction extends VimCommandAction {
@NotNull DataContext context,
@NotNull Command cmd,
@NotNull VimSelection range) {
if (CommandState.inVisualBlockMode(editor)) {
if (range.getType() == SelectionType.BLOCK_WISE) {
TextRange vimTextRange = range.toVimTextRange();
final int[] starts = vimTextRange.getStartOffsets();
final int[] ends = vimTextRange.getEndOffsets();

@@ -54,18 +54,13 @@ public class MotionDownAction extends MotionEditorAction {
int count,
int rawCount,
@Nullable Argument argument) {
Caret lastDownCaret = EditorData.getLastDownCaret(editor);
EditorData.setLastDownCaret(editor, caret);
if (CommandState.inVisualBlockMode(editor) && EditorData.shouldIgnoreNextMove(editor)) {
EditorData.dontIgnoreNextMove(editor);
if (lastDownCaret != caret) {
return caret.getOffset();
}
return caret.getOffset();
}
if (CommandState.inVisualBlockMode(editor)) {
Caret primaryCaret = editor.getCaretModel().getPrimaryCaret();
int blockEndOffset = CaretDataKt.getVimSelectionStart(primaryCaret);
int blockStartOffset = primaryCaret.getOffset();
int blockEndOffset = CaretDataKt.getVimSelectionStart(caret);
int blockStartOffset = caret.getOffset();
VisualPosition blockEndPosition = editor.offsetToVisualPosition(blockEndOffset);
VisualPosition blockStartPosition = editor.offsetToVisualPosition(blockStartOffset);
if (blockEndPosition.getLine() < blockStartPosition.getLine()) {

@@ -356,6 +356,15 @@ public class MotionGroup {
public static void moveCaret(@NotNull Editor editor, @NotNull Caret caret, int offset, boolean forceKeepVisual) {
if (offset >= 0 && offset <= editor.getDocument().getTextLength()) {
if (CommandState.inVisualBlockMode(editor)) {
scrollCaretIntoView(editor);
UtilsKt.vimMoveBlockSelectionToOffset(editor, offset);
Caret blockMainCaret = CaretDataKt.getVimBlockMainCaret(editor);
CaretData.setLastColumn(editor, blockMainCaret, blockMainCaret.getVisualPosition().column);
return;
}
final boolean keepVisual = forceKeepVisual || keepVisual(editor);
if (caret.getOffset() != offset) {
caret.moveToOffset(offset);

@@ -97,8 +97,14 @@ object PutCopyGroup {
): Boolean {
val res = Ref.create(true)
val caret = editor.caretModel.primaryCaret
val range = selection.toVimTextRange().normalize()
val line = if (insertBefore) {
editor.offsetToLogicalPosition(range.startOffset).line
} else {
editor.offsetToLogicalPosition(range.endOffset).line
}
VimPlugin.getChange().deleteRange(editor, caret, range, SelectionType.BLOCK_WISE, false)
val type = register?.type ?: return false
@@ -124,9 +130,9 @@ object PutCopyGroup {
}
SelectionType.LINE_WISE -> {
val startOffset = if (insertBefore) {
EditorHelper.getLineStartForOffset(editor, range.startOffset)
EditorHelper.getLineStartOffset(editor, line)
} else {
EditorHelper.getLineEndForOffset(editor, range.endOffset)
EditorHelper.getLineEndOffset(editor, line, true)
}
var text = register.text ?: run {

@@ -34,6 +34,7 @@ import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.CaretData
import com.maddyhome.idea.vim.helper.EditorData
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.vimBlockMainCaretSetToNull
import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.helper.vimSelectionStartSetToNull
import com.maddyhome.idea.vim.helper.vimStartSelectionAtPoint
@@ -283,6 +284,7 @@ object VisualMotionGroup {
val vimSelectionStart = primaryCaret.vimSelectionStart
VimPlugin.getMark().setVisualSelectionMarks(editor, TextRange(vimSelectionStart, primaryCaret.offset))
editor.caretModel.allCarets.forEach { it.vimSelectionStartSetToNull() }
editor.vimBlockMainCaretSetToNull()
CommandState.getInstance(editor).subMode = CommandState.SubMode.NONE
}

@@ -30,6 +30,7 @@ import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.vimBlockMainCaret
import com.maddyhome.idea.vim.helper.vimSelectionStart
/**
@@ -47,7 +48,10 @@ abstract class MotionEditorActionHandler : EditorActionHandlerBase(false) {
final override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
val visualBlockActive = CommandState.inVisualBlockMode(editor)
if (visualBlockActive || editor.caretModel.caretCount == 1 || alwaysBatchExecution) {
if (visualBlockActive) {
val primaryCaret = editor.vimBlockMainCaret
doExecute(editor, primaryCaret, context, cmd)
} else if (editor.caretModel.caretCount == 1 || alwaysBatchExecution) {
val primaryCaret = editor.caretModel.primaryCaret
doExecute(editor, primaryCaret, context, cmd)
} else {

@@ -34,6 +34,7 @@ import com.maddyhome.idea.vim.group.motion.VisualMotionGroup
import com.maddyhome.idea.vim.helper.CaretData
import com.maddyhome.idea.vim.helper.EditorData
import com.maddyhome.idea.vim.helper.VimSelection
import com.maddyhome.idea.vim.helper.vimBlockMainCaret
import com.maddyhome.idea.vim.helper.vimSelectionStart
import com.maddyhome.idea.vim.helper.visualBlockRange
@@ -68,7 +69,7 @@ abstract class VisualOperatorActionHandler : EditorActionHandlerBase(false) {
val res = Ref.create(true)
when {
selections.keys.isEmpty() -> return false
selections.keys.size == 1 -> res.set(executeAction(editor, editor.caretModel.primaryCaret, context, cmd, selections.values.first()))
selections.keys.size == 1 -> res.set(executeAction(editor, selections.keys.first(), context, cmd, selections.values.first()))
else -> editor.caretModel.runForEachCaret({ caret ->
val range = selections.getValue(caret)
val loopRes = executeAction(editor, caret, context, cmd, range)
@@ -95,8 +96,8 @@ abstract class VisualOperatorActionHandler : EditorActionHandlerBase(false) {
if (CommandState.inVisualBlockMode(this)) {
val adj = if (VisualMotionGroup.exclusiveSelection) 0 else 1
val primaryCaret = caretModel.primaryCaret
return mapOf(primaryCaret to VimSelection(primaryCaret.vimSelectionStart, primaryCaret.offset + adj, SelectionType.BLOCK_WISE, this))
val (start, end) = vimBlockMainCaret.run { if (vimSelectionStart > offset) vimSelectionStart + adj to offset else vimSelectionStart to offset + adj }
return mapOf(vimBlockMainCaret to VimSelection(start, end, SelectionType.BLOCK_WISE, this))
}
return this.caretModel.allCarets.associateWith { caret ->

@@ -59,7 +59,8 @@ public class CaretData {
caret.putUserData(LAST_COLUMN, col);
}
else {
editor.getCaretModel().getPrimaryCaret().putUserData(LAST_COLUMN, col);
Caret vimBlockMainCaret = CaretDataKt.getVimBlockMainCaret(editor);
vimBlockMainCaret.putUserData(LAST_COLUMN, col);
}
}

@@ -47,3 +47,17 @@ fun Caret.vimSelectionStartSetToNull() {
private var Caret._vimSelectionStart: Int? by userData()
private var Editor._vimBlockSelectinoStart: Int? by userData()
var Editor.vimBlockMainCaret: Caret
get() = _vimBlockMainCaret
?: throw AssertionError("Trying to access block main caret, but it's not set")
set(value) {
_vimBlockMainCaret = value
}
fun Editor.vimBlockMainCaretSetToNull() {
this._vimBlockMainCaret = null
}
private var Editor._vimBlockMainCaret: Caret? by userData()

@@ -270,21 +270,6 @@ public class EditorData {
editor.putUserData(WAS_VISUAL_BLOCK_MODE, value);
}
/**
* Gets the last caret used in down movement.
*/
@Nullable
public static Caret getLastDownCaret(@NotNull Editor editor) {
return editor.getUserData(LAST_DOWN_CARET);
}
/**
* Sets the last caret used in down movement.
*/
public static void setLastDownCaret(@NotNull Editor editor, @NotNull Caret caret) {
editor.putUserData(LAST_DOWN_CARET, caret);
}
/**
* This is a static helper - no instances needed
*/
@@ -307,7 +292,6 @@ public class EditorData {
private static final Key<Boolean> IS_KEEPING_VISUAL_OPERATOR_ACTION = new Key<>("isKeepingVisualOperatorAction");
private static final Key<CommandState.Mode> CHANGE_ACTION_SWITCH_MODE = new Key<>("changeActionSwitchMode");
private static final Key<Boolean> WAS_VISUAL_BLOCK_MODE = new Key<>("wasVisualBlockMode");
private static final Key<Caret> LAST_DOWN_CARET = new Key<>("lastDownCaret");
private static final Logger logger = Logger.getInstance(EditorData.class.getName());

@@ -38,19 +38,31 @@ val Editor.visualBlockRange: TextRange
get() = selectionModel.run { TextRange(blockSelectionStarts, blockSelectionEnds) }
fun Caret.vimStartSelectionAtPoint(point: Int) {
setVisualSelection(point, point, this)
vimSelectionStart = point
setVisualSelection(point, point, this)
}
fun Caret.vimMoveSelectionToCaret() {
if (CommandState.getInstance(editor).mode != CommandState.Mode.VISUAL)
throw RuntimeException("Attempt to extent selection in non-visual mode")
if (CommandState.inVisualBlockMode(editor))
throw RuntimeException("Move caret with [vimMoveBlockSelectionToOffset]")
val startOffsetMark = vimSelectionStart
setVisualSelection(startOffsetMark, offset, this)
}
fun vimMoveBlockSelectionToOffset(editor: Editor, offset: Int) {
if (!CommandState.inVisualBlockMode(editor))
throw RuntimeException("Move caret with [vimMoveSelectionToCaret]")
val vimBlockMainCaret = editor.vimBlockMainCaret
val startOffsetMark = vimBlockMainCaret.vimSelectionStart
setVisualSelection(startOffsetMark, offset, vimBlockMainCaret)
}
fun Caret.vimUpdateEditorSelection() {
val startOffsetMark = vimSelectionStart
setVisualSelection(startOffsetMark, offset, this)
@@ -73,12 +85,14 @@ private fun setVisualSelection(firstOffset: Int, secondOffset: Int, caret: Caret
caret.setSelection(start, adjEnd)
}
CommandState.SubMode.VISUAL_BLOCK -> {
if (caret != editor.caretModel.primaryCaret) return // Block operations are performed only on primary caret
editor.caretModel.removeSecondaryCarets()
val blockStart = editor.offsetToLogicalPosition(start)
var blockStart = editor.offsetToLogicalPosition(start)
var blockEnd = editor.offsetToLogicalPosition(end)
if (blockStart.column > blockEnd.column) {
// swap variables
blockStart = blockEnd.also { blockEnd = blockStart }
}
if (!VisualMotionGroup.exclusiveSelection) {
blockEnd = LogicalPosition(blockEnd.line, blockEnd.column + 1)
}
@@ -95,6 +109,17 @@ private fun setVisualSelection(firstOffset: Int, secondOffset: Int, caret: Caret
aCaret.moveToOffset(aCaret.selectionEnd - 1)
}
}
val startLine = editor.offsetToLogicalPosition(caret.vimSelectionStart).line
val startColumn = editor.offsetToLogicalPosition(caret.vimSelectionStart).column
if (editor.caretModel.allCarets.first().logicalPosition.line == startLine) {
editor.vimBlockMainCaret = editor.caretModel.allCarets.last()
} else {
editor.vimBlockMainCaret = editor.caretModel.allCarets.first()
}
if (editor.vimBlockMainCaret.logicalPosition.column <= startColumn) {
editor.vimBlockMainCaret.moveToOffset(editor.vimBlockMainCaret.selectionStart)
}
}
}
}