mirror of
https://github.com/chylex/IntelliJ-AceJump.git
synced 2024-11-25 17:42:46 +01:00
Compare commits
3 Commits
8062cf5cab
...
6de52d21b6
Author | SHA1 | Date | |
---|---|---|---|
6de52d21b6 | |||
a07c61a384 | |||
e072003c5c |
23
.gitignore
vendored
23
.gitignore
vendored
@ -1,20 +1,5 @@
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
|
||||
## Directory-based project format:
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
## Plugin-specific files:
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
### Gradle template
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Mac OS
|
||||
.DS_Store
|
||||
/.gradle/
|
||||
/build/
|
||||
|
@ -1,26 +1,43 @@
|
||||
@file:Suppress("ConvertLambdaToReference")
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
idea
|
||||
kotlin("jvm") version "1.5.10"
|
||||
id("org.jetbrains.intellij") version "1.11.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
intellij {
|
||||
version.set("2022.3.1")
|
||||
updateSinceUntilBuild.set(false)
|
||||
pluginsRepositories.custom("https://intellij.chylex.com")
|
||||
plugins.add("IdeaVIM:chylex-15")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=all")
|
||||
kotlin("jvm") version "1.8.0"
|
||||
id("org.jetbrains.intellij") version "1.15.0"
|
||||
}
|
||||
|
||||
group = "org.acejump"
|
||||
version = "chylex-11"
|
||||
version = "chylex-12"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
}
|
||||
|
||||
intellij {
|
||||
version.set("2023.1")
|
||||
updateSinceUntilBuild.set(false)
|
||||
plugins.add("IdeaVIM:chylex-15")
|
||||
|
||||
pluginsRepositories {
|
||||
custom("https://intellij.chylex.com")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.patchPluginXml {
|
||||
sinceBuild.set("231")
|
||||
}
|
||||
|
||||
tasks.buildSearchableOptions {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.freeCompilerArgs = listOf(
|
||||
"-Xjvm-default=all"
|
||||
)
|
||||
}
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -23,7 +23,7 @@ val Project.openEditors: List<Editor>
|
||||
return try {
|
||||
FileEditorManagerEx.getInstanceEx(this)
|
||||
.splitters
|
||||
.selectedEditors
|
||||
.getSelectedEditors()
|
||||
.mapNotNull { (it as? TextEditor)?.editor }
|
||||
} catch (e: IncorrectOperationException) {
|
||||
emptyList()
|
||||
|
@ -1,52 +0,0 @@
|
||||
package org.acejump.action
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import org.acejump.boundaries.Boundaries
|
||||
import org.acejump.openEditors
|
||||
import org.acejump.search.Pattern
|
||||
import org.acejump.session.Session
|
||||
import org.acejump.session.SessionManager
|
||||
|
||||
/**
|
||||
* Base class for keyboard-activated actions that create or update an AceJump [Session].
|
||||
*/
|
||||
abstract class AceKeyboardAction : DumbAwareAction() {
|
||||
final override fun update(action: AnActionEvent) {
|
||||
action.presentation.isEnabled = action.getData(EDITOR) != null
|
||||
}
|
||||
|
||||
final override fun actionPerformed(e: AnActionEvent) {
|
||||
val editor = e.getData(EDITOR) ?: return
|
||||
val project = e.project
|
||||
if (project != null) {
|
||||
val jumpEditors = project.openEditors
|
||||
.sortedBy { if (it === editor) 0 else 1 }
|
||||
.ifEmpty { listOf(editor) }
|
||||
invoke(SessionManager.start(editor, jumpEditors))
|
||||
}
|
||||
else {
|
||||
invoke(SessionManager.start(editor))
|
||||
}
|
||||
}
|
||||
|
||||
abstract operator fun invoke(session: Session)
|
||||
|
||||
/**
|
||||
* Generic action type that starts a regex search.
|
||||
*/
|
||||
abstract class BaseRegexSearchAction(private val pattern: Pattern, private val boundaries: Boundaries) : AceKeyboardAction() {
|
||||
override fun invoke(session: Session) {
|
||||
session.defaultBoundary = boundaries
|
||||
session.startRegexSearch(pattern)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or ends an AceJump session in quick jump mode.
|
||||
*/
|
||||
object ActivateAceJump : AceKeyboardAction() {
|
||||
override fun invoke(session: Session) = session.startJumpMode()
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
package org.acejump.action
|
||||
|
||||
import com.intellij.find.actions.ShowUsagesAction
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.command.UndoConfirmationPolicy
|
||||
import com.intellij.openapi.editor.Document
|
||||
@ -13,12 +9,7 @@ import com.intellij.openapi.fileEditor.TextEditor
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.playback.commands.ActionCommand
|
||||
import org.acejump.countMatchingCharacters
|
||||
import org.acejump.immutableText
|
||||
import org.acejump.isWordPart
|
||||
import org.acejump.search.SearchProcessor
|
||||
import org.acejump.wordStart
|
||||
|
||||
/**
|
||||
* Base class for actions available after typing a tag.
|
||||
@ -47,23 +38,7 @@ sealed class AceTagAction {
|
||||
abstract fun getCaretOffset(editor: Editor, searchProcessor: SearchProcessor, offset: Int): Int
|
||||
}
|
||||
|
||||
abstract class BaseWordAction : BaseJumpAction() {
|
||||
final override fun getCaretOffset(editor: Editor, searchProcessor: SearchProcessor, offset: Int): Int {
|
||||
val matchingChars = countMatchingCharacters(editor, searchProcessor, offset)
|
||||
val targetOffset = offset + matchingChars
|
||||
val isInsideWord = matchingChars > 0 && editor.immutableText.let { it[targetOffset - 1].isWordPart && it[targetOffset].isWordPart }
|
||||
|
||||
return getCaretOffset(editor, offset, targetOffset, isInsideWord)
|
||||
}
|
||||
|
||||
abstract fun getCaretOffset(editor: Editor, queryStartOffset: Int, queryEndOffset: Int, isInsideWord: Boolean): Int
|
||||
}
|
||||
|
||||
private companion object {
|
||||
fun countMatchingCharacters(editor: Editor, searchProcessor: SearchProcessor, offset: Int): Int {
|
||||
return editor.immutableText.countMatchingCharacters(offset, searchProcessor.query.rawText)
|
||||
}
|
||||
|
||||
fun recordCaretPosition(editor: Editor) = with(editor) {
|
||||
project?.let { addCurrentPositionToHistory(it, document) }
|
||||
}
|
||||
@ -73,20 +48,12 @@ sealed class AceTagAction {
|
||||
caretModel.removeSecondaryCarets()
|
||||
caretModel.moveToOffset(offset)
|
||||
}
|
||||
|
||||
fun performAction(actionName: String) {
|
||||
val actionManager = ActionManager.getInstance()
|
||||
val action = actionManager.getAction(actionName)
|
||||
if (action != null) {
|
||||
actionManager.tryToExecute(action, ActionCommand.getInputEvent(null), null, null, true)
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureEditorFocused(editor: Editor) {
|
||||
val project = editor.project ?: return
|
||||
val fem = FileEditorManagerEx.getInstanceEx(project)
|
||||
|
||||
val window = fem.windows.firstOrNull { (it.selectedEditor?.selectedWithProvider?.fileEditor as? TextEditor)?.editor === editor }
|
||||
val window = fem.windows.firstOrNull { (it.selectedComposite?.selectedWithProvider?.fileEditor as? TextEditor)?.editor === editor }
|
||||
if (window != null && window !== fem.currentWindow) {
|
||||
fem.currentWindow = window
|
||||
}
|
||||
@ -114,67 +81,4 @@ sealed class AceTagAction {
|
||||
return offset
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On default action, places the caret at the start of a word. Word detection uses [Character.isJavaIdentifierPart] to count some special
|
||||
* characters, such as underscores, as part of a word. If there is no word at the last character of the search query, then the caret is
|
||||
* placed at the first character of the search query.
|
||||
*
|
||||
* On shift action, adds the new caret to existing carets.
|
||||
*/
|
||||
object JumpToWordStart : BaseWordAction() {
|
||||
override fun getCaretOffset(editor: Editor, queryStartOffset: Int, queryEndOffset: Int, isInsideWord: Boolean): Int {
|
||||
return if (isInsideWord)
|
||||
editor.immutableText.wordStart(queryEndOffset)
|
||||
else
|
||||
queryStartOffset
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On default action, performs the Go To Declaration action, available via `Navigate | Declaration or Usages`.
|
||||
* On shift action, performs the Go To Type Declaration action, available via `Navigate | Type Declaration`.
|
||||
* Always places the caret at the start of the word.
|
||||
*/
|
||||
object GoToDeclaration : AceTagAction() {
|
||||
override fun invoke(editor: Editor, searchProcessor: SearchProcessor, offset: Int, shiftMode: Boolean, isFinal: Boolean) {
|
||||
JumpToWordStart(editor, searchProcessor, offset, shiftMode = false, isFinal = isFinal)
|
||||
ApplicationManager.getApplication().invokeLater { performAction(if (shiftMode) IdeActions.ACTION_GOTO_TYPE_DECLARATION else IdeActions.ACTION_GOTO_DECLARATION) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On default action, performs the Show Usages action, available via the context menu.
|
||||
* On shift action, performs the Find Usages action, available via the context menu.
|
||||
* Always places the caret at the start of the word.
|
||||
*/
|
||||
object ShowUsages : AceTagAction() {
|
||||
override fun invoke(editor: Editor, searchProcessor: SearchProcessor, offset: Int, shiftMode: Boolean, isFinal: Boolean) {
|
||||
JumpToWordStart(editor, searchProcessor, offset, shiftMode = false, isFinal = isFinal)
|
||||
ApplicationManager.getApplication().invokeLater { performAction(if (shiftMode) IdeActions.ACTION_FIND_USAGES else ShowUsagesAction.ID) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the Show Context Actions action, available via the context menu or Alt+Enter.
|
||||
* Always places the caret at the start of the word.
|
||||
*/
|
||||
object ShowIntentions : AceTagAction() {
|
||||
override fun invoke(editor: Editor, searchProcessor: SearchProcessor, offset: Int, shiftMode: Boolean, isFinal: Boolean) {
|
||||
JumpToWordStart(editor, searchProcessor, offset, shiftMode = false, isFinal = isFinal)
|
||||
ApplicationManager.getApplication().invokeLater { performAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On default action, performs the Refactor This action, available via the main menu.
|
||||
* On shift action, performs the Rename... refactoring, available via the main menu.
|
||||
* Always places the caret at the start of the word.
|
||||
*/
|
||||
object Refactor : AceTagAction() {
|
||||
override fun invoke(editor: Editor, searchProcessor: SearchProcessor, offset: Int, shiftMode: Boolean, isFinal: Boolean) {
|
||||
JumpToWordStart(editor, searchProcessor, offset, shiftMode = false, isFinal = isFinal)
|
||||
ApplicationManager.getApplication().invokeLater { performAction(if (shiftMode) IdeActions.ACTION_RENAME else "Refactorings.QuickListPopupAction") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +1,169 @@
|
||||
package org.acejump.action
|
||||
|
||||
import org.acejump.boundaries.Boundaries
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.maddyhome.idea.vim.KeyHandler
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.action.change.change.ChangeVisualAction
|
||||
import com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction
|
||||
import com.maddyhome.idea.vim.action.copy.YankVisualAction
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.MappingMode.OP_PENDING
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.command.VimStateMachine
|
||||
import com.maddyhome.idea.vim.group.visual.vimSetSelection
|
||||
import com.maddyhome.idea.vim.helper.inVisualMode
|
||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||
import com.maddyhome.idea.vim.newapi.vim
|
||||
import org.acejump.boundaries.StandardBoundaries.AFTER_CARET
|
||||
import org.acejump.boundaries.StandardBoundaries.BEFORE_CARET
|
||||
import org.acejump.boundaries.StandardBoundaries.CARET_LINE
|
||||
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
|
||||
import org.acejump.modes.ActionMode
|
||||
import org.acejump.session.Session
|
||||
import org.acejump.modes.JumpMode
|
||||
import org.acejump.search.Pattern
|
||||
import org.acejump.search.Tag
|
||||
import org.acejump.session.SessionManager
|
||||
import org.acejump.session.SessionState
|
||||
|
||||
sealed class AceVimAction : AceKeyboardAction() {
|
||||
protected abstract val boundary: Boundaries
|
||||
sealed class AceVimAction : DumbAwareAction() {
|
||||
protected abstract val mode: AceVimMode
|
||||
|
||||
final override fun invoke(session: Session) {
|
||||
session.defaultBoundary = boundary
|
||||
start(session)
|
||||
final override fun actionPerformed(e: AnActionEvent) {
|
||||
val editor = e.getData(CommonDataKeys.EDITOR) ?: return
|
||||
val context = e.dataContext.vim
|
||||
|
||||
val caret = editor.caretModel.currentCaret
|
||||
val initialOffset = caret.offset
|
||||
val selectionStart = if (editor.inVisualMode) caret.vimSelectionStart else null
|
||||
|
||||
val session = SessionManager.start(editor, mode.getJumpEditors(editor))
|
||||
|
||||
session.defaultBoundary = mode.boundaries
|
||||
session.startJumpMode {
|
||||
object : JumpMode() {
|
||||
override fun accept(state: SessionState, acceptedTag: Tag): Boolean {
|
||||
state.act(AceTagAction.JumpToSearchStart, acceptedTag, wasUpperCase, isFinal = true)
|
||||
|
||||
if (selectionStart != null) {
|
||||
caret.vimSetSelection(selectionStart, caret.offset, moveCaretToSelectionEnd = true)
|
||||
}
|
||||
else {
|
||||
val vim = editor.vim
|
||||
val commandState = vim.vimStateMachine
|
||||
if (commandState.isOperatorPending) {
|
||||
val key = commandState.commandBuilder.keys.singleOrNull()?.keyChar
|
||||
|
||||
commandState.reset()
|
||||
KeyHandler.getInstance().fullReset(vim)
|
||||
|
||||
VimPlugin.getVisualMotion().enterVisualMode(vim, VimStateMachine.SubMode.VISUAL_CHARACTER)
|
||||
caret.vimSetSelection(caret.offset, initialOffset, moveCaretToSelectionEnd = true)
|
||||
|
||||
val action = when (key) {
|
||||
'd' -> DeleteVisualAction()
|
||||
'c' -> ChangeVisualAction()
|
||||
'y' -> YankVisualAction()
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (action != null) {
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
WriteAction.run<Nothing> {
|
||||
commandState.commandBuilder.pushCommandPart(action)
|
||||
|
||||
val cmd = commandState.commandBuilder.buildCommand()
|
||||
val operatorArguments = OperatorArguments(
|
||||
commandState.mappingState.mappingMode == OP_PENDING,
|
||||
cmd.rawCount, commandState.mode, commandState.subMode
|
||||
)
|
||||
|
||||
commandState.setExecutingCommand(cmd)
|
||||
injector.actionExecutor.executeVimAction(vim, action, context, operatorArguments)
|
||||
// TODO does not update status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.finishSession(editor, session)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.setupSession(editor, session)
|
||||
}
|
||||
|
||||
protected abstract fun start(session: Session)
|
||||
|
||||
class GoToDeclaration : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.GoToDeclaration, shiftMode = false) }
|
||||
}
|
||||
class JumpAllEditors : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpAllEditors
|
||||
}
|
||||
|
||||
class GoToTypeDeclaration : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.GoToDeclaration, shiftMode = true) }
|
||||
}
|
||||
class JumpForward : AceVimAction() {
|
||||
override val mode = AceVimMode.Jump(AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class ShowIntentions : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.ShowIntentions, shiftMode = false) }
|
||||
}
|
||||
class JumpBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.Jump(BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class ShowUsages : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.ShowUsages, shiftMode = false) }
|
||||
}
|
||||
class JumpTillForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpTillForward(AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class FindUsages : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.ShowUsages, shiftMode = true) }
|
||||
}
|
||||
class JumpTillBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpTillBackward(BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class Refactor : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.Refactor, shiftMode = false) }
|
||||
}
|
||||
class JumpOnLineForward : AceVimAction() {
|
||||
override val mode = AceVimMode.Jump(AFTER_CARET.intersection(CARET_LINE))
|
||||
}
|
||||
|
||||
class Rename : AceVimAction() {
|
||||
override val boundary = VISIBLE_ON_SCREEN
|
||||
override fun start(session: Session) {
|
||||
session.startJumpMode { ActionMode(AceTagAction.Refactor, shiftMode = true) }
|
||||
}
|
||||
class JumpOnLineBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.Jump(BEFORE_CARET.intersection(CARET_LINE))
|
||||
}
|
||||
|
||||
class JumpLineIndentsForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.LINE_INDENTS, AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpLineIndentsBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.LINE_INDENTS, BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpLWordForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_LWORD, AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpUWordForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_UWORD, AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpLWordBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_LWORD, BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpUWordBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_UWORD, BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpLWordEndForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_LWORD_END, AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpUWordEndForward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_UWORD_END, AFTER_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpLWordEndBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_LWORD_END, BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
|
||||
class JumpUWordEndBackward : AceVimAction() {
|
||||
override val mode = AceVimMode.JumpToPattern(Pattern.VIM_UWORD_END, BEFORE_CARET.intersection(VISIBLE_ON_SCREEN))
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.acejump.vim
|
||||
package org.acejump.action
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.acejump.boundaries.Boundaries
|
||||
@ -8,8 +8,7 @@ import org.acejump.search.Pattern
|
||||
import org.acejump.session.Session
|
||||
|
||||
sealed class AceVimMode {
|
||||
open val boundaries: Boundaries
|
||||
get() = StandardBoundaries.VISIBLE_ON_SCREEN
|
||||
abstract val boundaries: Boundaries
|
||||
|
||||
open fun getJumpEditors(mainEditor: Editor): List<Editor> {
|
||||
return listOf(mainEditor)
|
||||
@ -21,6 +20,7 @@ sealed class AceVimMode {
|
||||
class Jump(override val boundaries: Boundaries) : AceVimMode()
|
||||
|
||||
object JumpAllEditors : AceVimMode() {
|
||||
override val boundaries = StandardBoundaries.VISIBLE_ON_SCREEN
|
||||
override fun getJumpEditors(mainEditor: Editor): List<Editor> {
|
||||
val project = mainEditor.project ?: return super.getJumpEditors(mainEditor)
|
||||
|
@ -1,12 +0,0 @@
|
||||
package org.acejump.modes
|
||||
|
||||
import org.acejump.action.AceTagAction
|
||||
import org.acejump.search.Tag
|
||||
import org.acejump.session.SessionState
|
||||
|
||||
class ActionMode(private val action: AceTagAction, private val shiftMode: Boolean) : JumpMode() {
|
||||
override fun accept(state: SessionState, acceptedTag: Tag): Boolean {
|
||||
state.act(action, acceptedTag, shiftMode, isFinal = true)
|
||||
return true
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package org.acejump.vim
|
||||
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.MappingMode
|
||||
import com.maddyhome.idea.vim.extension.VimExtension
|
||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade
|
||||
import com.maddyhome.idea.vim.key.MappingOwner
|
||||
import org.acejump.boundaries.StandardBoundaries
|
||||
import org.acejump.search.Pattern
|
||||
|
||||
class AceVimExtension : VimExtension {
|
||||
private companion object {
|
||||
const val NAME = "AceJump"
|
||||
const val PLUG_PREFIX = "<Plug>(acejump)"
|
||||
|
||||
private val OWNER = MappingOwner.Plugin.get(NAME)
|
||||
|
||||
private fun register(keys: String, mode: AceVimMode) {
|
||||
val keysPrefixed = injector.parser.parseKeys("${PLUG_PREFIX}$keys")
|
||||
val keysCommand = injector.parser.parseKeys(command(keys))
|
||||
|
||||
VimExtensionFacade.putExtensionHandlerMapping(MappingMode.NVO, keysCommand, OWNER, AceVimHandler(mode), false)
|
||||
VimExtensionFacade.putKeyMapping(MappingMode.NVO, keysPrefixed, OWNER, keysCommand, true)
|
||||
}
|
||||
|
||||
private fun command(name: String): String {
|
||||
return "<Plug>(acejump-$name)"
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return NAME
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
register("<Space>", AceVimMode.JumpAllEditors)
|
||||
register("s", AceVimMode.JumpAllEditors)
|
||||
|
||||
register("f", AceVimMode.Jump(StandardBoundaries.AFTER_CARET))
|
||||
register("F", AceVimMode.Jump(StandardBoundaries.BEFORE_CARET))
|
||||
register("t", AceVimMode.JumpTillForward(StandardBoundaries.AFTER_CARET))
|
||||
register("T", AceVimMode.JumpTillBackward(StandardBoundaries.BEFORE_CARET))
|
||||
|
||||
register("w", AceVimMode.JumpToPattern(Pattern.VIM_LWORD, StandardBoundaries.AFTER_CARET))
|
||||
register("W", AceVimMode.JumpToPattern(Pattern.VIM_UWORD, StandardBoundaries.AFTER_CARET))
|
||||
register("b", AceVimMode.JumpToPattern(Pattern.VIM_LWORD, StandardBoundaries.BEFORE_CARET))
|
||||
register("B", AceVimMode.JumpToPattern(Pattern.VIM_UWORD, StandardBoundaries.BEFORE_CARET))
|
||||
register("e", AceVimMode.JumpToPattern(Pattern.VIM_LWORD_END, StandardBoundaries.AFTER_CARET))
|
||||
register("E", AceVimMode.JumpToPattern(Pattern.VIM_LWORD_END, StandardBoundaries.AFTER_CARET))
|
||||
register("ge", AceVimMode.JumpToPattern(Pattern.VIM_UWORD_END, StandardBoundaries.BEFORE_CARET))
|
||||
register("gE", AceVimMode.JumpToPattern(Pattern.VIM_UWORD_END, StandardBoundaries.BEFORE_CARET))
|
||||
|
||||
register("j", AceVimMode.JumpToPattern(Pattern.LINE_INDENTS, StandardBoundaries.AFTER_CARET))
|
||||
register("k", AceVimMode.JumpToPattern(Pattern.LINE_INDENTS, StandardBoundaries.BEFORE_CARET))
|
||||
|
||||
register("l", AceVimMode.Jump(StandardBoundaries.AFTER_CARET.intersection(StandardBoundaries.CARET_LINE)))
|
||||
register("h", AceVimMode.Jump(StandardBoundaries.BEFORE_CARET.intersection(StandardBoundaries.CARET_LINE)))
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package org.acejump.vim
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.maddyhome.idea.vim.KeyHandler
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.action.change.change.ChangeVisualAction
|
||||
import com.maddyhome.idea.vim.action.change.delete.DeleteVisualAction
|
||||
import com.maddyhome.idea.vim.action.copy.YankVisualAction
|
||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.injector
|
||||
import com.maddyhome.idea.vim.command.MappingMode
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.command.VimStateMachine
|
||||
import com.maddyhome.idea.vim.extension.ExtensionHandler
|
||||
import com.maddyhome.idea.vim.group.visual.vimSetSelection
|
||||
import com.maddyhome.idea.vim.helper.inVisualMode
|
||||
import com.maddyhome.idea.vim.helper.vimSelectionStart
|
||||
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||
import com.maddyhome.idea.vim.newapi.ij
|
||||
import org.acejump.action.AceTagAction
|
||||
import org.acejump.modes.JumpMode
|
||||
import org.acejump.search.Tag
|
||||
import org.acejump.session.SessionManager
|
||||
import org.acejump.session.SessionState
|
||||
|
||||
class AceVimHandler(private val mode: AceVimMode) : ExtensionHandler {
|
||||
override fun execute(editor: VimEditor, context: ExecutionContext) {
|
||||
val ij = editor.ij
|
||||
val caret = ij.caretModel.currentCaret
|
||||
val initialOffset = caret.offset
|
||||
val selectionStart = if (ij.inVisualMode) caret.vimSelectionStart else null
|
||||
|
||||
val session = SessionManager.start(ij, mode.getJumpEditors(ij))
|
||||
|
||||
session.defaultBoundary = mode.boundaries
|
||||
session.startJumpMode {
|
||||
object : JumpMode() {
|
||||
override fun accept(state: SessionState, acceptedTag: Tag): Boolean {
|
||||
state.act(AceTagAction.JumpToSearchStart, acceptedTag, wasUpperCase, isFinal = true)
|
||||
|
||||
if (selectionStart != null) {
|
||||
caret.vimSetSelection(selectionStart, caret.offset, moveCaretToSelectionEnd = true)
|
||||
}
|
||||
else {
|
||||
val commandState = editor.vimStateMachine
|
||||
if (commandState.isOperatorPending) {
|
||||
val key = commandState.commandBuilder.keys.singleOrNull()?.keyChar
|
||||
|
||||
commandState.reset()
|
||||
KeyHandler.getInstance().fullReset(editor)
|
||||
|
||||
VimPlugin.getVisualMotion().enterVisualMode(editor, VimStateMachine.SubMode.VISUAL_CHARACTER)
|
||||
caret.vimSetSelection(caret.offset, initialOffset, moveCaretToSelectionEnd = true)
|
||||
|
||||
val action = when (key) {
|
||||
'd' -> DeleteVisualAction()
|
||||
'c' -> ChangeVisualAction()
|
||||
'y' -> YankVisualAction()
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (action != null) {
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
WriteAction.run<Nothing> {
|
||||
commandState.commandBuilder.pushCommandPart(action)
|
||||
|
||||
val cmd = commandState.commandBuilder.buildCommand()
|
||||
val operatorArguments = OperatorArguments(
|
||||
commandState.mappingState.mappingMode == MappingMode.OP_PENDING,
|
||||
cmd.rawCount, commandState.mode, commandState.subMode
|
||||
)
|
||||
|
||||
commandState.setExecutingCommand(cmd)
|
||||
injector.actionExecutor.executeVimAction(editor, action, context, operatorArguments)
|
||||
// TODO does not update status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.finishSession(ij, session)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.setupSession(ij, session)
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="IdeaVIM">
|
||||
<vimExtension implementation="org.acejump.vim.AceVimExtension" name="acejump" />
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -9,12 +9,11 @@
|
||||
</description>
|
||||
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
<depends>IdeaVIM</depends>
|
||||
|
||||
<category>Navigation</category>
|
||||
<vendor url="https://github.com/acejump/AceJump">AceJump</vendor>
|
||||
|
||||
<depends optional="true" config-file="acejump-ideavim.xml">IdeaVIM</depends>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService serviceImplementation="org.acejump.config.AceConfig"/>
|
||||
<applicationConfigurable groupId="tools" displayName="AceJump"
|
||||
@ -28,35 +27,24 @@
|
||||
<editorActionHandler action="EditorEnter" order="first"
|
||||
implementationClass="org.acejump.action.AceEditorAction$TagImmediately"/>
|
||||
</extensions>
|
||||
|
||||
|
||||
<actions>
|
||||
<action id="AceAction"
|
||||
class="org.acejump.action.AceKeyboardAction$ActivateAceJump"
|
||||
text="Activate AceJump">
|
||||
<keyboard-shortcut keymap="Mac OS X" first-keystroke="ctrl SEMICOLON"/>
|
||||
<keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="ctrl SEMICOLON"/>
|
||||
<keyboard-shortcut keymap="$default" first-keystroke="ctrl SEMICOLON"/>
|
||||
</action>
|
||||
<action id="AceVimAction_GoToDeclaration"
|
||||
class="org.acejump.action.AceVimAction$GoToDeclaration"
|
||||
text="AceJump Vim - GoToDeclaration"/>
|
||||
<action id="AceVimAction_GoToTypeDeclaration"
|
||||
class="org.acejump.action.AceVimAction$GoToTypeDeclaration"
|
||||
text="AceJump Vim - GoToTypeDeclaration"/>
|
||||
<action id="AceVimAction_ShowIntentions"
|
||||
class="org.acejump.action.AceVimAction$ShowIntentions"
|
||||
text="AceJump Vim - ShowIntentions"/>
|
||||
<action id="AceVimAction_ShowUsages"
|
||||
class="org.acejump.action.AceVimAction$ShowUsages"
|
||||
text="AceJump Vim - ShowUsages"/>
|
||||
<action id="AceVimAction_FindUsages"
|
||||
class="org.acejump.action.AceVimAction$FindUsages"
|
||||
text="AceJump Vim - FindUsages"/>
|
||||
<action id="AceVimAction_Refactor"
|
||||
class="org.acejump.action.AceVimAction$Refactor"
|
||||
text="AceJump Vim - Refactor"/>
|
||||
<action id="AceVimAction_Rename"
|
||||
class="org.acejump.action.AceVimAction$Rename"
|
||||
text="AceJump Vim - Rename"/>
|
||||
<action id="AceVimAction_JumpAllEditors" class="org.acejump.action.AceVimAction$JumpAllEditors" text="AceJump Vim - Jump All Editors" />
|
||||
<action id="AceVimAction_JumpForward" class="org.acejump.action.AceVimAction$JumpForward" text="AceJump Vim - Jump Forward" />
|
||||
<action id="AceVimAction_JumpBackward" class="org.acejump.action.AceVimAction$JumpBackward" text="AceJump Vim - Jump Backward" />
|
||||
<action id="AceVimAction_JumpTillForward" class="org.acejump.action.AceVimAction$JumpTillForward" text="AceJump Vim - Jump Till Forward" />
|
||||
<action id="AceVimAction_JumpTillBackward" class="org.acejump.action.AceVimAction$JumpTillBackward" text="AceJump Vim - Jump Till Backward" />
|
||||
<action id="AceVimAction_JumpOnLineForward" class="org.acejump.action.AceVimAction$JumpOnLineForward" text="AceJump Vim - Jump On Line Forward" />
|
||||
<action id="AceVimAction_JumpOnLineBackward" class="org.acejump.action.AceVimAction$JumpOnLineBackward" text="AceJump Vim - Jump On Line Backward" />
|
||||
<action id="AceVimAction_JumpLineIndentsForward" class="org.acejump.action.AceVimAction$JumpLineIndentsForward" text="AceJump Vim - Jump Line Indents Forward" />
|
||||
<action id="AceVimAction_JumpLineIndentsBackward" class="org.acejump.action.AceVimAction$JumpLineIndentsBackward" text="AceJump Vim - Jump Line Indents Backward" />
|
||||
<action id="AceVimAction_JumpLWordForward" class="org.acejump.action.AceVimAction$JumpLWordForward" text="AceJump Vim - Jump LWord Forward" />
|
||||
<action id="AceVimAction_JumpUWordForward" class="org.acejump.action.AceVimAction$JumpUWordForward" text="AceJump Vim - Jump UWord Forward" />
|
||||
<action id="AceVimAction_JumpLWordBackward" class="org.acejump.action.AceVimAction$JumpLWordBackward" text="AceJump Vim - Jump LWord Backward" />
|
||||
<action id="AceVimAction_JumpUWordBackward" class="org.acejump.action.AceVimAction$JumpUWordBackward" text="AceJump Vim - Jump UWord Backward" />
|
||||
<action id="AceVimAction_JumpLWordEndForward" class="org.acejump.action.AceVimAction$JumpLWordEndForward" text="AceJump Vim - Jump LWord End Forward" />
|
||||
<action id="AceVimAction_JumpUWordEndForward" class="org.acejump.action.AceVimAction$JumpUWordEndForward" text="AceJump Vim - Jump UWord End Forward" />
|
||||
<action id="AceVimAction_JumpLWordEndBackward" class="org.acejump.action.AceVimAction$JumpLWordEndBackward" text="AceJump Vim - Jump LWord End Backward" />
|
||||
<action id="AceVimAction_JumpUWordEndBackward" class="org.acejump.action.AceVimAction$JumpUWordEndBackward" text="AceJump Vim - Jump UWord End Backward" />
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
@ -1,11 +1,10 @@
|
||||
import org.acejump.action.AceKeyboardAction
|
||||
|
||||
import org.acejump.action.AceVimAction
|
||||
import org.acejump.test.util.BaseTest
|
||||
import org.junit.Ignore
|
||||
import java.io.File
|
||||
import kotlin.random.Random
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Ignore
|
||||
class LatencyTest : BaseTest() {
|
||||
|
||||
private fun `test tag latency`(editorText: String) {
|
||||
@ -15,7 +14,7 @@ class LatencyTest : BaseTest() {
|
||||
|
||||
for (query in chars) {
|
||||
makeEditor(editorText)
|
||||
myFixture.testAction(AceKeyboardAction.ActivateAceJump)
|
||||
myFixture.testAction(AceVimAction.JumpAllEditors())
|
||||
time += measureTimeMillis { typeAndWaitForResults("$query") }
|
||||
// TODO assert(Tagger.markers.isNotEmpty()) { "Should be tagged: $query" }
|
||||
resetEditor()
|
||||
|
@ -7,7 +7,7 @@ import com.intellij.openapi.fileTypes.PlainTextFileType
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.acejump.action.AceKeyboardAction
|
||||
import org.acejump.action.AceVimAction
|
||||
import org.acejump.session.SessionManager
|
||||
|
||||
abstract class BaseTest : BasePlatformTestCase() {
|
||||
@ -58,7 +58,7 @@ abstract class BaseTest : BasePlatformTestCase() {
|
||||
private fun String.executeQuery(query: String) {
|
||||
myFixture.run {
|
||||
makeEditor(this@executeQuery)
|
||||
testAction(AceKeyboardAction.ActivateAceJump)
|
||||
testAction(AceVimAction.JumpAllEditors())
|
||||
typeAndWaitForResults(query)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user