1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-10-16 15:39:36 +02:00

Compare commits

...

1 Commits

Author SHA1 Message Date
5aaa84744f Improve support for recording macros with code completion
Fixes wrong recorded inputs when code completion introduces an import.

Fixes wrong recorded inputs when completing a static member with a partial type name. Example: `WiE.A` -> `WindowEvent.ACTION_EVENT_MASK`
2025-10-08 05:20:08 +02:00

View File

@@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.actions.EnterAction import com.intellij.openapi.editor.actions.EnterAction
import com.intellij.openapi.keymap.KeymapManager import com.intellij.openapi.keymap.KeymapManager
import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.project.DumbAwareToggleAction
@@ -38,6 +39,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.VimShortcutKeyAction import com.maddyhome.idea.vim.action.VimShortcutKeyAction
import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.group.NotificationService import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.group.RegisterGroup
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.newapi.globalIjOptions import com.maddyhome.idea.vim.newapi.globalIjOptions
import com.maddyhome.idea.vim.newapi.initInjector import com.maddyhome.idea.vim.newapi.initInjector
@@ -61,8 +63,7 @@ internal object IdeaSpecifics {
private val surrounderAction = private val surrounderAction =
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction" "com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null private var editor: Editor? = null
private var completionPrevDocumentLength: Int? = null private var completionData: CompletionData? = null
private var completionPrevDocumentOffset: Int? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (VimPlugin.isNotEnabled()) return if (VimPlugin.isNotEnabled()) return
@@ -108,17 +109,36 @@ internal object IdeaSpecifics {
if (hostEditor != null && action is ChooseItemAction && injector.registerGroup.isRecording) { if (hostEditor != null && action is ChooseItemAction && injector.registerGroup.isRecording) {
val lookup = LookupManager.getActiveLookup(hostEditor) val lookup = LookupManager.getActiveLookup(hostEditor)
if (lookup != null) { val lookupItem = lookup?.currentItem
val charsToRemove = hostEditor.caretModel.primaryCaret.offset - lookup.lookupStart if (lookup is LookupImpl && lookupItem != null) {
val caretOffset = hostEditor.caretModel.primaryCaret.offset
val completionPrefixLength = lookup.itemMatcher(lookupItem).prefix.length + lookup.additionalPrefix.length
val completionStartOffset = caretOffset - completionPrefixLength
val documentLength = hostEditor.document.textLength
val charsToRemove = caretOffset - completionStartOffset
val register = VimPlugin.getRegister() val register = VimPlugin.getRegister()
val backSpace = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
repeat(charsToRemove) { if (charsToRemove > 0) {
register.recordKeyStroke(backSpace) val backSpaceKey = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
repeat(charsToRemove) {
register.recordKeyStroke(backSpaceKey)
}
} }
completionPrevDocumentLength = hostEditor.document.textLength - charsToRemove val completionStartMarker = hostEditor.document.createRangeMarker(
completionPrevDocumentOffset = lookup.lookupStart completionStartOffset,
completionStartOffset
).apply {
isGreedyToLeft = true
}
completionData = CompletionData(
completionStartMarker,
completionStartOffset,
caretOffset,
documentLength - charsToRemove
)
} }
} }
} }
@@ -128,30 +148,7 @@ internal object IdeaSpecifics {
val editor = editor val editor = editor
if (editor != null && action is ChooseItemAction && injector.registerGroup.isRecording) { if (editor != null && action is ChooseItemAction && injector.registerGroup.isRecording) {
val prevDocumentLength = completionPrevDocumentLength completionData?.recordCompletion(editor, VimPlugin.getRegister())
val prevDocumentOffset = completionPrevDocumentOffset
if (prevDocumentLength != null && prevDocumentOffset != null) {
val register = VimPlugin.getRegister()
val addedTextLength = editor.document.textLength - prevDocumentLength
val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
register.recordText(
editor.document.getText(
TextRange(
prevDocumentOffset,
prevDocumentOffset + addedTextLength
)
)
)
repeat(caretShift.coerceAtLeast(0)) {
register.recordKeyStroke(leftArrow)
}
}
this.completionPrevDocumentLength = null
this.completionPrevDocumentOffset = null
} }
//region Enter insert mode after surround with if //region Enter insert mode after surround with if
@@ -170,6 +167,46 @@ internal object IdeaSpecifics {
//endregion //endregion
this.editor = null this.editor = null
this.completionData?.dispose()
this.completionData = null
}
private data class CompletionData(
val completionStartMarker: RangeMarker,
val originalStartOffset: Int,
val originalCaretOffset: Int,
val originalDocumentLength: Int
) {
fun recordCompletion(editor: Editor, register: RegisterGroup) {
if (!completionStartMarker.isValid) {
return
}
val completionStartOffset = completionStartMarker.startOffset
val caretOffset = editor.caretModel.primaryCaret.offset
val completedCharCount = editor.document.textLength - originalDocumentLength - (completionStartOffset - originalStartOffset)
val completionEndOffset = completionStartOffset + completedCharCount
val completedText = editor.document.getText(TextRange(
completionStartOffset,
completionEndOffset
))
register.recordText(completedText)
val caretShift = completedCharCount - (caretOffset - completionStartOffset)
if (caretShift > 0) {
val leftArrowKey = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
repeat(caretShift) {
register.recordKeyStroke(leftArrowKey)
}
}
}
fun dispose() {
completionStartMarker.dispose()
}
} }
} }