mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-06-05 13:34:04 +02:00
[New Typing Handler]: Switch j
command to new typing handler
This commit is contained in:
parent
2829a13187
commit
43a79dbad4
build.gradle.kts
src
main
java/com/maddyhome/idea/vim
resources/META-INF
test/java/org/jetbrains/plugins/ideavim
vim-engine/src/main/kotlin/com/maddyhome/idea/vim
@ -242,7 +242,7 @@ tasks {
|
|||||||
|
|
||||||
// Don't forget to update plugin.xml
|
// Don't forget to update plugin.xml
|
||||||
patchPluginXml {
|
patchPluginXml {
|
||||||
sinceBuild.set("222")
|
sinceBuild.set("222.4167.9")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,11 @@ class VimTypedActionHandler(origHandler: TypedActionHandler) : TypedActionHandle
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useNewHandler(editor.vim, charTyped)) {
|
||||||
|
(KeyHandlerKeeper.getInstance().originalHandler as? TypedActionHandlerEx)?.beforeExecute(editor, charTyped, context, plan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
LOG.trace("Executing before execute")
|
LOG.trace("Executing before execute")
|
||||||
val modifiers = if (charTyped == ' ' && VimKeyListener.isSpaceShift) KeyEvent.SHIFT_DOWN_MASK else 0
|
val modifiers = if (charTyped == ' ' && VimKeyListener.isSpaceShift) KeyEvent.SHIFT_DOWN_MASK else 0
|
||||||
val keyStroke = KeyStroke.getKeyStroke(charTyped, modifiers)
|
val keyStroke = KeyStroke.getKeyStroke(charTyped, modifiers)
|
||||||
@ -80,12 +85,17 @@ class VimTypedActionHandler(origHandler: TypedActionHandler) : TypedActionHandle
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useNewHandler(editor.vim, charTyped)) {
|
||||||
|
KeyHandlerKeeper.getInstance().originalHandler.execute(editor, charTyped, context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG.trace("Executing typed action")
|
LOG.trace("Executing typed action")
|
||||||
val modifiers = if (charTyped == ' ' && VimKeyListener.isSpaceShift) KeyEvent.SHIFT_DOWN_MASK else 0
|
val modifiers = if (charTyped == ' ' && VimKeyListener.isSpaceShift) KeyEvent.SHIFT_DOWN_MASK else 0
|
||||||
val keyStroke = KeyStroke.getKeyStroke(charTyped, modifiers)
|
val keyStroke = KeyStroke.getKeyStroke(charTyped, modifiers)
|
||||||
val startTime = if (traceTime) System.currentTimeMillis() else null
|
val startTime = if (traceTime) System.currentTimeMillis() else null
|
||||||
handler.handleKey(editor.vim, keyStroke, EditorDataContext.init(editor, context).vim)
|
handler.handleKeyInitial(editor.vim, keyStroke, EditorDataContext.init(editor, context).vim)
|
||||||
if (startTime != null) {
|
if (startTime != null) {
|
||||||
val duration = System.currentTimeMillis() - startTime
|
val duration = System.currentTimeMillis() - startTime
|
||||||
LOG.info("VimTypedAction '$charTyped': $duration ms")
|
LOG.info("VimTypedAction '$charTyped': $duration ms")
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||||
|
* Copyright (C) 2003-2022 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.maddyhome.idea.vim
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.editorActions.TypedHandlerDelegate
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
|
import com.maddyhome.idea.vim.helper.EditorDataContext
|
||||||
|
import com.maddyhome.idea.vim.helper.inInsertMode
|
||||||
|
import com.maddyhome.idea.vim.helper.inNormalMode
|
||||||
|
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
|
class VimTypedDelegateHandler : TypedHandlerDelegate() {
|
||||||
|
|
||||||
|
lateinit var stateUpdateResult: KeyHandler.StateUpdateResult
|
||||||
|
|
||||||
|
override fun checkAutoPopup(charTyped: Char, project: Project, editor: Editor, file: PsiFile): Result {
|
||||||
|
if (!VimPlugin.isEnabled()) return Result.CONTINUE
|
||||||
|
if (editor.isIdeaVimDisabledHere) return Result.CONTINUE
|
||||||
|
if (!useNewHandler(editor.vim, charTyped)) return Result.CONTINUE
|
||||||
|
|
||||||
|
return if (editor.inInsertMode) Result.CONTINUE else Result.STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newTypingStarted(c: Char, editor: Editor, context: DataContext) {
|
||||||
|
if (!VimPlugin.isEnabled()) return
|
||||||
|
if (editor.isIdeaVimDisabledHere) return
|
||||||
|
if (!useNewHandler(editor.vim, c)) return
|
||||||
|
|
||||||
|
val keyStroke = KeyStroke.getKeyStroke(c)
|
||||||
|
val content = EditorDataContext.init(editor, context)
|
||||||
|
content.newTypingDelegate = true
|
||||||
|
stateUpdateResult = KeyHandler.getInstance()
|
||||||
|
.handleKeyInitial(editor.vim, keyStroke, content.vim, execute = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beforeCharTyped(c: Char, project: Project, editor: Editor, file: PsiFile, fileType: FileType): Result {
|
||||||
|
if (!VimPlugin.isEnabled()) return Result.CONTINUE
|
||||||
|
if (editor.isIdeaVimDisabledHere) return Result.CONTINUE
|
||||||
|
if (!useNewHandler(editor.vim, c)) return Result.CONTINUE
|
||||||
|
|
||||||
|
val keyStroke = KeyStroke.getKeyStroke(c)
|
||||||
|
val context = EditorDataContext.init(editor)
|
||||||
|
context.newTypingDelegate = true
|
||||||
|
if (stateUpdateResult.continueExecution) {
|
||||||
|
KeyHandler.getInstance().finishedCommandPreparation(editor.vim, context.vim, keyStroke, stateUpdateResult.shouldRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
override fun charTyped(c: Char, project: Project, editor: Editor, file: PsiFile): Result {
|
||||||
|
if (editor.isIdeaVimDisabledHere) return Result.CONTINUE
|
||||||
|
if (c !in charsByDelegate) return Result.CONTINUE
|
||||||
|
|
||||||
|
val keyStroke = KeyStroke.getKeyStroke(c)
|
||||||
|
KeyHandler.getInstance().handleKey(editor.vim, keyStroke, EditorDataContext.init(editor).vim)
|
||||||
|
|
||||||
|
return Result.STOP
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
override fun isImmediatePaintingEnabled(editor: Editor, c: Char, context: DataContext): Boolean {
|
||||||
|
if (!VimPlugin.isEnabled()) return true
|
||||||
|
if (editor.isIdeaVimDisabledHere) return true
|
||||||
|
if (!useNewHandler(editor.vim, c)) return true
|
||||||
|
|
||||||
|
return editor.inInsertMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val charsByDelegate = setOf('j')
|
||||||
|
|
||||||
|
internal fun useNewHandler(editor: VimEditor, c: Char): Boolean {
|
||||||
|
return c in charsByDelegate && editor.inNormalMode
|
||||||
|
}
|
@ -82,7 +82,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
|
|||||||
// Should we use HelperKt.getTopLevelEditor(editor) here, as we did in former EditorKeyHandler?
|
// Should we use HelperKt.getTopLevelEditor(editor) here, as we did in former EditorKeyHandler?
|
||||||
try {
|
try {
|
||||||
val start = if (traceTime) System.currentTimeMillis() else null
|
val start = if (traceTime) System.currentTimeMillis() else null
|
||||||
KeyHandler.getInstance().handleKey(editor.vim, keyStroke, EditorDataContext.init(editor, e.dataContext).vim)
|
KeyHandler.getInstance().handleKeyInitial(editor.vim, keyStroke, EditorDataContext.init(editor, e.dataContext).vim)
|
||||||
if (start != null) {
|
if (start != null) {
|
||||||
val duration = System.currentTimeMillis() - start
|
val duration = System.currentTimeMillis() - start
|
||||||
LOG.info("VimShortcut update '$keyStroke': $duration ms")
|
LOG.info("VimShortcut update '$keyStroke': $duration ms")
|
||||||
|
@ -73,7 +73,7 @@ public class MacroGroup extends VimMacroBase {
|
|||||||
final Runnable run = () -> {
|
final Runnable run = () -> {
|
||||||
// Handle one keystroke then queue up the next key
|
// Handle one keystroke then queue up the next key
|
||||||
if (keyStack.hasStroke()) {
|
if (keyStack.hasStroke()) {
|
||||||
KeyHandler.getInstance().handleKey(editor, keyStack.feedStroke(), context);
|
KeyHandler.getInstance().handleKey(editor, keyStack.feedStroke(), context, true, false, true);
|
||||||
}
|
}
|
||||||
if (keyStack.hasStroke()) {
|
if (keyStack.hasStroke()) {
|
||||||
playbackKeys(editor, context, cnt, total);
|
playbackKeys(editor, context, cnt, total);
|
||||||
@ -105,7 +105,7 @@ public class MacroGroup extends VimMacroBase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProgressManager.getInstance().executeNonCancelableSection(() -> {
|
ProgressManager.getInstance().executeNonCancelableSection(() -> {
|
||||||
KeyHandler.getInstance().handleKey(editor, key, context);
|
KeyHandler.getInstance().handleKey(editor, key, context, true, false, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
keyStack.resetFirst();
|
keyStack.resetFirst();
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package com.maddyhome.idea.vim.helper
|
package com.maddyhome.idea.vim.helper
|
||||||
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
|
import com.intellij.openapi.actionSystem.DataKey
|
||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
@ -27,6 +28,9 @@ class EditorDataContext @Deprecated("Please use `init` method") constructor(
|
|||||||
private val editor: Editor,
|
private val editor: Editor,
|
||||||
private val contextDelegate: DataContext? = null,
|
private val contextDelegate: DataContext? = null,
|
||||||
) : DataContext, UserDataHolder {
|
) : DataContext, UserDataHolder {
|
||||||
|
|
||||||
|
internal var newTypingDelegate = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the object corresponding to the specified data identifier. Some of the supported data identifiers are
|
* Returns the object corresponding to the specified data identifier. Some of the supported data identifiers are
|
||||||
* defined in the [PlatformDataKeys] class.
|
* defined in the [PlatformDataKeys] class.
|
||||||
@ -38,6 +42,7 @@ class EditorDataContext @Deprecated("Please use `init` method") constructor(
|
|||||||
PlatformDataKeys.EDITOR.name == dataId -> editor
|
PlatformDataKeys.EDITOR.name == dataId -> editor
|
||||||
PlatformDataKeys.PROJECT.name == dataId -> editor.project
|
PlatformDataKeys.PROJECT.name == dataId -> editor.project
|
||||||
PlatformDataKeys.VIRTUAL_FILE.name == dataId -> EditorHelper.getVirtualFile(editor)
|
PlatformDataKeys.VIRTUAL_FILE.name == dataId -> EditorHelper.getVirtualFile(editor)
|
||||||
|
NEW_DELEGATE.name == dataId -> newTypingDelegate
|
||||||
else -> contextDelegate?.getData(dataId)
|
else -> contextDelegate?.getData(dataId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,3 +76,5 @@ class EditorDataContext @Deprecated("Please use `init` method") constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val NEW_DELEGATE = DataKey.create<Boolean>("IdeaVim.NEW_DELEGATE")
|
||||||
|
@ -22,11 +22,16 @@ import com.intellij.openapi.actionSystem.DataContext
|
|||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.helper.EditorDataContext
|
import com.maddyhome.idea.vim.helper.EditorDataContext
|
||||||
|
import com.maddyhome.idea.vim.helper.NEW_DELEGATE
|
||||||
|
|
||||||
class IjExecutionContext(override val context: DataContext) : ExecutionContext {
|
class IjExecutionContext(override val context: DataContext) : ExecutionContext {
|
||||||
override fun updateEditor(editor: VimEditor): ExecutionContext {
|
override fun updateEditor(editor: VimEditor): ExecutionContext {
|
||||||
return IjExecutionContext(EditorDataContext.init((editor as IjVimEditor).editor, context))
|
return IjExecutionContext(EditorDataContext.init((editor as IjVimEditor).editor, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isNewDelegate(): Boolean {
|
||||||
|
return context.getData(NEW_DELEGATE) ?: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val DataContext.vim
|
val DataContext.vim
|
||||||
|
@ -126,7 +126,7 @@
|
|||||||
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
||||||
<!-- Check for [Version Update] tag in YouTrack as well -->
|
<!-- Check for [Version Update] tag in YouTrack as well -->
|
||||||
<!-- Also, please update the value in build.gradle.kts file-->
|
<!-- Also, please update the value in build.gradle.kts file-->
|
||||||
<idea-version since-build="222"/>
|
<idea-version since-build="222.4167.9"/>
|
||||||
|
|
||||||
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
||||||
<depends>com.intellij.modules.platform</depends>
|
<depends>com.intellij.modules.platform</depends>
|
||||||
@ -193,6 +193,8 @@
|
|||||||
<statistics.applicationUsagesCollector implementation="com.maddyhome.idea.vim.statistic.ShortcutConflictState"/>
|
<statistics.applicationUsagesCollector implementation="com.maddyhome.idea.vim.statistic.ShortcutConflictState"/>
|
||||||
|
|
||||||
<statistics.counterUsagesCollector implementationClass="com.maddyhome.idea.vim.statistic.ActionTracker"/>
|
<statistics.counterUsagesCollector implementationClass="com.maddyhome.idea.vim.statistic.ActionTracker"/>
|
||||||
|
|
||||||
|
<typedHandler implementation="com.maddyhome.idea.vim.VimTypedDelegateHandler" order="first, before completionAutoPopup"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
<xi:include href="/META-INF/includes/ApplicationServices.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||||
|
@ -99,7 +99,7 @@ public abstract class JavaVimTestCase extends JavaCodeInsightFixtureTestCase {
|
|||||||
exEntryPanel.handleKey(key);
|
exEntryPanel.handleKey(key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
keyHandler.handleKey(new IjVimEditor(editor), key, new IjExecutionContext(dataContext));
|
keyHandler.handleKey(new IjVimEditor(editor), key, new IjExecutionContext(dataContext), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, null, null);
|
}, null, null);
|
||||||
|
@ -29,6 +29,36 @@ import org.jetbrains.plugins.ideavim.VimTestCase
|
|||||||
* @author Alex Plate
|
* @author Alex Plate
|
||||||
*/
|
*/
|
||||||
class MotionDownActionTest : VimTestCase() {
|
class MotionDownActionTest : VimTestCase() {
|
||||||
|
fun `test simple motion down`() {
|
||||||
|
val keys = injector.parser.parseKeys("j")
|
||||||
|
val before = """
|
||||||
|
I found it in a ${c}legendary land
|
||||||
|
all rocks and lavender and tufted grass,
|
||||||
|
""".trimIndent()
|
||||||
|
val after = """
|
||||||
|
I found it in a legendary land
|
||||||
|
all rocks and la${c}vender and tufted grass,
|
||||||
|
""".trimIndent()
|
||||||
|
configureByText(before)
|
||||||
|
typeText(keys)
|
||||||
|
assertState(after)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test simple motion down multicaret`() {
|
||||||
|
val keys = injector.parser.parseKeys("j")
|
||||||
|
val before = """
|
||||||
|
I found it in a ${c}legendary ${c}land
|
||||||
|
all rocks and lavender and tufted grass,
|
||||||
|
""".trimIndent()
|
||||||
|
val after = """
|
||||||
|
I found it in a legendary land
|
||||||
|
all rocks and la${c}vender and${c} tufted grass,
|
||||||
|
""".trimIndent()
|
||||||
|
configureByText(before)
|
||||||
|
typeText(keys)
|
||||||
|
assertState(after)
|
||||||
|
}
|
||||||
|
|
||||||
fun `test motion down in visual block mode`() {
|
fun `test motion down in visual block mode`() {
|
||||||
val keys = "<C-V>2kjjj"
|
val keys = "<C-V>2kjjj"
|
||||||
val before = """
|
val before = """
|
||||||
|
@ -56,6 +56,11 @@ import java.awt.event.KeyEvent
|
|||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
|
|
||||||
|
data class KeyRoundInfo(
|
||||||
|
var commandState: CurrentCommandState,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles every keystroke that the user can argType except those that are still valid hotkeys for various Idea
|
* This handles every keystroke that the user can argType except those that are still valid hotkeys for various Idea
|
||||||
* actions. This is a singleton.
|
* actions. This is a singleton.
|
||||||
@ -67,6 +72,13 @@ class KeyHandler {
|
|||||||
val keyStack = KeyStack()
|
val keyStack = KeyStack()
|
||||||
val modalEntryKeys: MutableList<KeyStroke> = ArrayList()
|
val modalEntryKeys: MutableList<KeyStroke> = ArrayList()
|
||||||
|
|
||||||
|
fun handleKeyInitial(editor: VimEditor, key: KeyStroke, context: ExecutionContext, execute: Boolean = true): StateUpdateResult {
|
||||||
|
if (editor.vimStateMachine.commandBuilder.isReady) {
|
||||||
|
editor.vimStateMachine.commandBuilder.resetAll(getKeyRoot(editor.vimStateMachine.mappingState.mappingMode))
|
||||||
|
}
|
||||||
|
return handleKey(editor, key, context, execute)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main key handler for the Vim plugin. Every keystroke not handled directly by Idea is sent here for
|
* This is the main key handler for the Vim plugin. Every keystroke not handled directly by Idea is sent here for
|
||||||
* processing.
|
* processing.
|
||||||
@ -75,10 +87,15 @@ class KeyHandler {
|
|||||||
* @param key The keystroke typed by the user
|
* @param key The keystroke typed by the user
|
||||||
* @param context The data context
|
* @param context The data context
|
||||||
*/
|
*/
|
||||||
fun handleKey(editor: VimEditor, key: KeyStroke, context: ExecutionContext) {
|
fun handleKey(editor: VimEditor, key: KeyStroke, context: ExecutionContext, execute: Boolean = true): StateUpdateResult {
|
||||||
handleKey(editor, key, context, allowKeyMappings = true, mappingCompleted = false)
|
return handleKey(editor, key, context, allowKeyMappings = true, mappingCompleted = false, execute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class StateUpdateResult(
|
||||||
|
val continueExecution: Boolean,
|
||||||
|
val shouldRecord: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handling input keys with additional parameters
|
* Handling input keys with additional parameters
|
||||||
*
|
*
|
||||||
@ -93,7 +110,8 @@ class KeyHandler {
|
|||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
allowKeyMappings: Boolean,
|
allowKeyMappings: Boolean,
|
||||||
mappingCompleted: Boolean,
|
mappingCompleted: Boolean,
|
||||||
) {
|
execute: Boolean = true,
|
||||||
|
): StateUpdateResult {
|
||||||
LOG.trace {
|
LOG.trace {
|
||||||
"""
|
"""
|
||||||
------- Key Handler -------
|
------- Key Handler -------
|
||||||
@ -112,7 +130,7 @@ class KeyHandler {
|
|||||||
injector.messages.showStatusBarMessage(injector.messages.message("E223"))
|
injector.messages.showStatusBarMessage(injector.messages.message("E223"))
|
||||||
injector.messages.indicateError()
|
injector.messages.indicateError()
|
||||||
LOG.warn("Key handling, maximum recursion of the key received. maxdepth=$mapMapDepth")
|
LOG.warn("Key handling, maximum recursion of the key received. maxdepth=$mapMapDepth")
|
||||||
return
|
return StateUpdateResult(false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
injector.messages.clearError()
|
injector.messages.clearError()
|
||||||
@ -186,17 +204,20 @@ class KeyHandler {
|
|||||||
} finally {
|
} finally {
|
||||||
handleKeyRecursionCount--
|
handleKeyRecursionCount--
|
||||||
}
|
}
|
||||||
finishedCommandPreparation(editor, context, editorState, commandBuilder, key, shouldRecord)
|
if (execute) {
|
||||||
|
finishedCommandPreparation(editor, context, key, shouldRecord)
|
||||||
|
}
|
||||||
|
return StateUpdateResult(true, shouldRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finishedCommandPreparation(
|
fun finishedCommandPreparation(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
editorState: VimStateMachine,
|
|
||||||
commandBuilder: CommandBuilder,
|
|
||||||
key: KeyStroke?,
|
key: KeyStroke?,
|
||||||
shouldRecord: Boolean,
|
shouldRecord: Boolean,
|
||||||
) {
|
) {
|
||||||
|
val editorState = editor.vimStateMachine
|
||||||
|
val commandBuilder = editorState.commandBuilder
|
||||||
// Do we have a fully entered command at this point? If so, let's execute it.
|
// Do we have a fully entered command at this point? If so, let's execute it.
|
||||||
if (commandBuilder.isReady) {
|
if (commandBuilder.isReady) {
|
||||||
LOG.trace("Ready command builder. Execute command.")
|
LOG.trace("Ready command builder. Execute command.")
|
||||||
@ -657,7 +678,7 @@ class KeyHandler {
|
|||||||
editorState: VimStateMachine,
|
editorState: VimStateMachine,
|
||||||
) {
|
) {
|
||||||
LOG.trace("Command execution")
|
LOG.trace("Command execution")
|
||||||
val command = editorState.commandBuilder.buildCommand()
|
val command = editorState.commandBuilder.buildCommand(context)
|
||||||
val operatorArguments = OperatorArguments(
|
val operatorArguments = OperatorArguments(
|
||||||
editorState.mappingState.mappingMode == MappingMode.OP_PENDING,
|
editorState.mappingState.mappingMode == MappingMode.OP_PENDING,
|
||||||
command.rawCount, editorState.mode, editorState.subMode
|
command.rawCount, editorState.mode, editorState.subMode
|
||||||
@ -866,7 +887,9 @@ class KeyHandler {
|
|||||||
) : Runnable {
|
) : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val editorState = getInstance(editor)
|
val editorState = getInstance(editor)
|
||||||
editorState.commandBuilder.commandState = CurrentCommandState.NEW_COMMAND
|
if (!context.isNewDelegate()) {
|
||||||
|
editorState.commandBuilder.commandState = CurrentCommandState.NEW_COMMAND
|
||||||
|
}
|
||||||
val register = cmd.register
|
val register = cmd.register
|
||||||
if (register != null) {
|
if (register != null) {
|
||||||
injector.registerGroup.selectRegister(register)
|
injector.registerGroup.selectRegister(register)
|
||||||
|
@ -27,6 +27,7 @@ interface ExecutionContext {
|
|||||||
|
|
||||||
// TODO: 10.02.2022 Not sure about this method
|
// TODO: 10.02.2022 Not sure about this method
|
||||||
fun updateEditor(editor: VimEditor): ExecutionContext
|
fun updateEditor(editor: VimEditor): ExecutionContext
|
||||||
|
fun isNewDelegate(): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExecutionContextManager {
|
interface ExecutionContextManager {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package com.maddyhome.idea.vim.command
|
package com.maddyhome.idea.vim.command
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimActionsInitiator
|
import com.maddyhome.idea.vim.api.VimActionsInitiator
|
||||||
import com.maddyhome.idea.vim.common.CurrentCommandState
|
import com.maddyhome.idea.vim.common.CurrentCommandState
|
||||||
import com.maddyhome.idea.vim.diagnostic.debug
|
import com.maddyhome.idea.vim.diagnostic.debug
|
||||||
@ -156,13 +157,14 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode<VimActi
|
|||||||
return commandParts.peek()?.argument != null
|
return commandParts.peek()?.argument != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildCommand(): Command {
|
fun buildCommand(context: ExecutionContext): Command {
|
||||||
if (commandParts.last.action.id == "VimInsertCompletedDigraphAction" || commandParts.last.action.id == "VimResetModeAction") {
|
if (commandParts.last.action.id == "VimInsertCompletedDigraphAction" || commandParts.last.action.id == "VimResetModeAction") {
|
||||||
expectedArgumentType = prevExpectedArgumentType
|
expectedArgumentType = prevExpectedArgumentType
|
||||||
prevExpectedArgumentType = null
|
prevExpectedArgumentType = null
|
||||||
return commandParts.removeLast()
|
return commandParts.removeLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val original = ArrayDeque(commandParts)
|
||||||
var command: Command = commandParts.removeFirst()
|
var command: Command = commandParts.removeFirst()
|
||||||
while (commandParts.size > 0) {
|
while (commandParts.size > 0) {
|
||||||
val next = commandParts.removeFirst()
|
val next = commandParts.removeFirst()
|
||||||
@ -174,17 +176,22 @@ class CommandBuilder(private var currentCommandPartNode: CommandPartNode<VimActi
|
|||||||
command = next
|
command = next
|
||||||
} else {
|
} else {
|
||||||
command.argument = Argument(next)
|
command.argument = Argument(next)
|
||||||
assert(commandParts.size == 0)
|
// assert(commandParts.size == 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (context.isNewDelegate()) {
|
||||||
|
commandParts.addAll(original)
|
||||||
|
}
|
||||||
expectedArgumentType = null
|
expectedArgumentType = null
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetAll(commandPartNode: CommandPartNode<VimActionsInitiator>) {
|
fun resetAll(commandPartNode: CommandPartNode<VimActionsInitiator>, setNewCommand: Boolean = true) {
|
||||||
resetInProgressCommandPart(commandPartNode)
|
resetInProgressCommandPart(commandPartNode)
|
||||||
commandState = CurrentCommandState.NEW_COMMAND
|
if (setNewCommand) {
|
||||||
commandParts.clear()
|
commandState = CurrentCommandState.NEW_COMMAND
|
||||||
|
commandParts.clear()
|
||||||
|
}
|
||||||
keyList.clear()
|
keyList.clear()
|
||||||
expectedArgumentType = null
|
expectedArgumentType = null
|
||||||
prevExpectedArgumentType = null
|
prevExpectedArgumentType = null
|
||||||
|
@ -76,10 +76,14 @@ abstract class EditorActionHandlerBase(private val myRunForEachCaret: Boolean) {
|
|||||||
|
|
||||||
fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
val action = { caret: VimCaret -> doExecute(editor, caret, context, operatorArguments) }
|
val action = { caret: VimCaret -> doExecute(editor, caret, context, operatorArguments) }
|
||||||
if (myRunForEachCaret) {
|
if (!context.isNewDelegate()) {
|
||||||
editor.forEachCaret(action)
|
if (myRunForEachCaret) {
|
||||||
|
editor.forEachCaret(action)
|
||||||
|
} else {
|
||||||
|
action(editor.primaryCaret())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
action(editor.primaryCaret())
|
action(editor.currentCaret())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
|
|||||||
|
|
||||||
when (this) {
|
when (this) {
|
||||||
is SingleExecution -> run {
|
is SingleExecution -> run {
|
||||||
|
if (context.isNewDelegate() && !(caret == editor.currentCaret())) return@run
|
||||||
if (!preOffsetComputation(editor, context, cmd)) return@run
|
if (!preOffsetComputation(editor, context, cmd)) return@run
|
||||||
|
|
||||||
val offset = getOffset(editor, context, cmd.argument, operatorArguments)
|
val offset = getOffset(editor, context, cmd.argument, operatorArguments)
|
||||||
@ -177,34 +178,77 @@ sealed class MotionActionHandler : EditorActionHandlerBase(false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ForEachCaret -> run {
|
is ForEachCaret -> run {
|
||||||
when {
|
if (!context.isNewDelegate()) {
|
||||||
blockSubmodeActive || editor.carets().size == 1 -> {
|
when {
|
||||||
val primaryCaret = editor.primaryCaret()
|
blockSubmodeActive || editor.carets().size == 1 -> {
|
||||||
doExecuteForEach(editor, primaryCaret, context, cmd, operatorArguments)
|
val primaryCaret = editor.primaryCaret()
|
||||||
}
|
doExecuteForEach(editor, primaryCaret, context, cmd, operatorArguments)
|
||||||
else -> {
|
}
|
||||||
try {
|
else -> {
|
||||||
editor.addCaretListener(CaretMergingWatcher)
|
try {
|
||||||
editor.forEachCaret { caret ->
|
editor.addCaretListener(CaretMergingWatcher)
|
||||||
doExecuteForEach(
|
editor.forEachCaret { caret ->
|
||||||
editor,
|
doExecuteForEach(
|
||||||
caret,
|
editor,
|
||||||
context,
|
caret,
|
||||||
cmd,
|
context,
|
||||||
operatorArguments
|
cmd,
|
||||||
)
|
operatorArguments
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
editor.removeCaretListener(CaretMergingWatcher)
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
editor.removeCaretListener(CaretMergingWatcher)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
doExecuteForEach(
|
||||||
|
editor,
|
||||||
|
caret,
|
||||||
|
context,
|
||||||
|
cmd,
|
||||||
|
operatorArguments
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun SingleExecution.singleAction(
|
||||||
|
editor: VimEditor,
|
||||||
|
context: ExecutionContext,
|
||||||
|
cmd: Command,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
) {
|
||||||
|
if (!preOffsetComputation(editor, context, cmd)) return
|
||||||
|
|
||||||
|
val offset = getOffset(editor, context, cmd.argument, operatorArguments)
|
||||||
|
|
||||||
|
when (offset) {
|
||||||
|
is Motion.AbsoluteOffset -> {
|
||||||
|
var resultOffset = offset.offset
|
||||||
|
if (resultOffset < 0) {
|
||||||
|
logger.error("Offset is less than 0. $resultOffset. ${this.javaClass.name}")
|
||||||
|
}
|
||||||
|
if (CommandFlags.FLAG_SAVE_JUMP in cmd.flags) {
|
||||||
|
injector.markGroup.saveJumpLocation(editor)
|
||||||
|
}
|
||||||
|
if (!editor.isEndAllowed) {
|
||||||
|
resultOffset = injector.engineEditorHelper.normalizeOffset(editor, resultOffset, false)
|
||||||
|
}
|
||||||
|
preMove(editor, context, cmd)
|
||||||
|
editor.primaryCaret().moveToOffset(resultOffset)
|
||||||
|
postMove(editor, context, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
is Motion.Error -> injector.messages.indicateError()
|
||||||
|
is Motion.NoMotion -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun doExecuteForEach(
|
private fun doExecuteForEach(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
caret: VimCaret,
|
caret: VimCaret,
|
||||||
|
@ -175,7 +175,9 @@ class ToHandlerMappingInfo(
|
|||||||
injector.application.invokeLater {
|
injector.application.invokeLater {
|
||||||
KeyHandler.getInstance().finishedCommandPreparation(
|
KeyHandler.getInstance().finishedCommandPreparation(
|
||||||
editor,
|
editor,
|
||||||
context, VimStateMachine.getInstance(editor), VimStateMachine.getInstance(editor).commandBuilder, null, false
|
context,
|
||||||
|
null,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user