mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-04-23 04:15:46 +02:00
Revert per-caret registers
This commit is contained in:
parent
ce6a296233
commit
fb270cdbc5
src
main/java/com/maddyhome/idea/vim
test/java/org/jetbrains/plugins/ideavim/ex/implementation/variables
vim-engine/src/main/kotlin/com/maddyhome/idea/vim
action
api
common
put
regexp
register
vimscript/model/commands
yank
@ -282,4 +282,4 @@ fun VimExtensionFacade.exportOperatorFunction(name: String, function: OperatorFu
|
||||
|
||||
fun interface ScriptFunction {
|
||||
fun execute(editor: VimEditor, context: ExecutionContext, args: Map<String, VimDataType>): ExecutionResult
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,7 @@ import com.intellij.openapi.editor.markup.TextAttributes
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.util.Alarm
|
||||
import com.intellij.util.Alarm.ThreadToUse
|
||||
import com.jetbrains.rd.util.first
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.common.ModeChangeListener
|
||||
@ -123,9 +121,9 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
||||
initialised = false
|
||||
}
|
||||
|
||||
override fun yankPerformed(caretToRange: Map<ImmutableVimCaret, TextRange>) {
|
||||
override fun yankPerformed(editor: VimEditor, range: TextRange) {
|
||||
ensureInitialised()
|
||||
highlightHandler.highlightYankRange(caretToRange)
|
||||
highlightHandler.highlightYankRange(editor.ij, range)
|
||||
}
|
||||
|
||||
override fun modeChanged(editor: VimEditor, oldMode: Mode) {
|
||||
@ -146,25 +144,22 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
||||
private var lastEditor: Editor? = null
|
||||
private val highlighters = mutableSetOf<RangeHighlighter>()
|
||||
|
||||
fun highlightYankRange(caretToRange: Map<ImmutableVimCaret, TextRange>) {
|
||||
fun highlightYankRange(editor: Editor, range: TextRange) {
|
||||
// from vim-highlightedyank docs: When a new text is yanked or user starts editing, the old highlighting would be deleted
|
||||
clearYankHighlighters()
|
||||
|
||||
val editor = caretToRange.first().key.editor.ij
|
||||
lastEditor = editor
|
||||
|
||||
val attributes = getHighlightTextAttributes(editor)
|
||||
for (range in caretToRange.values) {
|
||||
for (i in 0 until range.size()) {
|
||||
val highlighter = editor.markupModel.addRangeHighlighter(
|
||||
range.startOffsets[i],
|
||||
range.endOffsets[i],
|
||||
HighlighterLayer.SELECTION,
|
||||
attributes,
|
||||
HighlighterTargetArea.EXACT_RANGE,
|
||||
)
|
||||
highlighters.add(highlighter)
|
||||
}
|
||||
for (i in 0 until range.size()) {
|
||||
val highlighter = editor.markupModel.addRangeHighlighter(
|
||||
range.startOffsets[i],
|
||||
range.endOffsets[i],
|
||||
HighlighterLayer.SELECTION,
|
||||
attributes,
|
||||
HighlighterTargetArea.EXACT_RANGE,
|
||||
)
|
||||
highlighters.add(highlighter)
|
||||
}
|
||||
|
||||
// from vim-highlightedyank docs: A negative number makes the highlight persistent.
|
||||
@ -282,4 +277,4 @@ internal class VimHighlightedYank : VimExtension, VimYankListener, ModeChangeLis
|
||||
return default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import com.maddyhome.idea.vim.extension.exportOperatorFunction
|
||||
import com.maddyhome.idea.vim.group.visual.VimSelection
|
||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||
import com.maddyhome.idea.vim.newapi.IjVimCopiedText
|
||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||
import com.maddyhome.idea.vim.newapi.ij
|
||||
import com.maddyhome.idea.vim.newapi.vim
|
||||
@ -154,8 +153,7 @@ private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimC
|
||||
usedType = SelectionType.CHARACTER_WISE
|
||||
}
|
||||
|
||||
val copiedText = IjVimCopiedText(usedText, (savedRegister.copiedText as IjVimCopiedText).transferableData)
|
||||
val textData = PutData.TextData(savedRegister.name, copiedText, usedType)
|
||||
val textData = PutData.TextData(usedText, usedType, savedRegister.transferableData, savedRegister.name)
|
||||
|
||||
val putData = PutData(
|
||||
textData,
|
||||
|
@ -207,7 +207,7 @@ internal class VimSurroundExtension : VimExtension {
|
||||
val trimmedValue = if (newSurround.shouldTrim) innerValue.trim() else innerValue
|
||||
it.first + trimmedValue + it.second
|
||||
} ?: innerValue
|
||||
val textData = PutData.TextData(null, injector.clipboardManager.dumbCopiedText(text), SelectionType.CHARACTER_WISE)
|
||||
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList(), null)
|
||||
val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = false)
|
||||
|
||||
surrounding.caret to putData
|
||||
|
@ -25,10 +25,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.maddyhome.idea.vim.api.VimInjectorKt.injector;
|
||||
|
||||
/**
|
||||
* This group works with command associated with copying and pasting text
|
||||
*/
|
||||
@ -128,7 +127,7 @@ public class RegisterGroup extends VimRegisterGroupBase implements PersistentSta
|
||||
final String text = VimPlugin.getXML().getSafeXmlText(textElement);
|
||||
if (text != null) {
|
||||
logger.trace("Register data parsed");
|
||||
register = new Register(key, injector.getClipboardManager().dumbCopiedText(text), type);
|
||||
register = new Register(key, type, text, Collections.emptyList());
|
||||
}
|
||||
else {
|
||||
logger.trace("Cannot parse register data");
|
||||
|
@ -36,7 +36,6 @@ import com.maddyhome.idea.vim.ide.isClionNova
|
||||
import com.maddyhome.idea.vim.ide.isRider
|
||||
import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS
|
||||
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||
import com.maddyhome.idea.vim.newapi.IjVimCopiedText
|
||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||
import com.maddyhome.idea.vim.newapi.ij
|
||||
import com.maddyhome.idea.vim.newapi.vim
|
||||
@ -127,7 +126,7 @@ internal class PutGroup : VimPutBase() {
|
||||
point.dispose()
|
||||
if (!caret.isValid) return@forEach
|
||||
|
||||
val caretPossibleEndOffset = lastPastedRegion?.endOffset ?: (startOffset + text.copiedText.text.length)
|
||||
val caretPossibleEndOffset = lastPastedRegion?.endOffset ?: (startOffset + text.text.length)
|
||||
val endOffset = if (data.indent) {
|
||||
doIndent(
|
||||
vimEditor,
|
||||
@ -179,10 +178,12 @@ internal class PutGroup : VimPutBase() {
|
||||
val allContentsBefore = CopyPasteManager.getInstance().allContents
|
||||
val sizeBeforeInsert = allContentsBefore.size
|
||||
val firstItemBefore = allContentsBefore.firstOrNull()
|
||||
logger.debug { "Copied text: ${text.copiedText}" }
|
||||
val (textContent, transferableData) = text.copiedText as IjVimCopiedText
|
||||
logger.debug { "Transferable classes: ${text.transferableData.joinToString { it.javaClass.name }}" }
|
||||
val origContent: TextBlockTransferable =
|
||||
injector.clipboardManager.setClipboardText(textContent, textContent, transferableData) as TextBlockTransferable
|
||||
injector.clipboardManager.setClipboardText(
|
||||
text.text,
|
||||
transferableData = text.transferableData,
|
||||
) as TextBlockTransferable
|
||||
val allContentsAfter = CopyPasteManager.getInstance().allContents
|
||||
val sizeAfterInsert = allContentsAfter.size
|
||||
try {
|
||||
@ -190,7 +191,7 @@ internal class PutGroup : VimPutBase() {
|
||||
} finally {
|
||||
val textInClipboard = (firstItemBefore as? TextBlockTransferable)
|
||||
?.getTransferData(DataFlavor.stringFlavor) as? String
|
||||
val textOnTop = textInClipboard != null && textInClipboard != text.copiedText.text
|
||||
val textOnTop = textInClipboard != null && textInClipboard != text.text
|
||||
if (sizeBeforeInsert != sizeAfterInsert || textOnTop) {
|
||||
// Sometimes an inserted text replaces an existing one. E.g. on insert with + or * register
|
||||
(CopyPasteManager.getInstance() as? CopyPasteManagerEx)?.run { removeContent(origContent) }
|
||||
|
@ -18,7 +18,6 @@ import com.intellij.openapi.editor.VisualPosition
|
||||
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.CaretRegisterStorageBase
|
||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||
import com.maddyhome.idea.vim.common.InsertSequence
|
||||
@ -98,7 +97,6 @@ internal var Caret.vimInsertStart: RangeMarker by userDataOr {
|
||||
}
|
||||
|
||||
// TODO: Data could be lost during visual block motion
|
||||
internal var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
|
||||
internal var Caret.markStorage: LocalMarkStorage? by userDataCaretToEditor()
|
||||
internal var Caret.lastSelectionInfo: SelectionInfo? by userDataCaretToEditor()
|
||||
|
||||
|
@ -12,8 +12,6 @@ import com.intellij.openapi.editor.Caret
|
||||
import com.intellij.openapi.editor.LogicalPosition
|
||||
import com.intellij.openapi.editor.VisualPosition
|
||||
import com.maddyhome.idea.vim.api.BufferPosition
|
||||
import com.maddyhome.idea.vim.api.CaretRegisterStorage
|
||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||
@ -21,6 +19,7 @@ import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimCaretBase
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.common.InsertSequence
|
||||
import com.maddyhome.idea.vim.common.LiveRange
|
||||
import com.maddyhome.idea.vim.group.visual.VisualChange
|
||||
@ -29,7 +28,6 @@ import com.maddyhome.idea.vim.helper.insertHistory
|
||||
import com.maddyhome.idea.vim.helper.lastSelectionInfo
|
||||
import com.maddyhome.idea.vim.helper.markStorage
|
||||
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
|
||||
import com.maddyhome.idea.vim.helper.registerStorage
|
||||
import com.maddyhome.idea.vim.helper.resetVimLastColumn
|
||||
import com.maddyhome.idea.vim.helper.vimInsertStart
|
||||
import com.maddyhome.idea.vim.helper.vimLastColumn
|
||||
@ -37,22 +35,14 @@ import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
|
||||
import com.maddyhome.idea.vim.helper.vimLine
|
||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
import com.maddyhome.idea.vim.helper.vimSelectionStartClear
|
||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
|
||||
internal class IjVimCaret(val caret: Caret) : VimCaretBase() {
|
||||
|
||||
override val registerStorage: CaretRegisterStorage
|
||||
get() {
|
||||
var storage = this.caret.registerStorage
|
||||
if (storage == null) {
|
||||
initInjector() // To initialize injector used in CaretRegisterStorageBase
|
||||
storage = CaretRegisterStorageBase(this)
|
||||
this.caret.registerStorage = storage
|
||||
} else if (storage.caret != this) {
|
||||
storage.caret = this
|
||||
}
|
||||
return storage
|
||||
}
|
||||
override val registerStorage: VimRegisterGroup
|
||||
get() = injector.registerGroup
|
||||
|
||||
override val markStorage: LocalMarkStorage
|
||||
get() {
|
||||
var storage = this.caret.markStorage
|
||||
|
@ -179,21 +179,38 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
|
||||
return editor.caretModel.allCarets.map { IjVimCaret(it) }
|
||||
}
|
||||
|
||||
override var isFirstCaret = true
|
||||
override var isReversingCarets = false
|
||||
|
||||
@Suppress("ideavimRunForEachCaret")
|
||||
override fun forEachCaret(action: (VimCaret) -> Unit) {
|
||||
if (editor.vim.inBlockSelection) {
|
||||
action(IjVimCaret(editor.caretModel.primaryCaret))
|
||||
} else {
|
||||
editor.caretModel.runForEachCaret({
|
||||
if (it.isValid) {
|
||||
action(IjVimCaret(it))
|
||||
}
|
||||
}, false)
|
||||
try {
|
||||
editor.caretModel.runForEachCaret({
|
||||
if (it.isValid) {
|
||||
action(IjVimCaret(it))
|
||||
isFirstCaret = false
|
||||
}
|
||||
}, false)
|
||||
} finally {
|
||||
isFirstCaret = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {
|
||||
editor.caretModel.runForEachCaret({ action(IjVimCaret(it)) }, reverse)
|
||||
isReversingCarets = reverse
|
||||
try {
|
||||
editor.caretModel.runForEachCaret({
|
||||
action(IjVimCaret(it))
|
||||
isFirstCaret = false
|
||||
}, reverse)
|
||||
} finally {
|
||||
isFirstCaret = true
|
||||
isReversingCarets = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInForEachCaretScope(): Boolean {
|
||||
|
@ -9,6 +9,7 @@
|
||||
package org.jetbrains.plugins.ideavim.ex.implementation.variables
|
||||
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.newapi.vim
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -43,10 +44,12 @@ class RegisterVariableTest : VimTestCase() {
|
||||
configureByText("abcd")
|
||||
enterCommand("""vnoremap <expr> y '"' . v:register . 'y'""")
|
||||
typeText("vl\"zy")
|
||||
val register = injector.registerGroup.getRegisters()
|
||||
val vimEditor = fixture.editor.vim
|
||||
val context = injector.executionContextManager.getEditorExecutionContext(vimEditor)
|
||||
val register = injector.registerGroup.getRegisters(vimEditor, context)
|
||||
.filter { reg -> reg.name == 'z' }
|
||||
.first()
|
||||
assertEquals("ab", register.text)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -69,15 +69,10 @@ class InsertRegisterAction : VimActionHandler.SingleExecution() {
|
||||
*/
|
||||
@RWLockLabel.SelfSynchronized
|
||||
private fun insertRegister(editor: VimEditor, context: ExecutionContext, key: Char): Boolean {
|
||||
val register: Register? = injector.registerGroup.getRegister(editor, context, key)
|
||||
val register: Register? = injector.registerGroup.getRegister(key)
|
||||
if (register != null) {
|
||||
val textData = PutData.TextData(
|
||||
register.name,
|
||||
injector.clipboardManager.dumbCopiedText(register.text),
|
||||
SelectionType.CHARACTER_WISE
|
||||
)
|
||||
val putData =
|
||||
PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = true)
|
||||
val textData = PutData.TextData(register.text, SelectionType.CHARACTER_WISE, emptyList(), register.name)
|
||||
val putData = PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = true)
|
||||
injector.put.putText(editor, context, putData)
|
||||
return true
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ package com.maddyhome.idea.vim.action.copy
|
||||
import com.intellij.vim.annotations.CommandOrMotion
|
||||
import com.intellij.vim.annotations.Mode
|
||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.Argument
|
||||
@ -36,33 +35,40 @@ sealed class PutTextBaseAction(
|
||||
val count = operatorArguments.count1
|
||||
val sortedCarets = editor.sortedCarets()
|
||||
return if (sortedCarets.size > 1) {
|
||||
val caretToPutData = sortedCarets.associateWith { getPutDataForCaret(editor, context, it, count) }
|
||||
val putData = getPutData(count)
|
||||
|
||||
val splitText = putData.textData?.rawText?.split('\n')?.dropLastWhile(String::isEmpty)
|
||||
val caretToPutData = if (splitText != null && splitText.size == sortedCarets.size) {
|
||||
sortedCarets.mapIndexed { index, caret -> caret to putData.copy(textData = putData.textData.copy(rawText = splitText[splitText.lastIndex - index])) }.toMap()
|
||||
} else {
|
||||
sortedCarets.associateWith { putData }
|
||||
}
|
||||
|
||||
var result = true
|
||||
caretToPutData.forEach {
|
||||
result = injector.put.putTextForCaret(editor, it.key, context, it.value) && result
|
||||
}
|
||||
result
|
||||
} else {
|
||||
val putData = getPutDataForCaret(editor, context, sortedCarets.single(), count)
|
||||
injector.put.putText(editor, context, putData)
|
||||
injector.put.putText(editor, context, getPutData(count))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPutDataForCaret(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
caret: ImmutableVimCaret,
|
||||
count: Int,
|
||||
private fun getPutData(count: Int,
|
||||
): PutData {
|
||||
val registerService = injector.registerGroup
|
||||
val registerChar = if (caret.editor.carets().size == 1) {
|
||||
registerService.currentRegister
|
||||
} else {
|
||||
registerService.getCurrentRegisterForMulticaret()
|
||||
}
|
||||
val register = caret.registerStorage.getRegister(editor, context, registerChar)
|
||||
val textData = register?.let { TextData(register) }
|
||||
return PutData(textData, null, count, insertTextBeforeCaret, indent, caretAfterInsertedText, -1)
|
||||
return PutData(getRegisterTextData(), null, count, insertTextBeforeCaret, indent, caretAfterInsertedText, -1)
|
||||
}
|
||||
}
|
||||
|
||||
fun getRegisterTextData(): TextData? {
|
||||
val register = injector.registerGroup.getRegister(injector.registerGroup.currentRegister)
|
||||
return register?.let {
|
||||
TextData(
|
||||
register.text ?: injector.parser.toPrintableString(register.keys),
|
||||
register.type,
|
||||
register.transferableData,
|
||||
register.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,22 @@ sealed class PutVisualTextBaseAction(
|
||||
): Boolean {
|
||||
if (caretsAndSelections.isEmpty()) return false
|
||||
val count = cmd.count
|
||||
val caretToPutData =
|
||||
editor.sortedCarets().associateWith { getPutDataForCaret(editor, context, it, caretsAndSelections[it], count) }
|
||||
val sortedCarets =
|
||||
editor.sortedCarets()
|
||||
|
||||
val textData = getRegisterTextData()
|
||||
val splitText = textData?.rawText?.split('\n')?.dropLastWhile(String::isEmpty)
|
||||
|
||||
val caretToTextData = if (splitText != null && splitText.size == sortedCarets.size) {
|
||||
sortedCarets.mapIndexed { index, caret -> caret to textData.copy(rawText = splitText[splitText.lastIndex - index]) }.toMap()
|
||||
} else {
|
||||
sortedCarets.associateWith { textData }
|
||||
}
|
||||
|
||||
val caretToPutData = caretToTextData.mapValues { (caret, textData) ->
|
||||
getPutDataForCaret(textData, caret, caretsAndSelections[caret], count)
|
||||
}
|
||||
|
||||
injector.registerGroup.resetRegister()
|
||||
var result = true
|
||||
caretToPutData.forEach {
|
||||
@ -50,17 +64,11 @@ sealed class PutVisualTextBaseAction(
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getPutDataForCaret(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
|
||||
private fun getPutDataForCaret(textData: PutData.TextData?,
|
||||
caret: VimCaret,
|
||||
selection: VimSelection?,
|
||||
count: Int,
|
||||
): PutData {
|
||||
val lastRegisterChar = injector.registerGroup.lastRegisterChar
|
||||
val register = caret.registerStorage.getRegister(editor, context, lastRegisterChar)
|
||||
val textData = register?.let { PutData.TextData(register) }
|
||||
count: Int,): PutData {
|
||||
val visualSelection = selection?.let { PutData.VisualSelection(mapOf(caret to it), it.type) }
|
||||
return PutData(textData, visualSelection, count, insertTextBeforeCaret, indent, caretAfterInsertedText)
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
package com.maddyhome.idea.vim.api
|
||||
|
||||
import com.maddyhome.idea.vim.common.LiveRange
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.group.visual.VisualChange
|
||||
import com.maddyhome.idea.vim.group.visual.vimMoveBlockSelectionToOffset
|
||||
import com.maddyhome.idea.vim.group.visual.vimMoveSelectionToCaret
|
||||
@ -17,13 +16,11 @@ import com.maddyhome.idea.vim.handler.Motion
|
||||
import com.maddyhome.idea.vim.helper.RWLockLabel
|
||||
import com.maddyhome.idea.vim.helper.StrictMode
|
||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||
import com.maddyhome.idea.vim.register.Register
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
||||
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
||||
import com.maddyhome.idea.vim.state.mode.inCommandLineModeWithVisual
|
||||
import com.maddyhome.idea.vim.state.mode.inSelectMode
|
||||
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
/**
|
||||
* Immutable interface of the caret. Immutable caret is an important concept of Fleet.
|
||||
@ -65,7 +62,7 @@ interface ImmutableVimCaret {
|
||||
fun hasSelection(): Boolean
|
||||
|
||||
var lastSelectionInfo: SelectionInfo
|
||||
val registerStorage: CaretRegisterStorage
|
||||
val registerStorage: VimRegisterGroup
|
||||
val markStorage: LocalMarkStorage
|
||||
}
|
||||
|
||||
@ -149,36 +146,3 @@ fun VimCaret.moveToMotion(motion: Motion): VimCaret {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
interface CaretRegisterStorage {
|
||||
val caret: ImmutableVimCaret
|
||||
|
||||
/**
|
||||
* Stores text to caret's recordable (named/numbered/unnamed) register
|
||||
*/
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
fun storeText(editor: VimEditor, range: TextRange, type: SelectionType, isDelete: Boolean): Boolean
|
||||
fun storeText(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
* Gets text from caret's recordable register
|
||||
* If the register is not recordable - global text state will be returned
|
||||
*/
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.api.CaretRegisterStorage#getRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char)")
|
||||
fun getRegister(r: Char): Register?
|
||||
fun getRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register?
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.api.CaretRegisterStorage#setKeys(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, java.util.List<? extends javax.swing.KeyStroke>)")
|
||||
fun setKeys(register: Char, keys: List<KeyStroke>)
|
||||
fun setKeys(editor: VimEditor, context: ExecutionContext, register: Char, keys: List<KeyStroke>)
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.api.CaretRegisterStorage#saveRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, com.maddyhome.idea.vim.register.Register)")
|
||||
fun saveRegister(r: Char, register: Register)
|
||||
fun saveRegister(editor: VimEditor, context: ExecutionContext, r: Char, register: Register)
|
||||
}
|
||||
|
@ -8,106 +8,4 @@
|
||||
|
||||
package com.maddyhome.idea.vim.api
|
||||
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.register.Register
|
||||
import com.maddyhome.idea.vim.register.RegisterConstants
|
||||
import com.maddyhome.idea.vim.register.VimRegisterGroupBase
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
abstract class VimCaretBase : VimCaret
|
||||
|
||||
open class CaretRegisterStorageBase(override var caret: ImmutableVimCaret) : CaretRegisterStorage,
|
||||
VimRegisterGroupBase() {
|
||||
companion object {
|
||||
private const val ALLOWED_TO_STORE_REGISTERS = RegisterConstants.RECORDABLE_REGISTERS +
|
||||
RegisterConstants.SMALL_DELETION_REGISTER +
|
||||
RegisterConstants.BLACK_HOLE_REGISTER +
|
||||
RegisterConstants.LAST_INSERTED_TEXT_REGISTER +
|
||||
RegisterConstants.LAST_SEARCH_REGISTER
|
||||
}
|
||||
|
||||
override var lastRegisterChar: Char
|
||||
get() {
|
||||
return injector.registerGroup.lastRegisterChar
|
||||
}
|
||||
set(_) {}
|
||||
|
||||
override var isRegisterSpecifiedExplicitly: Boolean
|
||||
get() {
|
||||
return injector.registerGroup.isRegisterSpecifiedExplicitly
|
||||
}
|
||||
set(_) {}
|
||||
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
override fun storeText(editor: VimEditor, range: TextRange, type: SelectionType, isDelete: Boolean): Boolean {
|
||||
val context = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||
return storeText(editor, context, caret, range, type, isDelete)
|
||||
}
|
||||
|
||||
override fun storeText(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
): Boolean {
|
||||
val registerChar = if (caret.editor.carets().size == 1) currentRegister else getCurrentRegisterForMulticaret()
|
||||
if (caret.isPrimary) {
|
||||
val registerService = injector.registerGroup
|
||||
registerService.lastRegisterChar = registerChar
|
||||
return registerService.storeText(editor, context, caret, range, type, isDelete)
|
||||
} else {
|
||||
if (!ALLOWED_TO_STORE_REGISTERS.contains(registerChar)) {
|
||||
return false
|
||||
}
|
||||
val text = preprocessTextBeforeStoring(editor.getText(range), type)
|
||||
return storeTextInternal(editor, context, range, text, type, registerChar, isDelete)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRegister(r: Char): Register? {
|
||||
val editorStub = injector.fallbackWindow
|
||||
val contextStub = injector.executionContextManager.getEditorExecutionContext(editorStub)
|
||||
return getRegister(editorStub, contextStub, r)
|
||||
}
|
||||
|
||||
override fun getRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register? {
|
||||
if (caret.isPrimary || !RegisterConstants.RECORDABLE_REGISTERS.contains(r)) {
|
||||
return injector.registerGroup.getRegister(editor, context, r)
|
||||
}
|
||||
return super.getRegister(editor, context, r) ?: injector.registerGroup.getRegister(editor, context, r)
|
||||
}
|
||||
|
||||
override fun setKeys(register: Char, keys: List<KeyStroke>) {
|
||||
val editorStub = injector.fallbackWindow
|
||||
val contextStub = injector.executionContextManager.getEditorExecutionContext(editorStub)
|
||||
setKeys(editorStub, contextStub, register, keys)
|
||||
}
|
||||
|
||||
override fun setKeys(editor: VimEditor, context: ExecutionContext, register: Char, keys: List<KeyStroke>) {
|
||||
if (caret.isPrimary) {
|
||||
injector.registerGroup.setKeys(register, keys)
|
||||
}
|
||||
if (!RegisterConstants.RECORDABLE_REGISTERS.contains(register)) {
|
||||
return
|
||||
}
|
||||
return super.setKeys(register, keys)
|
||||
}
|
||||
|
||||
override fun saveRegister(r: Char, register: Register) {
|
||||
val editorStub = injector.fallbackWindow
|
||||
val contextStub = injector.executionContextManager.getEditorExecutionContext(editorStub)
|
||||
saveRegister(editorStub, contextStub, r, register)
|
||||
}
|
||||
|
||||
override fun saveRegister(editor: VimEditor, context: ExecutionContext, r: Char, register: Register) {
|
||||
if (caret.isPrimary) {
|
||||
injector.registerGroup.saveRegister(editor, context, r, register)
|
||||
}
|
||||
if (!RegisterConstants.RECORDABLE_REGISTERS.contains(r)) {
|
||||
return
|
||||
}
|
||||
return super.saveRegister(editor, context, r, register)
|
||||
}
|
||||
}
|
||||
|
@ -182,31 +182,41 @@ abstract class VimChangeGroupBase : VimChangeGroup {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val isInsertMode = editor.mode == Mode.INSERT || editor.mode == Mode.REPLACE
|
||||
val shouldYank = type != null && !isInsertMode && saveToRegister
|
||||
if (shouldYank && !caret.registerStorage.storeText(editor, context, updatedRange, type, isDelete = true)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val startOffsets = updatedRange.startOffsets
|
||||
val endOffsets = updatedRange.endOffsets
|
||||
for (i in updatedRange.size() - 1 downTo 0) {
|
||||
val (newRange, _) = editor.search(
|
||||
startOffsets[i] to endOffsets[i],
|
||||
val mode = editor.mode
|
||||
if (type == null ||
|
||||
(mode == Mode.INSERT || mode == Mode.REPLACE) ||
|
||||
!saveToRegister ||
|
||||
injector.registerGroup.storeText(
|
||||
editor,
|
||||
LineDeleteShift.NL_ON_END
|
||||
) ?: continue
|
||||
injector.application.runWriteAction {
|
||||
context,
|
||||
caret,
|
||||
updatedRange,
|
||||
type,
|
||||
true,
|
||||
!editor.isFirstCaret,
|
||||
editor.isReversingCarets
|
||||
)
|
||||
) {
|
||||
val startOffsets = updatedRange.startOffsets
|
||||
val endOffsets = updatedRange.endOffsets
|
||||
for (i in updatedRange.size() - 1 downTo 0) {
|
||||
val (newRange, _) = editor.search(
|
||||
startOffsets[i] to endOffsets[i],
|
||||
editor,
|
||||
LineDeleteShift.NL_ON_END
|
||||
) ?: continue
|
||||
injector.application.runWriteAction {
|
||||
editor.deleteString(TextRange(newRange.first, newRange.second))
|
||||
}
|
||||
}
|
||||
if (type != null) {
|
||||
val start = updatedRange.startOffset
|
||||
injector.markService.setMark(caret, MARK_CHANGE_POS, start)
|
||||
injector.markService.setChangeMarks(caret, TextRange(start, start + 1))
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (type != null) {
|
||||
val start = updatedRange.startOffset
|
||||
injector.markService.setMark(caret, MARK_CHANGE_POS, start)
|
||||
injector.markService.setChangeMarks(caret, TextRange(start, start + 1))
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,7 +111,8 @@ interface VimEditor {
|
||||
* This method should perform caret merging after the operations. This is similar to IJ runForEachCaret
|
||||
* TODO review
|
||||
*/
|
||||
|
||||
val isFirstCaret: Boolean
|
||||
val isReversingCarets: Boolean
|
||||
fun forEachCaret(action: (VimCaret) -> Unit)
|
||||
fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean = false)
|
||||
fun isInForEachCaretScope(): Boolean
|
||||
|
@ -17,8 +17,6 @@ import com.maddyhome.idea.vim.common.VimListenersNotifier
|
||||
import com.maddyhome.idea.vim.diagnostic.VimLogger
|
||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
||||
import com.maddyhome.idea.vim.impl.state.VimStateMachineImpl
|
||||
import com.maddyhome.idea.vim.register.VimRegisterGroup
|
||||
import com.maddyhome.idea.vim.register.VimRegisterGroupBase
|
||||
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
||||
import com.maddyhome.idea.vim.vimscript.services.VimVariableServiceBase
|
||||
@ -28,7 +26,6 @@ import com.maddyhome.idea.vim.yank.YankGroupBase
|
||||
abstract class VimInjectorBase : VimInjector {
|
||||
companion object {
|
||||
val logger: VimLogger by lazy { vimLogger<VimInjectorBase>() }
|
||||
val registerGroupStub: VimRegisterGroupBase by lazy { object : VimRegisterGroupBase() {} }
|
||||
}
|
||||
|
||||
override val vimState: VimStateMachine = VimStateMachineImpl()
|
||||
@ -38,8 +35,6 @@ abstract class VimInjectorBase : VimInjector {
|
||||
|
||||
override val variableService: VariableService by lazy { object : VimVariableServiceBase() {} }
|
||||
|
||||
override val registerGroup: VimRegisterGroup by lazy { registerGroupStub }
|
||||
override val registerGroupIfCreated: VimRegisterGroup? by lazy { registerGroupStub }
|
||||
override val messages: VimMessages by lazy { VimMessagesStub() }
|
||||
override val processGroup: VimProcessGroup by lazy { VimProcessGroupStub() }
|
||||
override val application: VimApplication by lazy { VimApplicationStub() }
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
package com.maddyhome.idea.vim.common
|
||||
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.state.mode.Mode
|
||||
@ -72,9 +71,9 @@ class VimListenersNotifier {
|
||||
isReplaceCharListeners.forEach { it.isReplaceCharChanged(editor) }
|
||||
}
|
||||
|
||||
fun notifyYankPerformed(caretToRange: Map<ImmutableVimCaret, TextRange>) {
|
||||
fun notifyYankPerformed(editor: VimEditor, range: TextRange) {
|
||||
if (!injector.enabler.isEnabled()) return // we remove all the listeners when turning the plugin off, but let's do it just in case
|
||||
yankListeners.forEach { it.yankPerformed(caretToRange) }
|
||||
yankListeners.forEach { it.yankPerformed(editor, range) }
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
package com.maddyhome.idea.vim.common
|
||||
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
|
||||
interface VimYankListener {
|
||||
fun yankPerformed(caretToRange: Map<ImmutableVimCaret, TextRange>)
|
||||
}
|
||||
fun yankPerformed(editor: VimEditor, range: TextRange)
|
||||
}
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
package com.maddyhome.idea.vim.put
|
||||
|
||||
import com.maddyhome.idea.vim.common.VimCopiedText
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
|
||||
data class ProcessedTextData(
|
||||
val registerChar: Char?,
|
||||
val copiedText: VimCopiedText,
|
||||
val text: String,
|
||||
val typeInRegister: SelectionType,
|
||||
val transferableData: List<Any>,
|
||||
val registerChar: Char?,
|
||||
)
|
||||
|
@ -9,9 +9,7 @@
|
||||
package com.maddyhome.idea.vim.put
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.common.VimCopiedText
|
||||
import com.maddyhome.idea.vim.group.visual.VimSelection
|
||||
import com.maddyhome.idea.vim.register.Register
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
|
||||
/**
|
||||
@ -35,12 +33,9 @@ data class PutData(
|
||||
)
|
||||
|
||||
data class TextData(
|
||||
val registerChar: Char?,
|
||||
val copiedText: VimCopiedText,
|
||||
val rawText: String?,
|
||||
val typeInRegister: SelectionType,
|
||||
) {
|
||||
constructor(register: Register) : this(register.name, register.copiedText, register.type)
|
||||
|
||||
val rawText = copiedText.text // TODO do not call it raw text...
|
||||
}
|
||||
val transferableData: List<Any>,
|
||||
val registerChar: Char?,
|
||||
)
|
||||
}
|
||||
|
@ -141,7 +141,6 @@ abstract class VimPutBase : VimPut {
|
||||
|
||||
if (data.visualSelection?.typeInEditor?.isLine == true && data.textData.typeInRegister.isChar) text += "\n"
|
||||
|
||||
// TODO: shouldn't it be adjusted when we are storing the text?
|
||||
if (data.textData.typeInRegister.isLine && text.isNotEmpty() && text.last() != '\n') text += '\n'
|
||||
|
||||
if (data.textData.typeInRegister.isChar && text.lastOrNull() == '\n' && data.visualSelection?.typeInEditor?.isLine == false) {
|
||||
@ -150,9 +149,10 @@ abstract class VimPutBase : VimPut {
|
||||
}
|
||||
|
||||
return ProcessedTextData(
|
||||
data.textData.registerChar,
|
||||
data.textData.copiedText.updateText(text),
|
||||
text,
|
||||
data.textData.typeInRegister,
|
||||
data.textData.transferableData,
|
||||
data.textData.registerChar,
|
||||
)
|
||||
}
|
||||
|
||||
@ -512,7 +512,7 @@ abstract class VimPutBase : VimPut {
|
||||
startOffsets.forEach { startOffset ->
|
||||
val selectionType = data.visualSelection?.typeInEditor ?: SelectionType.CHARACTER_WISE
|
||||
val (endOffset, updatedCaret) = putTextInternal(
|
||||
editor, updated, context, text.copiedText.text, text.typeInRegister, selectionType,
|
||||
editor, updated, context, text.text, text.typeInRegister, selectionType,
|
||||
startOffset, data.count, data.indent, data.caretAfterInsertedText,
|
||||
)
|
||||
updated = updatedCaret
|
||||
|
@ -633,7 +633,13 @@ class VimRegex(pattern: String) {
|
||||
override fun carets(): List<VimCaret> = emptyList()
|
||||
|
||||
override fun nativeCarets(): List<VimCaret> = emptyList()
|
||||
|
||||
override val isFirstCaret: Boolean
|
||||
get() = false
|
||||
|
||||
override val isReversingCarets: Boolean
|
||||
get() = false
|
||||
|
||||
override fun forEachCaret(action: (VimCaret) -> Unit) {}
|
||||
|
||||
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {}
|
||||
|
@ -8,32 +8,86 @@
|
||||
package com.maddyhome.idea.vim.register
|
||||
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.common.VimCopiedText
|
||||
import com.maddyhome.idea.vim.helper.EngineStringHelper
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
// TODO should we prefer keys over text, as they are more informative?
|
||||
// TODO e.g. could be both <Esc> and <C-[> after trying to restore original keys
|
||||
data class Register(
|
||||
val name: Char,
|
||||
val copiedText: VimCopiedText,
|
||||
val type: SelectionType,
|
||||
) {
|
||||
val text = copiedText.text
|
||||
val keys get() = injector.parser.stringToKeys(copiedText.text)
|
||||
val printableString: String =
|
||||
EngineStringHelper.toPrintableCharacters(keys) // should be the same as [text], but we can't render control notation properly
|
||||
class Register {
|
||||
var name: Char
|
||||
val type: SelectionType
|
||||
val keys: MutableList<KeyStroke>
|
||||
val transferableData: MutableList<out Any>
|
||||
val rawText: String?
|
||||
|
||||
constructor(name: Char, type: SelectionType, keys: MutableList<KeyStroke>) : this(
|
||||
name,
|
||||
injector.clipboardManager.dumbCopiedText(injector.parser.toPrintableString(keys)),
|
||||
type
|
||||
)
|
||||
// constructor(name: Char, type: SelectionType, text: String, transferableData: MutableList<out Any>) : this(name, text, type, transferableData)
|
||||
constructor(name: Char, type: SelectionType, keys: MutableList<KeyStroke>) {
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.keys = keys
|
||||
this.transferableData = mutableListOf()
|
||||
this.rawText = text
|
||||
}
|
||||
|
||||
override fun toString(): String = "@$name = $printableString"
|
||||
constructor(
|
||||
name: Char,
|
||||
type: SelectionType,
|
||||
text: String,
|
||||
transferableData: MutableList<out Any>,
|
||||
) {
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.keys = injector.parser.stringToKeys(text).toMutableList()
|
||||
this.transferableData = transferableData
|
||||
this.rawText = text
|
||||
}
|
||||
|
||||
constructor(
|
||||
name: Char,
|
||||
type: SelectionType,
|
||||
text: String,
|
||||
transferableData: MutableList<out Any>,
|
||||
rawText: String,
|
||||
) {
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.keys = injector.parser.stringToKeys(text).toMutableList()
|
||||
this.transferableData = transferableData
|
||||
this.rawText = rawText
|
||||
}
|
||||
|
||||
val text: String?
|
||||
get() {
|
||||
val builder = StringBuilder()
|
||||
for (key in keys) {
|
||||
val c = key.keyChar
|
||||
if (c == KeyEvent.CHAR_UNDEFINED) {
|
||||
return null
|
||||
}
|
||||
builder.append(c)
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
val printableString: String
|
||||
get() = EngineStringHelper.toPrintableCharacters(keys) // should be the same as [text], but we can't render control notation properly
|
||||
|
||||
/**
|
||||
* Append the supplied text to any existing text.
|
||||
*/
|
||||
fun addTextAndResetTransferableData(text: String) {
|
||||
addKeys(injector.parser.stringToKeys(text))
|
||||
transferableData.clear()
|
||||
}
|
||||
|
||||
fun prependTextAndResetTransferableData(text: String) {
|
||||
this.keys.addAll(0, injector.parser.stringToKeys(text))
|
||||
transferableData.clear()
|
||||
}
|
||||
|
||||
fun addKeys(keys: List<KeyStroke>) {
|
||||
this.keys.addAll(keys)
|
||||
}
|
||||
|
||||
object KeySorter : Comparator<Register> {
|
||||
@NonNls
|
||||
@ -44,27 +98,3 @@ data class Register(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagine you yanked two lines and have the following content in your register a - foo\nbar\n (register type is line-wise)
|
||||
* Now, there are three different ways to append content, each with a different outcome:
|
||||
* - If you append a macro qAbazq, you'll get foo\nbarbaz\n in register `a` and it stays line-wise
|
||||
* - If you use Vim script and execute let @A = "baz", the result will be foo\nbar\nbaz and the register becomes character-wise
|
||||
* - If you copy "baz" to register A, it becomes foo\nbar\nbaz\n and stays line-wise
|
||||
*
|
||||
* At the moment, we will stick to the third option to not overcomplicate the plugin
|
||||
* (until there is a user who notices the difference)
|
||||
*/
|
||||
fun Register.addText(text: String): Register {
|
||||
return when (this.type) {
|
||||
SelectionType.CHARACTER_WISE -> {
|
||||
Register(this.name, injector.clipboardManager.dumbCopiedText(this.text + text), SelectionType.CHARACTER_WISE) // todo it's empty for historical reasons, but should we really clear transferable data?
|
||||
}
|
||||
SelectionType.LINE_WISE -> {
|
||||
Register(this.name, injector.clipboardManager.dumbCopiedText(this.text + text + (if (text.endsWith('\n')) "" else "\n")), SelectionType.LINE_WISE) // todo it's empty for historical reasons, but should we really clear transferable data?
|
||||
}
|
||||
SelectionType.BLOCK_WISE -> {
|
||||
Register(this.name, injector.clipboardManager.dumbCopiedText(this.text + "\n" + text), SelectionType.BLOCK_WISE) // todo it's empty for historical reasons, but should we really clear transferable data?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,13 @@ import javax.swing.KeyStroke
|
||||
|
||||
interface VimRegisterGroup {
|
||||
|
||||
/**
|
||||
* Get the last register selected by the user
|
||||
*
|
||||
* @return The register, null if no such register
|
||||
*/
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getLastRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext)")
|
||||
val lastRegister: Register?
|
||||
var lastRegisterChar: Char
|
||||
val currentRegister: Char
|
||||
|
||||
@ -32,7 +39,6 @@ interface VimRegisterGroup {
|
||||
val isRegisterSpecifiedExplicitly: Boolean
|
||||
val defaultRegister: Char
|
||||
|
||||
fun getLastRegister(editor: VimEditor, context: ExecutionContext): Register?
|
||||
fun isValid(reg: Char): Boolean
|
||||
fun selectRegister(reg: Char): Boolean
|
||||
fun resetRegister()
|
||||
@ -42,15 +48,6 @@ interface VimRegisterGroup {
|
||||
fun isRegisterWritable(reg: Char): Boolean
|
||||
|
||||
/** Store text into the last register. */
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, com.maddyhome.idea.vim.api.ImmutableVimCaret, com.maddyhome.idea.vim.common.TextRange, com.maddyhome.idea.vim.state.mode.SelectionType, boolean)")
|
||||
fun storeText(
|
||||
editor: VimEditor,
|
||||
caret: ImmutableVimCaret,
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
): Boolean
|
||||
|
||||
fun storeText(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
@ -58,31 +55,20 @@ interface VimRegisterGroup {
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
forceAppend: Boolean = false,
|
||||
prependInsteadOfAppend: Boolean = false
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
* Stores text to any writable register (used for the let command)
|
||||
*/
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, java.lang.String)")
|
||||
fun storeText(register: Char, text: String): Boolean
|
||||
fun storeText(editor: VimEditor, context: ExecutionContext, register: Char, text: String): Boolean
|
||||
|
||||
/**
|
||||
* Stores text to any writable register (used for multicaret tests)
|
||||
*/
|
||||
@TestOnly
|
||||
// todo better tests
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, java.lang.String, com.maddyhome.idea.vim.state.mode.SelectionType)")
|
||||
fun storeText(register: Char, text: String, selectionType: SelectionType): Boolean
|
||||
|
||||
@TestOnly
|
||||
fun storeText(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
register: Char,
|
||||
text: String,
|
||||
selectionType: SelectionType,
|
||||
): Boolean
|
||||
fun storeText(editor: VimEditor, context: ExecutionContext, register: Char, text: String, selectionType: SelectionType): Boolean
|
||||
|
||||
/**
|
||||
* Stores text, character wise, in the given special register
|
||||
@ -98,29 +84,17 @@ interface VimRegisterGroup {
|
||||
* preferable to yank from the fixture editor.
|
||||
*/
|
||||
fun storeTextSpecial(register: Char, text: String): Boolean
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char)")
|
||||
fun getRegister(r: Char): Register?
|
||||
fun getRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register?
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getRegisters(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext)")
|
||||
fun getRegisters(): List<Register>
|
||||
fun getRegisters(editor: VimEditor, context: ExecutionContext): List<Register>
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#saveRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, com.maddyhome.idea.vim.register.Register)")
|
||||
fun saveRegister(r: Char, register: Register)
|
||||
fun saveRegister(editor: VimEditor, context: ExecutionContext, r: Char, register: Register)
|
||||
fun startRecording(register: Char): Boolean
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getPlaybackRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char)")
|
||||
fun getPlaybackRegister(r: Char): Register?
|
||||
fun getPlaybackRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register?
|
||||
fun recordText(text: String)
|
||||
fun setKeys(register: Char, keys: List<KeyStroke>)
|
||||
fun setKeys(register: Char, keys: List<KeyStroke>, type: SelectionType)
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#finishRecording(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext)")
|
||||
fun finishRecording()
|
||||
fun finishRecording(editor: VimEditor, context: ExecutionContext)
|
||||
fun getCurrentRegisterForMulticaret(): Char // `set clipbaard+=unnamedplus` should not make system register the default one when working with multiple carets VIM-2804
|
||||
fun isSystemClipboard(register: Char): Boolean
|
||||
|
@ -17,7 +17,6 @@ import com.maddyhome.idea.vim.api.globalOptions
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.Argument
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.common.VimCopiedText
|
||||
import com.maddyhome.idea.vim.diagnostic.VimLogger
|
||||
import com.maddyhome.idea.vim.diagnostic.debug
|
||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
||||
@ -75,9 +74,13 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
override val defaultRegister: Char
|
||||
get() = defaultRegisterChar
|
||||
|
||||
override fun getLastRegister(editor: VimEditor, context: ExecutionContext): Register? {
|
||||
return getRegister(editor, context, lastRegisterChar)
|
||||
}
|
||||
/**
|
||||
* Get the last register selected by the user
|
||||
*
|
||||
* @return The register, null if no such register
|
||||
*/
|
||||
override val lastRegister: Register?
|
||||
get() = getRegister(lastRegisterChar)
|
||||
|
||||
private val onClipboardChanged: () -> Unit = {
|
||||
val clipboardOptionValue = injector.globalOptions().clipboard
|
||||
@ -113,13 +116,20 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
return if (isValid(reg)) {
|
||||
isRegisterSpecifiedExplicitly = true
|
||||
lastRegisterChar = reg
|
||||
logger.debug { "register selected: $lastRegisterChar" }
|
||||
logger.debug { "register selected: $lastRegister" }
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRegister(r: Char): Register? {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return getRegister(dummyEditor, dummyContext, r)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the selected register back to the default register.
|
||||
*/
|
||||
@ -175,6 +185,8 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
type: SelectionType,
|
||||
register: Char,
|
||||
isDelete: Boolean,
|
||||
forceAppend: Boolean,
|
||||
prependInsteadOfAppend: Boolean,
|
||||
): Boolean {
|
||||
// Null register doesn't get saved, but acts like it was
|
||||
if (lastRegisterChar == BLACK_HOLE_REGISTER) return true
|
||||
@ -193,50 +205,62 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
end = t
|
||||
}
|
||||
|
||||
val copiedText =
|
||||
if (start != -1) { // FIXME: so, we had invalid ranges all the time?.. I've never handled such cases
|
||||
injector.clipboardManager.collectCopiedText(editor, context, range, text)
|
||||
} else {
|
||||
injector.clipboardManager.dumbCopiedText(text)
|
||||
}
|
||||
logger.debug { "Copy to '$lastRegisterChar' with copied text: $copiedText" }
|
||||
// If this is an uppercase register, we need to append the text to the corresponding lowercase register
|
||||
if (Character.isUpperCase(register)) {
|
||||
val transferableData: List<Any> =
|
||||
if (start != -1) injector.clipboardManager.getTransferableData(editor, range) else ArrayList()
|
||||
var processedText =
|
||||
if (start != -1) injector.clipboardManager.preprocessText(editor, range, text, transferableData) else text
|
||||
logger.debug {
|
||||
val transferableClasses = transferableData.joinToString(",") { it.javaClass.name }
|
||||
"Copy to '$lastRegister' with transferable data: $transferableClasses"
|
||||
}
|
||||
if (Character.isUpperCase(register) || forceAppend) {
|
||||
if (forceAppend && type == SelectionType.CHARACTER_WISE) {
|
||||
processedText = if (prependInsteadOfAppend)
|
||||
processedText + '\n'
|
||||
else
|
||||
'\n' + processedText
|
||||
}
|
||||
val lreg = Character.toLowerCase(register)
|
||||
val r = myRegisters[lreg]
|
||||
// Append the text if the lowercase register existed
|
||||
if (r != null) {
|
||||
myRegisters[lreg] = r.addText(copiedText.text)
|
||||
if (prependInsteadOfAppend) {
|
||||
r.prependTextAndResetTransferableData(processedText)
|
||||
}
|
||||
else {
|
||||
r.addTextAndResetTransferableData(processedText)
|
||||
}
|
||||
} else {
|
||||
myRegisters[lreg] = Register(lreg, copiedText, type)
|
||||
logger.debug { "register '$register' contains: \"$copiedText\"" }
|
||||
myRegisters[lreg] = Register(lreg, type, processedText, ArrayList(transferableData))
|
||||
logger.debug { "register '$register' contains: \"$processedText\"" }
|
||||
} // Set the text if the lowercase register didn't exist yet
|
||||
} else {
|
||||
myRegisters[register] = Register(register, copiedText, type)
|
||||
logger.debug { "register '$register' contains: \"$copiedText\"" }
|
||||
myRegisters[register] = Register(register, type, processedText, ArrayList(transferableData))
|
||||
logger.debug { "register '$register' contains: \"$processedText\"" }
|
||||
} // Put the text in the specified register
|
||||
|
||||
if (register == CLIPBOARD_REGISTER) {
|
||||
injector.clipboardManager.setClipboardContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setClipboardText(processedText, text, ArrayList(transferableData))
|
||||
if (!isRegisterSpecifiedExplicitly && !isDelete && isPrimaryRegisterSupported() && OptionConstants.clipboard_unnamedplus in injector.globalOptions().clipboard) {
|
||||
injector.clipboardManager.setPrimaryContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setPrimaryText(processedText, text, ArrayList(transferableData))
|
||||
}
|
||||
}
|
||||
if (register == PRIMARY_REGISTER) {
|
||||
if (isPrimaryRegisterSupported()) {
|
||||
injector.clipboardManager.setPrimaryContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setPrimaryText(processedText, text, ArrayList(transferableData))
|
||||
if (!isRegisterSpecifiedExplicitly && !isDelete && OptionConstants.clipboard_unnamed in injector.globalOptions().clipboard) {
|
||||
injector.clipboardManager.setClipboardContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setClipboardText(processedText, text, ArrayList(transferableData))
|
||||
}
|
||||
} else {
|
||||
injector.clipboardManager.setClipboardContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setClipboardText(processedText, text, ArrayList(transferableData))
|
||||
}
|
||||
}
|
||||
|
||||
// Also add it to the unnamed register if the default wasn't specified
|
||||
if (register != UNNAMED_REGISTER && ".:/".indexOf(register) == -1) {
|
||||
myRegisters[UNNAMED_REGISTER] = Register(UNNAMED_REGISTER, copiedText, type)
|
||||
logger.debug { "register '$UNNAMED_REGISTER' contains: \"$copiedText\"" }
|
||||
myRegisters[UNNAMED_REGISTER] = Register(UNNAMED_REGISTER, type, processedText, ArrayList(transferableData))
|
||||
logger.debug { "register '$UNNAMED_REGISTER' contains: \"$processedText\"" }
|
||||
}
|
||||
|
||||
if (isDelete) {
|
||||
@ -256,44 +280,26 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
while (d >= '1') {
|
||||
val t = myRegisters[d]
|
||||
if (t != null) {
|
||||
val incName = (d.code + 1).toChar()
|
||||
myRegisters[incName] = Register(incName, t.copiedText, t.type)
|
||||
t.name = (d.code + 1).toChar()
|
||||
myRegisters[(d.code + 1).toChar()] = t
|
||||
}
|
||||
d--
|
||||
}
|
||||
myRegisters['1'] = Register('1', copiedText, type)
|
||||
myRegisters['1'] = Register('1', type, processedText, ArrayList(transferableData))
|
||||
}
|
||||
|
||||
// Deletes smaller than one line and without specified register go the the "-" register
|
||||
if (smallInlineDeletion && register == defaultRegister) {
|
||||
myRegisters[SMALL_DELETION_REGISTER] =
|
||||
Register(SMALL_DELETION_REGISTER, copiedText, type)
|
||||
Register(SMALL_DELETION_REGISTER, type, processedText, ArrayList(transferableData))
|
||||
}
|
||||
} else if (register == defaultRegister) {
|
||||
myRegisters['0'] = Register('0', copiedText, type)
|
||||
logger.debug { "register '0' contains: \"$copiedText\"" }
|
||||
myRegisters['0'] = Register('0', type, processedText, ArrayList(transferableData))
|
||||
logger.debug { "register '0' contains: \"$processedText\"" }
|
||||
} // Yanks also go to register 0 if the default register was used
|
||||
return true
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, com.maddyhome.idea.vim.api.ImmutableVimCaret, com.maddyhome.idea.vim.common.TextRange, com.maddyhome.idea.vim.state.mode.SelectionType, boolean)")
|
||||
override fun storeText(
|
||||
editor: VimEditor,
|
||||
caret: ImmutableVimCaret,
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
): Boolean {
|
||||
return storeText(
|
||||
editor,
|
||||
injector.executionContextManager.getEditorExecutionContext(editor),
|
||||
caret,
|
||||
range,
|
||||
type,
|
||||
isDelete
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store text into the last register.
|
||||
*
|
||||
@ -310,10 +316,12 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
isDelete: Boolean,
|
||||
forceAppend: Boolean,
|
||||
prependInsteadOfAppend: Boolean
|
||||
): Boolean {
|
||||
if (isRegisterWritable()) {
|
||||
val text = preprocessTextBeforeStoring(editor.getText(range), type)
|
||||
return storeTextInternal(editor, context, range, text, type, lastRegisterChar, isDelete)
|
||||
return storeTextInternal(editor, context, range, text, type, lastRegisterChar, isDelete, forceAppend, prependInsteadOfAppend)
|
||||
}
|
||||
|
||||
return false
|
||||
@ -348,68 +356,36 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
if (READONLY_REGISTERS.indexOf(register) == -1 && register != LAST_SEARCH_REGISTER && register != UNNAMED_REGISTER) {
|
||||
return false
|
||||
}
|
||||
myRegisters[register] = Register(
|
||||
register,
|
||||
injector.clipboardManager.dumbCopiedText(text),
|
||||
myRegisters[register] = Register(register,
|
||||
SelectionType.CHARACTER_WISE
|
||||
) // TODO why transferable data is not collected?
|
||||
, text, ArrayList())
|
||||
logger.debug { "register '$register' contains: \"$text\"" }
|
||||
return true
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char)")
|
||||
override fun getRegister(r: Char): Register? {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return getRegister(dummyEditor, dummyContext, r)
|
||||
override fun storeText(editor: VimEditor, context: ExecutionContext, register: Char, text: String): Boolean {
|
||||
return storeText(editor, context, register, text, SelectionType.CHARACTER_WISE)
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, java.lang.String, com.maddyhome.idea.vim.state.mode.SelectionType)")
|
||||
override fun storeText(register: Char, text: String, selectionType: SelectionType): Boolean {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return storeText(dummyEditor, dummyContext, register, text, selectionType)
|
||||
}
|
||||
|
||||
override fun storeText(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
register: Char,
|
||||
text: String,
|
||||
selectionType: SelectionType,
|
||||
|
||||
override fun storeText(editor: VimEditor, context: ExecutionContext, register: Char, text: String, selectionType: SelectionType,
|
||||
): Boolean {
|
||||
if (!WRITABLE_REGISTERS.contains(register)) {
|
||||
return false
|
||||
}
|
||||
logger.debug { "register '$register' contains: \"$text\"" }
|
||||
val oldRegister = getRegister(editor, context, register.lowercaseChar())
|
||||
val newRegister = if (register.isUpperCase() && oldRegister != null) {
|
||||
oldRegister.addText(text)
|
||||
val textToStore = if (register.isUpperCase()) {
|
||||
(getRegister(register.lowercaseChar())?.rawText ?: "") + text
|
||||
} else {
|
||||
Register(
|
||||
register,
|
||||
injector.clipboardManager.dumbCopiedText(text),
|
||||
selectionType
|
||||
) // FIXME why don't we collect transferable data?
|
||||
text
|
||||
}
|
||||
saveRegister(editor, context, register, newRegister)
|
||||
val reg = Register(register, selectionType, textToStore, ArrayList())
|
||||
saveRegister(editor, context, register, reg)
|
||||
if (register == '/') {
|
||||
injector.searchGroup.lastSearchPattern = text // todo we should not have this field if we have the "/" register
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#storeText(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, java.lang.String)")
|
||||
override fun storeText(register: Char, text: String): Boolean {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return storeText(dummyEditor, dummyContext, register, text)
|
||||
}
|
||||
|
||||
override fun storeText(editor: VimEditor, context: ExecutionContext, register: Char, text: String): Boolean {
|
||||
return storeText(editor, context, register, text, SelectionType.CHARACTER_WISE)
|
||||
}
|
||||
|
||||
private fun guessSelectionType(text: String): SelectionType {
|
||||
return if (text.endsWith("\n")) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
|
||||
}
|
||||
@ -421,10 +397,10 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
* @param r - the register character corresponding to either the primary selection (*) or clipboard selection (+)
|
||||
* @return the content of the selection, if available, otherwise null
|
||||
*/
|
||||
private fun refreshClipboardRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register? {
|
||||
private fun refreshClipboardRegister(r: Char): Register? {
|
||||
return when (r) {
|
||||
PRIMARY_REGISTER -> refreshPrimaryRegister(editor, context)
|
||||
CLIPBOARD_REGISTER -> refreshClipboardRegister(editor, context)
|
||||
PRIMARY_REGISTER -> refreshPrimaryRegister()
|
||||
CLIPBOARD_REGISTER -> refreshClipboardRegister()
|
||||
else -> throw RuntimeException("Clipboard register expected, got $r")
|
||||
}
|
||||
}
|
||||
@ -433,56 +409,60 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
return System.getenv("DISPLAY") != null && injector.systemInfoService.isXWindow
|
||||
}
|
||||
|
||||
private fun setSystemPrimaryRegisterText(editor: VimEditor, context: ExecutionContext, copiedText: VimCopiedText) {
|
||||
logger.trace("Setting text: $copiedText to primary selection...")
|
||||
private fun setSystemPrimaryRegisterText(text: String, rawText: String, transferableData: List<Any>) {
|
||||
logger.trace("Setting text: $text to primary selection...")
|
||||
if (isPrimaryRegisterSupported()) {
|
||||
try {
|
||||
injector.clipboardManager.setPrimaryContent(editor, context, copiedText)
|
||||
injector.clipboardManager.setPrimaryText(text, rawText, transferableData)
|
||||
} catch (e: Exception) {
|
||||
logger.warn("False positive X11 primary selection support")
|
||||
logger.trace("Setting text to primary selection failed. Setting it to clipboard selection instead")
|
||||
setSystemClipboardRegisterText(editor, context, copiedText)
|
||||
setSystemClipboardRegisterText(text, rawText, transferableData)
|
||||
}
|
||||
} else {
|
||||
logger.trace("X11 primary selection is not supporting. Setting clipboard selection instead")
|
||||
setSystemClipboardRegisterText(editor, context, copiedText)
|
||||
setSystemClipboardRegisterText(text, rawText, transferableData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setSystemClipboardRegisterText(editor: VimEditor, context: ExecutionContext, copiedText: VimCopiedText) {
|
||||
injector.clipboardManager.setClipboardContent(editor, context, copiedText)
|
||||
private fun setSystemClipboardRegisterText(text: String, rawText: String, transferableData: List<Any>) {
|
||||
injector.clipboardManager.setClipboardText(text, rawText, transferableData)
|
||||
}
|
||||
|
||||
private fun refreshPrimaryRegister(editor: VimEditor, context: ExecutionContext): Register? {
|
||||
private fun refreshPrimaryRegister(): Register? {
|
||||
logger.trace("Syncing cached primary selection value..")
|
||||
if (!isPrimaryRegisterSupported()) {
|
||||
logger.trace("X11 primary selection is not supported. Syncing clipboard selection..")
|
||||
return refreshClipboardRegister(editor, context)
|
||||
return refreshClipboardRegister()
|
||||
}
|
||||
try {
|
||||
val clipboardData = injector.clipboardManager.getPrimaryContent(editor, context) ?: return null
|
||||
val clipboardData = injector.clipboardManager.getPrimaryTextAndTransferableData() ?: return null
|
||||
val currentRegister = myRegisters[PRIMARY_REGISTER]
|
||||
if (currentRegister != null && clipboardData.text == currentRegister.text) {
|
||||
val text = clipboardData.first
|
||||
val transferableData = clipboardData.second?.toMutableList()
|
||||
if (currentRegister != null && text == currentRegister.text) {
|
||||
return currentRegister
|
||||
}
|
||||
return Register(PRIMARY_REGISTER, clipboardData, guessSelectionType(clipboardData.text))
|
||||
return transferableData?.let { Register(PRIMARY_REGISTER, guessSelectionType(text), text, it) }
|
||||
} catch (e: Exception) {
|
||||
logger.warn("False positive X11 primary selection support")
|
||||
logger.trace("Syncing primary selection failed. Syncing clipboard selection instead")
|
||||
return refreshClipboardRegister(editor, context)
|
||||
return refreshClipboardRegister()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshClipboardRegister(editor: VimEditor, context: ExecutionContext): Register? {
|
||||
private fun refreshClipboardRegister(): Register? {
|
||||
// for some reason non-X systems use PRIMARY_REGISTER as a clipboard storage
|
||||
val systemAwareClipboardRegister = if (isPrimaryRegisterSupported()) CLIPBOARD_REGISTER else PRIMARY_REGISTER
|
||||
|
||||
val clipboardData = injector.clipboardManager.getClipboardContent(editor, context) ?: return null
|
||||
val clipboardData = injector.clipboardManager.getClipboardTextAndTransferableData() ?: return null
|
||||
val currentRegister = myRegisters[systemAwareClipboardRegister]
|
||||
if (currentRegister != null && clipboardData.text == currentRegister.text) {
|
||||
val text = clipboardData.first
|
||||
val transferableData = clipboardData.second?.toMutableList()
|
||||
if (currentRegister != null && text == currentRegister.text) {
|
||||
return currentRegister
|
||||
}
|
||||
return Register(systemAwareClipboardRegister, clipboardData, guessSelectionType(clipboardData.text))
|
||||
return transferableData?.let { Register(systemAwareClipboardRegister, guessSelectionType(text), text, it) }
|
||||
}
|
||||
|
||||
override fun getRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register? {
|
||||
@ -492,50 +472,35 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
myR = Character.toLowerCase(myR)
|
||||
}
|
||||
return if (CLIPBOARD_REGISTERS.indexOf(myR) >= 0) refreshClipboardRegister(
|
||||
editor,
|
||||
context,
|
||||
myR
|
||||
) else myRegisters[myR]
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getRegisters(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext)")
|
||||
override fun getRegisters(): List<Register> {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return getRegisters(dummyEditor, dummyContext)
|
||||
myR) else myRegisters[myR]
|
||||
}
|
||||
|
||||
override fun getRegisters(editor: VimEditor, context: ExecutionContext): List<Register> {
|
||||
val filteredRegisters = myRegisters.values.filterNot { CLIPBOARD_REGISTERS.contains(it.name) }.toMutableList()
|
||||
val clipboardRegisters = CLIPBOARD_REGISTERS
|
||||
.filterNot { it == CLIPBOARD_REGISTER && !isPrimaryRegisterSupported() } // for some reason non-X systems use PRIMARY_REGISTER as a clipboard storage
|
||||
.mapNotNull { refreshClipboardRegister(editor, context, it) }
|
||||
.mapNotNull { refreshClipboardRegister(it) }
|
||||
|
||||
return (filteredRegisters + clipboardRegisters).sortedWith(Register.KeySorter)
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#saveRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char, com.maddyhome.idea.vim.register.Register)")
|
||||
override fun saveRegister(r: Char, register: Register) {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
saveRegister(dummyEditor, dummyContext, r, register)
|
||||
}
|
||||
|
||||
override fun saveRegister(editor: VimEditor, context: ExecutionContext, r: Char, register: Register) {
|
||||
var myR = if (Character.isUpperCase(r)) Character.toLowerCase(r) else r
|
||||
val text = register.text
|
||||
val rawText = register.rawText
|
||||
|
||||
if (CLIPBOARD_REGISTERS.indexOf(myR) >= 0) {
|
||||
if (CLIPBOARD_REGISTERS.indexOf(myR) >= 0 && text != null && rawText != null) {
|
||||
when (myR) {
|
||||
CLIPBOARD_REGISTER -> {
|
||||
if (!isPrimaryRegisterSupported()) {
|
||||
// it looks wrong, but for some reason non-X systems use the * register to store the clipboard content
|
||||
myR = PRIMARY_REGISTER
|
||||
}
|
||||
setSystemClipboardRegisterText(editor, context, register.copiedText)
|
||||
setSystemClipboardRegisterText(text, rawText, ArrayList(register.transferableData))
|
||||
}
|
||||
|
||||
PRIMARY_REGISTER -> {
|
||||
setSystemPrimaryRegisterText(editor, context, register.copiedText)
|
||||
setSystemPrimaryRegisterText(text, rawText, ArrayList(register.transferableData))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,15 +517,8 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#getPlaybackRegister(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext, char)")
|
||||
override fun getPlaybackRegister(r: Char): Register? {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
return getPlaybackRegister(dummyEditor, dummyContext, r)
|
||||
}
|
||||
|
||||
override fun getPlaybackRegister(editor: VimEditor, context: ExecutionContext, r: Char): Register? {
|
||||
return if (PLAYBACK_REGISTERS.indexOf(r) != 0) getRegister(editor, context, r) else null
|
||||
return if (PLAYBACK_REGISTERS.indexOf(r) != 0) getRegister(r) else null
|
||||
}
|
||||
|
||||
override fun recordText(text: String) {
|
||||
@ -578,19 +536,12 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
myRegisters[register] = Register(register, type, keys.toMutableList())
|
||||
}
|
||||
|
||||
@Deprecated("Please use com.maddyhome.idea.vim.register.VimRegisterGroup#finishRecording(com.maddyhome.idea.vim.api.VimEditor, com.maddyhome.idea.vim.api.ExecutionContext)")
|
||||
override fun finishRecording() {
|
||||
val dummyEditor = injector.fallbackWindow
|
||||
val dummyContext = injector.executionContextManager.getEditorExecutionContext(dummyEditor)
|
||||
finishRecording(dummyEditor, dummyContext)
|
||||
}
|
||||
|
||||
override fun finishRecording(editor: VimEditor, context: ExecutionContext) {
|
||||
val register = recordRegister
|
||||
if (register != null) {
|
||||
var reg: Register? = null
|
||||
if (Character.isUpperCase(register)) {
|
||||
reg = getRegister(editor, context, register)
|
||||
reg = getRegister(register)
|
||||
}
|
||||
|
||||
val myRecordList = recordList
|
||||
@ -599,7 +550,7 @@ abstract class VimRegisterGroupBase : VimRegisterGroup {
|
||||
reg = Register(Character.toLowerCase(register), SelectionType.CHARACTER_WISE, myRecordList)
|
||||
myRegisters[Character.toLowerCase(register)] = reg
|
||||
} else {
|
||||
myRegisters[reg.name.lowercaseChar()] = reg.addText(injector.parser.toPrintableString(myRecordList))
|
||||
reg.addKeys(myRecordList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ package com.maddyhome.idea.vim.vimscript.model.commands
|
||||
import com.intellij.vim.annotations.ExCommand
|
||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.getText
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.ex.ranges.Range
|
||||
@ -37,7 +38,7 @@ data class CopyTextCommand(val range: Range, val modifier: CommandModifier, val
|
||||
val carets = editor.sortedCarets()
|
||||
for (caret in carets) {
|
||||
val range = getLineRange(editor, caret).toTextRange(editor)
|
||||
val copiedText = injector.clipboardManager.collectCopiedText(editor, context, range)
|
||||
val text = editor.getText(range)
|
||||
|
||||
// Copy is defined as:
|
||||
// :[range]co[py] {address}
|
||||
@ -46,7 +47,8 @@ data class CopyTextCommand(val range: Range, val modifier: CommandModifier, val
|
||||
// the line _before_ the first line (i.e., copy to above the first line).
|
||||
val address1 = getAddressFromArgument(editor)
|
||||
|
||||
val textData = PutData.TextData(null, copiedText, SelectionType.LINE_WISE)
|
||||
val transferableData = injector.clipboardManager.getTransferableData(editor, range)
|
||||
val textData = PutData.TextData(text, SelectionType.LINE_WISE, transferableData, null)
|
||||
var mutableCaret = caret
|
||||
val putData = if (address1 == 0) {
|
||||
// TODO: This should maintain current column location
|
||||
|
@ -88,7 +88,7 @@ data class MoveTextCommand(val range: Range, val modifier: CommandModifier, val
|
||||
val selectionEndOffset = lastSelectionInfo.end?.let { editor.bufferPositionToOffset(it) }
|
||||
|
||||
val text = editor.getText(range)
|
||||
val textData = PutData.TextData(null, injector.clipboardManager.dumbCopiedText(text), SelectionType.LINE_WISE)
|
||||
val textData = PutData.TextData(text, SelectionType.LINE_WISE, emptyList(), null)
|
||||
|
||||
val dropNewLineInEnd = (line + linesMoved == editor.lineCount() - 1 && text.last() == '\n') ||
|
||||
(lineRange.endLine == editor.lineCount() - 1)
|
||||
|
@ -47,7 +47,12 @@ data class PutLinesCommand(val range: Range, val modifier: CommandModifier, val
|
||||
|
||||
val line = if (range.size() == 0) -1 else getLine(editor)
|
||||
val textData = registerGroup.getRegister(editor, context, registerGroup.lastRegisterChar)?.let {
|
||||
PutData.TextData(null, it.copiedText, SelectionType.LINE_WISE)
|
||||
PutData.TextData(
|
||||
it.text ?: injector.parser.toKeyNotation(it.keys),
|
||||
SelectionType.LINE_WISE,
|
||||
it.transferableData,
|
||||
null,
|
||||
)
|
||||
}
|
||||
val putData = PutData(
|
||||
textData,
|
||||
|
@ -14,6 +14,7 @@ import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.ex.ranges.Range
|
||||
import com.maddyhome.idea.vim.helper.EngineStringHelper
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
|
||||
|
||||
@ -41,7 +42,8 @@ data class RegistersCommand(val range: Range, val modifier: CommandModifier, val
|
||||
SelectionType.CHARACTER_WISE -> "c"
|
||||
SelectionType.BLOCK_WISE -> "b"
|
||||
}
|
||||
" $type \"${reg.name} ${reg.printableString.take(200)}"
|
||||
val text = reg.rawText?.let { injector.parser.parseKeys(it) } ?: reg.keys
|
||||
" $type \"${reg.name} ${EngineStringHelper.toPrintableCharacters(text).take(200)}"
|
||||
}
|
||||
|
||||
injector.outputPanel.output(editor, context, regs)
|
||||
|
@ -38,8 +38,6 @@ interface VimYankGroup {
|
||||
* @param count The number of lines to yank
|
||||
* @return true if able to yank the lines, false if not
|
||||
*/
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
fun yankLine(editor: VimEditor, count: Int): Boolean
|
||||
fun yankLine(editor: VimEditor, context: ExecutionContext, count: Int): Boolean
|
||||
|
||||
/**
|
||||
@ -50,8 +48,6 @@ interface VimYankGroup {
|
||||
* @param type The type of yank
|
||||
* @return true if able to yank the range, false if not
|
||||
*/
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean
|
||||
fun yankRange(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
|
@ -10,18 +10,14 @@ package com.maddyhome.idea.vim.yank
|
||||
|
||||
import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction
|
||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.anyNonWhitespace
|
||||
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
||||
import com.maddyhome.idea.vim.api.getLineStartForOffset
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.Argument
|
||||
import com.maddyhome.idea.vim.command.MotionType
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.handler.MotionActionHandler
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import org.jetbrains.annotations.Contract
|
||||
import kotlin.math.min
|
||||
@ -30,20 +26,16 @@ open class YankGroupBase : VimYankGroup {
|
||||
private fun yankRange(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
caretToRange: Map<ImmutableVimCaret, Pair<TextRange, SelectionType>>,
|
||||
range: TextRange,
|
||||
type: SelectionType,
|
||||
startOffsets: Map<VimCaret, Int>?,
|
||||
): Boolean {
|
||||
startOffsets?.forEach { (caret, offset) ->
|
||||
caret.moveToOffset(offset)
|
||||
}
|
||||
|
||||
injector.listenersNotifier.notifyYankPerformed(caretToRange.mapValues { it.value.first })
|
||||
|
||||
var result = true
|
||||
for ((caret, myRange) in caretToRange) {
|
||||
result = caret.registerStorage.storeText(editor, context, myRange.first, myRange.second, false) && result
|
||||
}
|
||||
return result
|
||||
injector.listenersNotifier.notifyYankPerformed(editor, range)
|
||||
return injector.registerGroup.storeText(editor, context, editor.primaryCaret(), range, type, false)
|
||||
}
|
||||
|
||||
@Contract("_, _ -> new")
|
||||
@ -83,11 +75,12 @@ open class YankGroupBase : VimYankGroup {
|
||||
operatorArguments: OperatorArguments,
|
||||
): Boolean {
|
||||
val motion = argument as? Argument.Motion ?: return false
|
||||
val motionType = motion.getMotionType()
|
||||
|
||||
val nativeCaretCount = editor.nativeCarets().size
|
||||
if (nativeCaretCount <= 0) return false
|
||||
|
||||
val caretToRange = HashMap<ImmutableVimCaret, Pair<TextRange, SelectionType>>(nativeCaretCount)
|
||||
val ranges = ArrayList<Pair<Int, Int>>(nativeCaretCount)
|
||||
|
||||
// This logic is from original vim
|
||||
val startOffsets =
|
||||
@ -97,49 +90,28 @@ open class YankGroupBase : VimYankGroup {
|
||||
HashMap<VimCaret, Int>(nativeCaretCount)
|
||||
}
|
||||
|
||||
|
||||
for (caret in editor.nativeCarets()) {
|
||||
var motionType = motion.getMotionType()
|
||||
val motionRange = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments)
|
||||
?: continue
|
||||
|
||||
assert(motionRange.size() == 1)
|
||||
ranges.add(motionRange.startOffset to motionRange.endOffset)
|
||||
startOffsets?.put(caret, motionRange.normalize().startOffset)
|
||||
|
||||
// Yank motion commands that are not linewise become linewise if all the following are true:
|
||||
// 1) The range is across multiple lines
|
||||
// 2) There is only whitespace before the start of the range
|
||||
// 3) There is only whitespace after the end of the range
|
||||
if (argument.motion is MotionActionHandler && argument.motion.motionType == MotionType.EXCLUSIVE) {
|
||||
val start = editor.offsetToBufferPosition(motionRange.startOffset)
|
||||
val end = editor.offsetToBufferPosition(motionRange.endOffset)
|
||||
if (start.line != end.line
|
||||
&& !editor.anyNonWhitespace(motionRange.startOffset, -1)
|
||||
&& !editor.anyNonWhitespace(motionRange.endOffset, 1)
|
||||
) {
|
||||
motionType = SelectionType.LINE_WISE
|
||||
}
|
||||
}
|
||||
|
||||
caretToRange[caret] = TextRange(motionRange.startOffset, motionRange.endOffset) to motionType
|
||||
}
|
||||
|
||||
if (caretToRange.isEmpty()) return false
|
||||
val range = getTextRange(ranges, motionType) ?: return false
|
||||
|
||||
if (range.size() == 0) return false
|
||||
|
||||
return yankRange(
|
||||
editor,
|
||||
context,
|
||||
caretToRange,
|
||||
range,
|
||||
motionType,
|
||||
startOffsets,
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
override fun yankLine(editor: VimEditor, count: Int): Boolean {
|
||||
val context = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||
return yankLine(editor, context, count)
|
||||
}
|
||||
|
||||
/**
|
||||
* This yanks count lines of text
|
||||
*
|
||||
@ -149,24 +121,18 @@ open class YankGroupBase : VimYankGroup {
|
||||
*/
|
||||
override fun yankLine(editor: VimEditor, context: ExecutionContext, count: Int): Boolean {
|
||||
val caretCount = editor.nativeCarets().size
|
||||
val caretToRange = HashMap<ImmutableVimCaret, Pair<TextRange, SelectionType>>(caretCount)
|
||||
val ranges = ArrayList<Pair<Int, Int>>(caretCount)
|
||||
for (caret in editor.nativeCarets()) {
|
||||
val start = injector.motion.moveCaretToCurrentLineStart(editor, caret)
|
||||
val end =
|
||||
min(injector.motion.moveCaretToRelativeLineEnd(editor, caret, count - 1, true) + 1, editor.fileSize().toInt())
|
||||
val end = min(injector.motion.moveCaretToRelativeLineEnd(editor, caret, count - 1, true) + 1, editor.fileSize().toInt())
|
||||
|
||||
if (end == -1) continue
|
||||
|
||||
caretToRange[caret] = TextRange(start, end) to SelectionType.LINE_WISE
|
||||
ranges.add(start to end)
|
||||
}
|
||||
|
||||
return yankRange(editor, context, caretToRange, null)
|
||||
}
|
||||
|
||||
@Deprecated("Please use the same method, but with ExecutionContext")
|
||||
override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean {
|
||||
val context = injector.executionContextManager.getEditorExecutionContext(editor)
|
||||
return yankRange(editor, context, range, type, moveCursor)
|
||||
val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false
|
||||
return yankRange(editor, context, range, SelectionType.LINE_WISE, null)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,15 +143,8 @@ open class YankGroupBase : VimYankGroup {
|
||||
* @param type The type of yank
|
||||
* @return true if able to yank the range, false if not
|
||||
*/
|
||||
override fun yankRange(
|
||||
editor: VimEditor,
|
||||
context: ExecutionContext,
|
||||
range: TextRange?,
|
||||
type: SelectionType,
|
||||
moveCursor: Boolean,
|
||||
): Boolean {
|
||||
override fun yankRange(editor: VimEditor, context: ExecutionContext, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean {
|
||||
range ?: return false
|
||||
val caretToRange = HashMap<ImmutableVimCaret, Pair<TextRange, SelectionType>>()
|
||||
|
||||
if (type == SelectionType.LINE_WISE) {
|
||||
for (i in 0 until range.size()) {
|
||||
@ -205,19 +164,17 @@ open class YankGroupBase : VimYankGroup {
|
||||
val startOffsets = HashMap<VimCaret, Int>(editor.nativeCarets().size)
|
||||
if (type == SelectionType.BLOCK_WISE) {
|
||||
startOffsets[editor.primaryCaret()] = range.normalize().startOffset
|
||||
caretToRange[editor.primaryCaret()] = range to type
|
||||
} else {
|
||||
for ((i, caret) in editor.nativeCarets().withIndex()) {
|
||||
val textRange = TextRange(rangeStartOffsets[i], rangeEndOffsets[i])
|
||||
startOffsets[caret] = textRange.normalize().startOffset
|
||||
caretToRange[caret] = textRange to type
|
||||
}
|
||||
}
|
||||
|
||||
return if (moveCursor) {
|
||||
yankRange(editor, context, caretToRange, startOffsets)
|
||||
yankRange(editor, context, range, type, startOffsets)
|
||||
} else {
|
||||
yankRange(editor, context, caretToRange, null)
|
||||
yankRange(editor, context, range, type, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user