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

Support multicaret for entering visual mode with count

This commit is contained in:
Alex Plate 2019-05-08 18:44:02 +03:00
parent b3f3a307ba
commit 4237ce9b3c
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F
8 changed files with 100 additions and 22 deletions

View File

@ -242,7 +242,7 @@ public class Ranges {
endLine = range.getLine(editor, context, lastZero);
if (range.isMove()) {
MotionGroup.moveCaret(editor, editor.getCaretModel().getPrimaryCaret(),
VimPlugin.getMotion().moveCaretToLine(editor, endLine));
VimPlugin.getMotion().moveCaretToLine(editor, endLine, editor.getCaretModel().getPrimaryCaret()));
}
// Did that last range represent the start of the file?
lastZero = (endLine < 0);
@ -265,7 +265,7 @@ public class Ranges {
startLine = endLine;
endLine = range.getLine(editor, caret, context, lastZero);
if (range.isMove()) MotionGroup.moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLine(editor, endLine));
if (range.isMove()) MotionGroup.moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLine(editor, endLine, editor.getCaretModel().getPrimaryCaret()));
lastZero = endLine < 0;
++count;

View File

@ -41,7 +41,7 @@ class RepeatHandler : CommandHandler(commands("@"),
lastArg = arg
val line = cmd.getLine(editor, caret, context)
MotionGroup.moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLine(editor, line))
MotionGroup.moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLine(editor, line, editor.caretModel.primaryCaret))
if (arg == ':') {
return CommandParser.getInstance().processLastCommand(editor, context, 1)

View File

@ -1098,8 +1098,8 @@ public class MotionGroup {
return false;
}
public int moveCaretToLine(@NotNull Editor editor, int logicalLine) {
int col = CaretDataKt.getVimLastColumn(editor.getCaretModel().getPrimaryCaret());
public int moveCaretToLine(@NotNull Editor editor, int logicalLine, @NotNull Caret caret) {
int col = CaretDataKt.getVimLastColumn(caret);
int line = logicalLine;
if (logicalLine < 0) {
line = 0;

View File

@ -129,17 +129,16 @@ class VisualMotionGroup {
if (!CommandState.inVisualMode(editor)) {
// Enable visual subMode
if (rawCount > 0) {
if (editor.caretModel.caretCount > 1) {
// FIXME: 2019-03-05 Support multicaret
return false
}
val range = editor.caretModel.primaryCaret.vimLastVisualOperatorRange ?: VisualChange.default(subMode)
val end = VisualOperation.calculateRange(editor, range, count)
val lastColumn = if (range.columns == MotionGroup.LAST_COLUMN) MotionGroup.LAST_COLUMN else editor.offsetToLogicalPosition(end).column
CommandState.getInstance(editor).pushState(CommandState.Mode.VISUAL, range.type.toSubMode(), MappingMode.VISUAL)
val primarySubMode = editor.caretModel.primaryCaret.vimLastVisualOperatorRange?.type?.toSubMode()
?: subMode
CommandState.getInstance(editor).pushState(CommandState.Mode.VISUAL, primarySubMode, MappingMode.VISUAL)
editor.vimForAllOrPrimaryCaret {
val range = it.vimLastVisualOperatorRange ?: VisualChange.default(subMode)
val end = VisualOperation.calculateRange(editor, range, count, it)
val lastColumn = if (range.columns == MotionGroup.LAST_COLUMN) MotionGroup.LAST_COLUMN else editor.offsetToLogicalPosition(end).column
it.vimLastColumn = lastColumn
it.vimSetSelection(editor.caretModel.offset, end, true)
it.vimSetSelection(it.offset, end, true)
}
} else {
CommandState.getInstance(editor).pushState(CommandState.Mode.VISUAL, subMode, MappingMode.VISUAL)

View File

@ -79,7 +79,7 @@ class VisualOperation {
/**
* Calculate end offset of [VisualChange]
*/
fun calculateRange(editor: Editor, range: VisualChange, count: Int): Int {
fun calculateRange(editor: Editor, range: VisualChange, count: Int, caret: Caret): Int {
var (lines, chars, type) = range
if (type == SelectionType.LINE_WISE || type == SelectionType.BLOCK_WISE || lines > 1) {
lines *= count
@ -87,16 +87,15 @@ class VisualOperation {
if (type == SelectionType.CHARACTER_WISE && lines == 1 || type == SelectionType.BLOCK_WISE) {
chars *= count
}
val start = editor.caretModel.offset
val sp = editor.offsetToLogicalPosition(start)
val sp = editor.offsetToLogicalPosition(caret.offset)
val linesDiff = (lines - 1).coerceAtLeast(0)
val endLine = (sp.line + linesDiff).coerceAtMost(editor.document.lineCount - 1)
return when (type) {
SelectionType.LINE_WISE -> VimPlugin.getMotion().moveCaretToLine(editor, endLine)
SelectionType.LINE_WISE -> VimPlugin.getMotion().moveCaretToLine(editor, endLine, caret)
SelectionType.CHARACTER_WISE -> when {
lines > 1 -> VimPlugin.getMotion().moveCaretToLineStart(editor, endLine) + min(EditorHelper.getLineLength(editor, endLine), chars)
else -> EditorHelper.normalizeOffset(editor, sp.line, start + chars - 1, true)
else -> EditorHelper.normalizeOffset(editor, sp.line, caret.offset + chars - 1, true)
}
SelectionType.BLOCK_WISE -> {
val endColumn = min(EditorHelper.getLineLength(editor, endLine), sp.column + chars - 1)

View File

@ -47,7 +47,7 @@ fun SelectionModel.vimSetSystemBlockSelectionSilently(start: LogicalPosition, en
fun Caret.vimSetSystemSelectionSilently(start: Int, end: Int) =
SelectionVimListenerSuppressor.lock().use { setSelection(start, end) }
inline fun Editor.vimForAllOrPrimaryCaret(action: (caret: Caret) -> Unit) {
fun Editor.vimForAllOrPrimaryCaret(action: (caret: Caret) -> Unit) {
if (CommandState.inVisualBlockMode(this)) {
action(this.caretModel.primaryCaret)
} else {

View File

@ -130,6 +130,27 @@ class VisualToggleCharacterModeActionTest : VimTestCase() {
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_CHARACTER)
}
fun `test enter visual with count multicaret`() {
doTest(parseKeys("1v"),
"""
A Discovery
I ${c}found it in a legendary land
all rocks and ${c}lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
"""
A Discovery
I ${s}${c}f${se}ound it in a legendary land
all rocks and ${s}${c}l${se}avender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_CHARACTER)
}
fun `test enter visual with five count`() {
doTest(parseKeys("5v"),
"""
@ -193,6 +214,27 @@ class VisualToggleCharacterModeActionTest : VimTestCase() {
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_CHARACTER)
}
fun `test enter visual with count after visual operation multicaret`() {
doTest(parseKeys("vedx", "1v"),
"""
A Discovery
I ${c}found it in a legendary land
all rocks and ${c}lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
"""
A Discovery
I ${s}it i${c}n${se} a legendary land
all rocks and ${s}and tuf${c}t${se}ed grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_CHARACTER)
}
fun `test enter visual with count after visual operation multiple time`() {
doTest(parseKeys("vedx", "1v", "<ESC>bb", "1v"),
"""
@ -248,7 +290,7 @@ class VisualToggleCharacterModeActionTest : VimTestCase() {
"""
A Discovery
I ${s}it in a legendary lan${c}d${se}
I ${s}it in a legendary land${c}${se}
all rocks and lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
@ -330,7 +372,7 @@ class VisualToggleCharacterModeActionTest : VimTestCase() {
A Discovery
I
${s}all rocks and lavender and tufted grass${c},${se}
${s}all rocks and lavender and tufted grass,${c}${se}
where it was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
@ -378,6 +420,23 @@ class VisualToggleCharacterModeActionTest : VimTestCase() {
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_LINE)
}
fun `test enter visual with count after line visual operation multicaret`() {
doTest(parseKeys("Vd", "1v"),
"""
A ${c}Discovery
I found it in a legendary land
all ${c}rocks and lavender and tufted grass,
where it was settled on some sodden sand
hard by the torrent of a mountain pass.""".trimIndent(),
"""
${s}${c}
${se}I found it in a legendary land
${s}${c}where it was settled on some sodden sand
${se}hard by the torrent of a mountain pass.""".trimIndent(),
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_LINE)
}
fun `test enter visual with double count after line visual operation`() {
doTest(parseKeys("Vd", "2v"),
"""

View File

@ -46,6 +46,27 @@ class VisualToggleLineModeActionTest : VimTestCase() {
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_LINE)
}
fun `test enter visual with count multicaret`() {
doTest(parseKeys("1V"),
"""
A Discovery
I ${c}found it in a legendary land
all rocks and lavender and tufted grass,
where it ${c}was settled on some sodden sand
hard by the torrent of a mountain pass.
""".trimIndent(),
"""
A Discovery
${s}I ${c}found it in a legendary land
${se}all rocks and lavender and tufted grass,
${s}where it ${c}was settled on some sodden sand
${se}hard by the torrent of a mountain pass.
""".trimIndent(),
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_LINE)
}
fun `test enter visual with 3 count`() {
doTest(parseKeys("3V"),
"""