mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-02-27 17:45:59 +01:00
Better selection marks
This commit is contained in:
parent
8c7d0b06d1
commit
fe1ae29fa3
src/main/java/com/maddyhome/idea/vim
vim-engine/src/main/kotlin/com/maddyhome/idea/vim
@ -20,8 +20,7 @@ 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.VimMarkService
|
||||
import com.maddyhome.idea.vim.api.VimMarkServiceBase
|
||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||
import com.maddyhome.idea.vim.command.SelectionType
|
||||
import com.maddyhome.idea.vim.command.VimStateMachine
|
||||
import com.maddyhome.idea.vim.ex.ExOutputModel
|
||||
@ -97,6 +96,7 @@ var Caret.vimInsertStart: RangeMarker by userDataOr {
|
||||
// TODO: Data could be lost during visual block motion
|
||||
var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
|
||||
var Caret.markStorage: LocalMarkStorage? by userDataCaretToEditor()
|
||||
var Caret.lastSelectionInfo: SelectionInfo? by userDataCaretToEditor()
|
||||
|
||||
// ------------------ Editor
|
||||
fun unInitializeEditor(editor: Editor) {
|
||||
|
@ -16,10 +16,12 @@ import com.maddyhome.idea.vim.api.CaretRegisterStorage
|
||||
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
|
||||
import com.maddyhome.idea.vim.api.LocalMarkStorage
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.SelectionInfo
|
||||
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.command.SelectionType
|
||||
import com.maddyhome.idea.vim.common.EditorLine
|
||||
import com.maddyhome.idea.vim.common.LiveRange
|
||||
import com.maddyhome.idea.vim.common.Offset
|
||||
@ -30,6 +32,7 @@ import com.maddyhome.idea.vim.group.visual.vimSetSelection
|
||||
import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
|
||||
import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection
|
||||
import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn
|
||||
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
|
||||
@ -44,7 +47,7 @@ import com.maddyhome.idea.vim.helper.vimSelectionStartClear
|
||||
class IjVimCaret(val caret: Caret) : VimCaretBase() {
|
||||
override val registerStorage: CaretRegisterStorage
|
||||
get() {
|
||||
// todo
|
||||
// todo update caret in getter to simplify signature
|
||||
var storage = this.caret.registerStorage
|
||||
if (storage == null) {
|
||||
storage = CaretRegisterStorageBase()
|
||||
@ -63,6 +66,19 @@ class IjVimCaret(val caret: Caret) : VimCaretBase() {
|
||||
}
|
||||
return storage
|
||||
}
|
||||
override var lastSelectionInfo: SelectionInfo
|
||||
get() {
|
||||
val lastSelection = this.caret.lastSelectionInfo
|
||||
if (lastSelection == null) {
|
||||
val defaultValue = SelectionInfo(null, null, SelectionType.CHARACTER_WISE)
|
||||
this.caret.lastSelectionInfo = defaultValue
|
||||
return defaultValue
|
||||
}
|
||||
return lastSelection
|
||||
}
|
||||
set(value) {
|
||||
this.caret.lastSelectionInfo = value
|
||||
}
|
||||
override val editor: VimEditor
|
||||
get() = IjVimEditor(caret.editor)
|
||||
override val offset: Offset
|
||||
|
@ -60,6 +60,7 @@ interface ImmutableVimCaret {
|
||||
val visualLineStart: Int
|
||||
fun hasSelection(): Boolean
|
||||
|
||||
var lastSelectionInfo: SelectionInfo
|
||||
val registerStorage: CaretRegisterStorage
|
||||
val markStorage: LocalMarkStorage
|
||||
}
|
||||
@ -150,3 +151,5 @@ interface CaretRegisterStorage {
|
||||
fun setKeys(caret: ImmutableVimCaret, register: Char, keys: List<KeyStroke>)
|
||||
fun saveRegister(caret: ImmutableVimCaret, r: Char, register: Register)
|
||||
}
|
||||
|
||||
data class SelectionInfo(val startOffset: Int?, val endOffset: Int?, val type: SelectionType)
|
||||
|
@ -24,10 +24,14 @@ import com.maddyhome.idea.vim.api.VimMarkService.Companion.SENTENCE_END_MARK
|
||||
import com.maddyhome.idea.vim.api.VimMarkService.Companion.SENTENCE_START_MARK
|
||||
import com.maddyhome.idea.vim.api.VimMarkService.Companion.UPPERCASE_MARKS
|
||||
import com.maddyhome.idea.vim.command.Command
|
||||
import com.maddyhome.idea.vim.command.SelectionType
|
||||
import com.maddyhome.idea.vim.command.VimStateMachine
|
||||
import com.maddyhome.idea.vim.common.Offset
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.diagnostic.debug
|
||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
||||
import com.maddyhome.idea.vim.helper.inVisualMode
|
||||
import com.maddyhome.idea.vim.helper.subMode
|
||||
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||
import com.maddyhome.idea.vim.mark.Mark
|
||||
import com.maddyhome.idea.vim.mark.VimMark
|
||||
@ -81,12 +85,19 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
protected fun getLocalMark(caret: ImmutableVimCaret, char: Char): Mark? {
|
||||
val markChar = if (char == '`') '\'' else char
|
||||
if (!markChar.isLocalMark()) return null
|
||||
|
||||
if (markChar == SELECTION_START_MARK) {
|
||||
return getSelectionStartMark(caret)
|
||||
} else if (markChar == SELECTION_END_MARK) {
|
||||
return getSelectionEndMark(caret)
|
||||
}
|
||||
|
||||
val editor = caret.editor
|
||||
val path = editor.getPath() ?: return null
|
||||
return if (caret.isPrimary) {
|
||||
val mark = getLocalMarks(path)[markChar]
|
||||
when (markChar) {
|
||||
VimMarkService.LAST_BUFFER_POSITION -> mark ?: VimMark('"', 1, 1, path, editor.extractProtocol())
|
||||
LAST_BUFFER_POSITION -> mark ?: createMark(caret, LAST_BUFFER_POSITION, 0)
|
||||
else -> mark
|
||||
}
|
||||
} else {
|
||||
@ -100,9 +111,9 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
|
||||
val editor = caret.editor
|
||||
val path = editor.getPath()
|
||||
return if (path != null && setOf(VimMarkService.PARAGRAPH_START_MARK, VimMarkService.PARAGRAPH_END_MARK).contains(markChar)) {
|
||||
return if (path != null && setOf(PARAGRAPH_START_MARK, PARAGRAPH_END_MARK).contains(markChar)) {
|
||||
getParagraphMark(editor, caret, markChar)
|
||||
} else if (path != null && setOf(VimMarkService.SENTENCE_START_MARK, VimMarkService.SENTENCE_END_MARK).contains(markChar)) {
|
||||
} else if (path != null && setOf(SENTENCE_START_MARK, SENTENCE_END_MARK).contains(markChar)) {
|
||||
getSentenceMark(editor, caret, markChar)
|
||||
} else if (markChar.isLocalMark()) {
|
||||
getLocalMark(caret, markChar)
|
||||
@ -115,11 +126,12 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
|
||||
override fun getAllLocalMarks(caret: ImmutableVimCaret): Set<Mark> {
|
||||
val path = caret.editor.getPath() ?: return emptySet()
|
||||
return if (caret.isPrimary) {
|
||||
getLocalMarks(path).values.toSet()
|
||||
val marks = if (caret.isPrimary) {
|
||||
getLocalMarks(path).values
|
||||
} else {
|
||||
caret.markStorage.getMarks().values.toSet()
|
||||
}
|
||||
return (marks + getLocalMark(caret, SELECTION_START_MARK) + getLocalMark(caret, SELECTION_END_MARK)).filterNotNull().toSet()
|
||||
}
|
||||
|
||||
override fun getAllMarksForFile(editor: VimEditor): Set<Mark> {
|
||||
@ -169,27 +181,26 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
|
||||
if (markChar.isGlobalMark()) {
|
||||
setGlobalMark(caret.editor, mark)
|
||||
return true
|
||||
}
|
||||
|
||||
if (markChar.isLocalMark()) {
|
||||
} else if (markChar == SELECTION_START_MARK || markChar == SELECTION_END_MARK) {
|
||||
when (markChar) {
|
||||
SELECTION_START_MARK -> setSelectionStartMark(caret, mark.offset(caret.editor))
|
||||
SELECTION_END_MARK -> setSelectionEndMark(caret, mark.offset(caret.editor))
|
||||
}
|
||||
} else if (markChar.isLocalMark()) {
|
||||
if (caret.isPrimary) {
|
||||
getLocalMarks(mark.filepath)[markChar] = mark
|
||||
} else {
|
||||
caret.markStorage.setMark(mark)
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setMark(caret: ImmutableVimCaret, char: Char, offset: Int): Boolean {
|
||||
val markChar = if (char == '`') '\'' else char
|
||||
val editor = caret.editor
|
||||
val position = editor.offsetToBufferPosition(offset)
|
||||
val path = editor.getPath() ?: return false
|
||||
val mark = VimMark(markChar, position.line, position.column, path, editor.extractProtocol())
|
||||
val mark = createMark(caret, markChar, offset) ?: return false
|
||||
return setMark(caret, mark)
|
||||
}
|
||||
|
||||
@ -225,13 +236,13 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
|
||||
override fun setVisualSelectionMarks(editor: VimEditor) {
|
||||
if (!editor.inVisualMode) return
|
||||
val selectionType = SelectionType.fromSubMode(editor.subMode)
|
||||
editor.carets()
|
||||
.map {
|
||||
val startOffset = min(it.vimSelectionStart, it.offset.point)
|
||||
val endOffset = max(it.vimSelectionStart, it.offset.point)
|
||||
it to TextRange(startOffset, endOffset)
|
||||
.forEach {
|
||||
val startOffset = it.vimSelectionStart
|
||||
val endOffset = it.offset.point
|
||||
it.lastSelectionInfo = SelectionInfo(startOffset, endOffset, selectionType)
|
||||
}
|
||||
.forEach { setVisualSelectionMarks(it.first, it.second) }
|
||||
}
|
||||
|
||||
override fun setVisualSelectionMarks(caret: ImmutableVimCaret, range: TextRange) {
|
||||
@ -455,6 +466,52 @@ abstract class VimMarkServiceBase : VimMarkService {
|
||||
val lp = editor.offsetToBufferPosition(offset)
|
||||
return VimMark(char, lp.line, lp.column, path, editor.extractProtocol())
|
||||
}
|
||||
|
||||
protected fun getSelectionStartMark(caret: ImmutableVimCaret): Mark? {
|
||||
val selectionInfo = caret.lastSelectionInfo
|
||||
var offset = if (selectionInfo.startOffset != null && selectionInfo.endOffset != null) {
|
||||
min(selectionInfo.startOffset!!, selectionInfo.endOffset!!)
|
||||
} else {
|
||||
selectionInfo.startOffset
|
||||
} ?: return null
|
||||
|
||||
if (selectionInfo.type == SelectionType.LINE_WISE) {
|
||||
offset = caret.editor.getLineStartForOffset(offset)
|
||||
}
|
||||
|
||||
return createMark(caret, SELECTION_START_MARK, offset)
|
||||
}
|
||||
|
||||
protected fun getSelectionEndMark(caret: ImmutableVimCaret): Mark? {
|
||||
val selectionInfo = caret.lastSelectionInfo
|
||||
var offset = if (selectionInfo.startOffset != null && selectionInfo.endOffset != null) {
|
||||
max(selectionInfo.startOffset!!, selectionInfo.endOffset!!)
|
||||
} else {
|
||||
selectionInfo.endOffset
|
||||
} ?: return null
|
||||
|
||||
if (selectionInfo.type == SelectionType.LINE_WISE) {
|
||||
offset = caret.editor.getLineEndForOffset(offset)
|
||||
}
|
||||
|
||||
return createMark(caret, SELECTION_END_MARK, offset)
|
||||
}
|
||||
|
||||
protected fun setSelectionStartMark(caret: ImmutableVimCaret, offset: Int) {
|
||||
val selectionInfo = caret.lastSelectionInfo
|
||||
caret.lastSelectionInfo = SelectionInfo(offset, selectionInfo.endOffset, selectionInfo.type)
|
||||
}
|
||||
|
||||
protected fun setSelectionEndMark(caret: ImmutableVimCaret, offset: Int) {
|
||||
val selectionInfo = caret.lastSelectionInfo
|
||||
caret.lastSelectionInfo = SelectionInfo(selectionInfo.startOffset, offset, selectionInfo.type)
|
||||
}
|
||||
|
||||
private fun createMark(caret: ImmutableVimCaret, char: Char, offset: Int): Mark? {
|
||||
val editor = caret.editor
|
||||
val position = editor.offsetToBufferPosition(offset)
|
||||
return VimMark(char, position.line, position.column, editor.getPath() ?: return null, editor.extractProtocol());
|
||||
}
|
||||
}
|
||||
|
||||
class LocalMarkStorage(var caret: ImmutableVimCaret) {
|
||||
|
@ -14,8 +14,8 @@ import org.jetbrains.annotations.NonNls
|
||||
|
||||
interface Mark {
|
||||
val key: Char
|
||||
val line: Int
|
||||
val col: Int
|
||||
val line: Int // 0-based
|
||||
val col: Int // 0-based
|
||||
val filepath: String
|
||||
val protocol: String?
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user