mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2026-03-31 06:52:37 +02:00
Compare commits
6 Commits
customized
...
customized
| Author | SHA1 | Date | |
|---|---|---|---|
|
7b813899f0
|
|||
|
727dee5b85
|
|||
|
3e7ea8668c
|
|||
|
89f7c76180
|
|||
|
a7d0297e2d
|
|||
|
45da61debe
|
@@ -20,7 +20,7 @@ ideaVersion=2026.1
|
|||||||
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
||||||
ideaType=IU
|
ideaType=IU
|
||||||
instrumentPluginCode=true
|
instrumentPluginCode=true
|
||||||
version=chylex-1
|
version=chylex-53
|
||||||
javaVersion=21
|
javaVersion=21
|
||||||
remoteRobotVersion=0.11.23
|
remoteRobotVersion=0.11.23
|
||||||
antlrVersion=4.10.1
|
antlrVersion=4.10.1
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ class MotionGroup : VimMotionGroupBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun moveCaretToCurrentDisplayLineStart(editor: VimEditor, caret: ImmutableVimCaret): Motion {
|
override fun moveCaretToCurrentDisplayLineStart(editor: VimEditor, caret: ImmutableVimCaret): Motion {
|
||||||
|
if (editor.ij.softWrapModel.isSoftWrappingEnabled) {
|
||||||
|
return AbsoluteOffset(caret.ij.visualLineStart)
|
||||||
|
}
|
||||||
val col = EditorHelper.getVisualColumnAtLeftOfDisplay(editor.ij, caret.getVisualPosition().line)
|
val col = EditorHelper.getVisualColumnAtLeftOfDisplay(editor.ij, caret.getVisualPosition().line)
|
||||||
return moveCaretToColumn(editor, caret, col, false)
|
return moveCaretToColumn(editor, caret, col, false)
|
||||||
}
|
}
|
||||||
@@ -94,6 +97,15 @@ class MotionGroup : VimMotionGroupBase() {
|
|||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
caret: ImmutableVimCaret,
|
caret: ImmutableVimCaret,
|
||||||
): @Range(from = 0, to = Int.MAX_VALUE.toLong()) Int {
|
): @Range(from = 0, to = Int.MAX_VALUE.toLong()) Int {
|
||||||
|
if (editor.ij.softWrapModel.isSoftWrappingEnabled) {
|
||||||
|
val offset = caret.ij.visualLineStart
|
||||||
|
val line = editor.offsetToBufferPosition(offset).line
|
||||||
|
return if (offset == editor.getLineStartOffset(line)) {
|
||||||
|
editor.getLeadingCharacterOffset(line, 0)
|
||||||
|
} else {
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
}
|
||||||
val col = EditorHelper.getVisualColumnAtLeftOfDisplay(editor.ij, caret.getVisualPosition().line)
|
val col = EditorHelper.getVisualColumnAtLeftOfDisplay(editor.ij, caret.getVisualPosition().line)
|
||||||
val bufferLine = caret.getLine()
|
val bufferLine = caret.getLine()
|
||||||
return editor.getLeadingCharacterOffset(bufferLine, col)
|
return editor.getLeadingCharacterOffset(bufferLine, col)
|
||||||
@@ -104,6 +116,9 @@ class MotionGroup : VimMotionGroupBase() {
|
|||||||
caret: ImmutableVimCaret,
|
caret: ImmutableVimCaret,
|
||||||
allowEnd: Boolean,
|
allowEnd: Boolean,
|
||||||
): Motion {
|
): Motion {
|
||||||
|
if (editor.ij.softWrapModel.isSoftWrappingEnabled) {
|
||||||
|
return AbsoluteOffset(caret.ij.visualLineEnd - 1)
|
||||||
|
}
|
||||||
val col = EditorHelper.getVisualColumnAtRightOfDisplay(editor.ij, caret.getVisualPosition().line)
|
val col = EditorHelper.getVisualColumnAtRightOfDisplay(editor.ij, caret.getVisualPosition().line)
|
||||||
return moveCaretToColumn(editor, caret, col, allowEnd)
|
return moveCaretToColumn(editor, caret, col, allowEnd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,19 @@ import com.intellij.openapi.diagnostic.thisLogger
|
|||||||
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
|
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
|
||||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
|
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
|
||||||
import com.intellij.openapi.util.NlsContexts
|
import com.intellij.openapi.util.NlsContexts
|
||||||
|
import com.intellij.refactoring.actions.BaseRefactoringAction
|
||||||
import com.maddyhome.idea.vim.RegisterActions
|
import com.maddyhome.idea.vim.RegisterActions
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.NativeAction
|
import com.maddyhome.idea.vim.api.NativeAction
|
||||||
import com.maddyhome.idea.vim.api.VimActionExecutor
|
import com.maddyhome.idea.vim.api.VimActionExecutor
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
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.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
|
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
|
||||||
import com.maddyhome.idea.vim.newapi.IjNativeAction
|
import com.maddyhome.idea.vim.newapi.IjNativeAction
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
|
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
@@ -68,6 +72,12 @@ class IjActionExecutor : VimActionExecutor {
|
|||||||
thisLogger().error("Actions cannot be updated when write-action is running or pending")
|
thisLogger().error("Actions cannot be updated when write-action is running or pending")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val startVisualModeType = (editor?.mode as? Mode.VISUAL)?.selectionType
|
||||||
|
val startVisualCaretSelection = if (editor != null && startVisualModeType != null && action.action !is BaseRefactoringAction)
|
||||||
|
editor.primaryCaret().let { Triple(it.offset, it.selectionStart, it.selectionEnd) }
|
||||||
|
else
|
||||||
|
null
|
||||||
|
|
||||||
val ijAction = (action as IjNativeAction).action
|
val ijAction = (action as IjNativeAction).action
|
||||||
try {
|
try {
|
||||||
isRunningActionFromVim = true
|
isRunningActionFromVim = true
|
||||||
@@ -77,6 +87,20 @@ class IjActionExecutor : VimActionExecutor {
|
|||||||
val place = ijAction.choosePlace()
|
val place = ijAction.choosePlace()
|
||||||
val res = ActionManager.getInstance().tryToExecute(ijAction, null, contextComponent, place, true)
|
val res = ActionManager.getInstance().tryToExecute(ijAction, null, contextComponent, place, true)
|
||||||
res.waitFor(5_000)
|
res.waitFor(5_000)
|
||||||
|
|
||||||
|
if (startVisualModeType != null && startVisualCaretSelection != null) {
|
||||||
|
val primaryCaret = editor.primaryCaret()
|
||||||
|
val endVisualCaretOffset = primaryCaret.offset
|
||||||
|
if (startVisualCaretSelection.first != endVisualCaretOffset) {
|
||||||
|
if (!editor.inVisualMode || (editor.mode as Mode.VISUAL).selectionType != startVisualModeType) {
|
||||||
|
injector.visualMotionGroup.toggleVisual(editor, 1, 0, startVisualModeType)
|
||||||
|
}
|
||||||
|
primaryCaret.moveToOffset(startVisualCaretSelection.first)
|
||||||
|
primaryCaret.setSelection(startVisualCaretSelection.second, startVisualCaretSelection.third)
|
||||||
|
primaryCaret.moveToOffset(endVisualCaretOffset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res.isDone
|
return res.isDone
|
||||||
} finally {
|
} finally {
|
||||||
isRunningActionFromVim = false
|
isRunningActionFromVim = false
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.intellij.openapi.editor.markup.HighlighterLayer
|
|||||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||||
import com.intellij.openapi.editor.markup.TextAttributes
|
import com.intellij.openapi.editor.markup.TextAttributes
|
||||||
|
import com.intellij.util.application
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
@@ -30,6 +31,7 @@ import com.maddyhome.idea.vim.state.mode.inVisualMode
|
|||||||
import org.jetbrains.annotations.Contract
|
import org.jetbrains.annotations.Contract
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.swing.Timer
|
||||||
|
|
||||||
fun updateSearchHighlights(
|
fun updateSearchHighlights(
|
||||||
pattern: String?,
|
pattern: String?,
|
||||||
@@ -84,6 +86,12 @@ fun addSubstitutionConfirmationHighlight(editor: Editor, start: Int, end: Int):
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val removeHighlightsEditors = mutableListOf<Editor>()
|
||||||
|
val removeHighlightsTimer = Timer(400) {
|
||||||
|
removeHighlightsEditors.forEach(::removeSearchHighlights)
|
||||||
|
removeHighlightsEditors.clear()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes current search highlights for all visible editors
|
* Refreshes current search highlights for all visible editors
|
||||||
*/
|
*/
|
||||||
@@ -125,17 +133,28 @@ private fun updateSearchHighlights(
|
|||||||
// hlsearch (+ incsearch/noincsearch)
|
// hlsearch (+ incsearch/noincsearch)
|
||||||
// Make sure the range fits this editor. Note that Vim will use the same range for all windows. E.g., given
|
// Make sure the range fits this editor. Note that Vim will use the same range for all windows. E.g., given
|
||||||
// `:1,5s/foo`, Vim will highlight all occurrences of `foo` in the first five lines of all visible windows
|
// `:1,5s/foo`, Vim will highlight all occurrences of `foo` in the first five lines of all visible windows
|
||||||
|
val isSearching = injector.commandLine.getActiveCommandLine() != null
|
||||||
|
application.invokeLater {
|
||||||
val vimEditor = editor.vim
|
val vimEditor = editor.vim
|
||||||
val editorLastLine = vimEditor.lineCount() - 1
|
val editorLastLine = vimEditor.lineCount() - 1
|
||||||
val searchStartLine = searchRange?.startLine ?: 0
|
val searchStartLine = searchRange?.startLine ?: 0
|
||||||
val searchEndLine = (searchRange?.endLine ?: -1).coerceAtMost(editorLastLine)
|
val searchEndLine = (searchRange?.endLine ?: -1).coerceAtMost(editorLastLine)
|
||||||
if (searchStartLine <= editorLastLine) {
|
if (searchStartLine <= editorLastLine) {
|
||||||
|
val visibleArea = editor.scrollingModel.visibleAreaOnScrollingFinished
|
||||||
|
val visibleTopLeft = visibleArea.location
|
||||||
|
val visibleBottomRight = visibleArea.location.apply { translate(visibleArea.width, visibleArea.height) }
|
||||||
|
val visibleStartOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(visibleTopLeft))
|
||||||
|
val visibleEndOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(visibleBottomRight))
|
||||||
|
val visibleStartLine = editor.document.getLineNumber(visibleStartOffset)
|
||||||
|
val visibleEndLine = editor.document.getLineNumber(visibleEndOffset)
|
||||||
|
removeSearchHighlights(editor)
|
||||||
|
|
||||||
val results =
|
val results =
|
||||||
injector.searchHelper.findAll(
|
injector.searchHelper.findAll(
|
||||||
vimEditor,
|
vimEditor,
|
||||||
pattern,
|
pattern,
|
||||||
searchStartLine,
|
searchStartLine.coerceAtLeast(visibleStartLine),
|
||||||
searchEndLine,
|
searchEndLine.coerceAtMost(visibleEndLine),
|
||||||
shouldIgnoreCase(pattern, shouldIgnoreSmartCase)
|
shouldIgnoreCase(pattern, shouldIgnoreSmartCase)
|
||||||
)
|
)
|
||||||
if (results.isNotEmpty()) {
|
if (results.isNotEmpty()) {
|
||||||
@@ -143,9 +162,14 @@ private fun updateSearchHighlights(
|
|||||||
currentMatchOffset = findClosestMatch(results, initialOffset, count1, forwards)
|
currentMatchOffset = findClosestMatch(results, initialOffset, count1, forwards)
|
||||||
}
|
}
|
||||||
highlightSearchResults(editor, pattern, results, currentMatchOffset)
|
highlightSearchResults(editor, pattern, results, currentMatchOffset)
|
||||||
|
if (!isSearching) {
|
||||||
|
removeHighlightsEditors.add(editor)
|
||||||
|
removeHighlightsTimer.restart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
editor.vimLastSearch = pattern
|
editor.vimLastSearch = pattern
|
||||||
|
}
|
||||||
} else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) {
|
} else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) {
|
||||||
// nohlsearch + incsearch. Even though search highlights are disabled, we still show a highlight (current editor
|
// nohlsearch + incsearch. Even though search highlights are disabled, we still show a highlight (current editor
|
||||||
// only), because 'incsearch' is active. But we don't show a search if Visual is active (behind Command-line of
|
// only), because 'incsearch' is active. But we don't show a search if Visual is active (behind Command-line of
|
||||||
@@ -179,6 +203,7 @@ private fun updateSearchHighlights(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeHighlightsTimer.restart()
|
||||||
return currentEditorCurrentMatchOffset
|
return currentEditorCurrentMatchOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +229,7 @@ private fun removeSearchHighlights(editor: Editor) {
|
|||||||
*/
|
*/
|
||||||
@Contract("_, _, false -> false; _, null, true -> false")
|
@Contract("_, _, false -> false; _, null, true -> false")
|
||||||
private fun shouldAddAllSearchHighlights(editor: Editor, newPattern: String?, hlSearch: Boolean): Boolean {
|
private fun shouldAddAllSearchHighlights(editor: Editor, newPattern: String?, hlSearch: Boolean): Boolean {
|
||||||
return hlSearch && newPattern != null && newPattern != editor.vimLastSearch && newPattern != ""
|
return hlSearch && newPattern != null && newPattern != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findClosestMatch(
|
private fun findClosestMatch(
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ object VimListenerManager {
|
|||||||
injector.outputPanel.getCurrentOutputPanel()?.close()
|
injector.outputPanel.getCurrentOutputPanel()?.close()
|
||||||
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
FileGroupHelper.fileEditorManagerSelectionChangedCallback(event)
|
FileGroupHelper.fileEditorManagerSelectionChangedCallback(event)
|
||||||
(VimPlugin.getSearch() as IjVimSearchGroup).fileEditorManagerSelectionChangedCallback(event)
|
// (VimPlugin.getSearch() as IjVimSearchGroup).fileEditorManagerSelectionChangedCallback(event)
|
||||||
IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
|
IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event)
|
||||||
VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor)
|
VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -631,6 +631,10 @@ class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase() {
|
|||||||
get() = ijFoldRegion.endOffset
|
get() = ijFoldRegion.endOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getSoftWrapStartAtOffset(offset: Int): Int? {
|
||||||
|
return editor.softWrapModel.getSoftWrap(offset)?.start
|
||||||
|
}
|
||||||
|
|
||||||
override fun <T : ImmutableVimCaret> findLastVersionOfCaret(caret: T): T {
|
override fun <T : ImmutableVimCaret> findLastVersionOfCaret(caret: T): T {
|
||||||
return caret
|
return caret
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ class MotionCamelLeftAction : MotionActionHandler.ForEachCaret() {
|
|||||||
argument: Argument?,
|
argument: Argument?,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): Motion {
|
): Motion {
|
||||||
|
if (caret.hasSelection() && caret.offset > caret.vimSelectionStart) {
|
||||||
|
val target = injector.searchHelper.findPreviousCamelEnd(editor.text(), caret.offset, operatorArguments.count1)
|
||||||
|
if (target != null && target > caret.vimSelectionStart) {
|
||||||
|
return target.toMotionOrError()
|
||||||
|
}
|
||||||
|
}
|
||||||
return injector.searchHelper.findPreviousCamelStart(editor.text(), caret.offset, operatorArguments.count1)
|
return injector.searchHelper.findPreviousCamelStart(editor.text(), caret.offset, operatorArguments.count1)
|
||||||
?.toMotionOrError() ?: Motion.Error
|
?.toMotionOrError() ?: Motion.Error
|
||||||
}
|
}
|
||||||
@@ -47,6 +53,10 @@ class MotionCamelRightAction : MotionActionHandler.ForEachCaret() {
|
|||||||
argument: Argument?,
|
argument: Argument?,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): Motion {
|
): Motion {
|
||||||
|
if (caret.hasSelection() && caret.offset >= caret.vimSelectionStart) {
|
||||||
|
return injector.searchHelper.findNextCamelEnd(editor.text(), caret.offset + 1, operatorArguments.count1)
|
||||||
|
?.toMotionOrError() ?: Motion.Error
|
||||||
|
}
|
||||||
return injector.searchHelper.findNextCamelStart(editor.text(), caret.offset + 1, operatorArguments.count1)
|
return injector.searchHelper.findNextCamelStart(editor.text(), caret.offset + 1, operatorArguments.count1)
|
||||||
?.toMotionOrError() ?: Motion.Error
|
?.toMotionOrError() ?: Motion.Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,6 @@ class MotionDownNotLineWiseAction : MotionActionHandler.ForEachCaret() {
|
|||||||
argument: Argument?,
|
argument: Argument?,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): Motion {
|
): Motion {
|
||||||
return injector.motion.getVerticalMotionOffset(editor, caret, operatorArguments.count1)
|
return injector.motion.getVerticalMotionOffset(editor, caret, operatorArguments.count1, bufferLines = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,6 @@ class MotionUpNotLineWiseAction : MotionActionHandler.ForEachCaret() {
|
|||||||
argument: Argument?,
|
argument: Argument?,
|
||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
): Motion {
|
): Motion {
|
||||||
return injector.motion.getVerticalMotionOffset(editor, caret, -operatorArguments.count1)
|
return injector.motion.getVerticalMotionOffset(editor, caret, -operatorArguments.count1, bufferLines = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ interface VimEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createIndentBySize(size: Int): String
|
fun createIndentBySize(size: Int): String
|
||||||
|
fun getSoftWrapStartAtOffset(offset: Int): Int?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the collapsed fold region at the specified offset, if any.
|
* Returns the collapsed fold region at the specified offset, if any.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ interface VimMotionGroup {
|
|||||||
allowWrap: Boolean = false,
|
allowWrap: Boolean = false,
|
||||||
): Motion
|
): Motion
|
||||||
|
|
||||||
fun getVerticalMotionOffset(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Motion
|
fun getVerticalMotionOffset(editor: VimEditor, caret: ImmutableVimCaret, count: Int, bufferLines: Boolean = false): Motion
|
||||||
|
|
||||||
// TODO: Consider naming. These don't move the caret, but calculate offsets. Also consider returning Motion
|
// TODO: Consider naming. These don't move the caret, but calculate offsets. Also consider returning Motion
|
||||||
|
|
||||||
|
|||||||
@@ -33,14 +33,18 @@ abstract class VimMotionGroupBase : VimMotionGroup {
|
|||||||
override var lastFTCmd: TillCharacterMotionType = TillCharacterMotionType.LAST_SMALL_T
|
override var lastFTCmd: TillCharacterMotionType = TillCharacterMotionType.LAST_SMALL_T
|
||||||
override var lastFTChar: Char = ' '
|
override var lastFTChar: Char = ' '
|
||||||
|
|
||||||
override fun getVerticalMotionOffset(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Motion {
|
override fun getVerticalMotionOffset(editor: VimEditor, caret: ImmutableVimCaret, count: Int, bufferLines: Boolean): Motion {
|
||||||
val pos = caret.getVisualPosition()
|
val pos = caret.getVisualPosition()
|
||||||
if ((pos.line == 0 && count < 0) || (pos.line >= editor.getVisualLineCount() - 1 && count > 0)) {
|
if ((pos.line == 0 && count < 0) || (pos.line >= editor.getVisualLineCount() - 1 && count > 0)) {
|
||||||
return Motion.Error
|
return Motion.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
val intendedColumn = caret.vimLastColumn
|
val intendedColumn = caret.vimLastColumn
|
||||||
val line = editor.normalizeVisualLine(pos.line + count)
|
val line = if (bufferLines)
|
||||||
|
// TODO Does not work with folds, but I don't use those.
|
||||||
|
editor.normalizeVisualLine(editor.bufferLineToVisualLine(editor.visualLineToBufferLine(pos.line) + count))
|
||||||
|
else
|
||||||
|
editor.normalizeVisualLine(pos.line + count)
|
||||||
|
|
||||||
if (intendedColumn == LAST_COLUMN) {
|
if (intendedColumn == LAST_COLUMN) {
|
||||||
val normalisedColumn = injector.engineEditorHelper.normalizeVisualColumn(
|
val normalisedColumn = injector.engineEditorHelper.normalizeVisualColumn(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
|||||||
import com.maddyhome.idea.vim.api.VimCaret
|
import com.maddyhome.idea.vim.api.VimCaret
|
||||||
import com.maddyhome.idea.vim.api.VimCaretListener
|
import com.maddyhome.idea.vim.api.VimCaretListener
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
|
import com.maddyhome.idea.vim.api.VimMotionGroupBase
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.api.normalizeOffset
|
import com.maddyhome.idea.vim.api.normalizeOffset
|
||||||
import com.maddyhome.idea.vim.command.Argument
|
import com.maddyhome.idea.vim.command.Argument
|
||||||
@@ -226,7 +227,15 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
|
|||||||
StrictMode.assert(caret.isPrimary, "Block selection mode must only operate on primary caret")
|
StrictMode.assert(caret.isPrimary, "Block selection mode must only operate on primary caret")
|
||||||
}
|
}
|
||||||
|
|
||||||
val normalisedOffset = prepareMoveToAbsoluteOffset(editor, cmd, offset)
|
val normalisedOffset = prepareMoveToAbsoluteOffset(editor, cmd, offset).let {
|
||||||
|
if (offset.intendedColumn == VimMotionGroupBase.LAST_COLUMN) {
|
||||||
|
val softWrapStart = editor.getSoftWrapStartAtOffset(it)
|
||||||
|
if (softWrapStart != null) softWrapStart - 1 else it
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
StrictMode.assert(normalisedOffset == offset.offset, "Adjusted offset should be normalised by action")
|
StrictMode.assert(normalisedOffset == offset.offset, "Adjusted offset should be normalised by action")
|
||||||
|
|
||||||
// Set before moving, so it can be applied during move, especially important for LAST_COLUMN and visual block mode
|
// Set before moving, so it can be applied during move, especially important for LAST_COLUMN and visual block mode
|
||||||
|
|||||||
@@ -793,6 +793,10 @@ class VimRegex(pattern: String) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getSoftWrapStartAtOffset(offset: Int): Int? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAllFoldRegions(): List<VimFoldRegion> {
|
override fun getAllFoldRegions(): List<VimFoldRegion> {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user