1
0
mirror of https://github.com/chylex/IntelliJ-AceJump.git synced 2025-04-09 17:15:43 +02:00

Replaces the staggering hack that was SearchBox with the slightly less messy, but still hacky KeyboardHandler

This commit is contained in:
breandan.considine 2016-11-24 15:08:34 -05:00
parent 7847ee351d
commit 6e4a096c5f
8 changed files with 206 additions and 196 deletions

View File

@ -20,7 +20,7 @@ apply plugin: 'org.jetbrains.intellij'
apply plugin: 'kotlin'
intellij {
version '162.1121.32'
version '163.7743.44'
pluginName 'AceJump'
updateSinceUntilBuild false

View File

@ -0,0 +1,26 @@
package com.johnlindquist.acejump
import com.intellij.find.FindManager
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.components.ApplicationComponent
import com.intellij.openapi.project.ProjectManager
class AceJumpPlugin : ApplicationComponent {
val COMPONENT_NAME = "AceJump"
val project = ProjectManager.getInstance().defaultProject
val findManager = FindManager.getInstance(project)
var searchBox: KeyboardHandler? = null
val action = ActionManager.getInstance().getAction("AceJumpKeyAction")
override fun initComponent() {
}
override fun disposeComponent() {
}
override fun getComponentName(): String {
return COMPONENT_NAME
}
}

View File

@ -4,19 +4,19 @@ import com.intellij.find.FindManager
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR
import com.intellij.openapi.actionSystem.CommonDataKeys.PROJECT
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.IdeFocusManager
import com.johnlindquist.acejump.keycommands.ShowLineMarkers
import com.johnlindquist.acejump.search.AceFinder
import com.johnlindquist.acejump.ui.SearchBox
import com.sun.glass.events.KeyEvent.VK_BACKSPACE
import java.awt.event.KeyEvent
import java.awt.event.KeyEvent.VK_ESCAPE
private var aceFinder: AceFinder? = null
private var searchBox: KeyboardHandler? = null
open class AceJumpAction() : DumbAwareAction() {
var aceFinder: AceFinder? = null
var searchBox: SearchBox? = null
override fun update(e: AnActionEvent?) {
e?.presentation?.isEnabled = (e?.getData(EDITOR)) != null
}
@ -27,17 +27,25 @@ open class AceJumpAction() : DumbAwareAction() {
val editor = actionEvent.getData(EDITOR) as EditorImpl
val findManager = FindManager.getInstance(project)!!
aceFinder = AceFinder(findManager, editor)
searchBox = SearchBox(aceFinder!!, editor)
ApplicationManager.getApplication().invokeLater({
IdeFocusManager.getInstance(project).requestFocus(searchBox!!, false)
})
searchBox = KeyboardHandler(aceFinder!!, editor)
}
}
class AceJumpLineAction : AceJumpAction() {
override fun actionPerformed(actionEvent: AnActionEvent) {
super.actionPerformed(actionEvent)
searchBox!!.processRegexCommand(ShowLineMarkers(aceFinder!!))
super.actionPerformed(actionEvent)
}
}
class AceJumpKeyAction : AceJumpAction() {
override fun actionPerformed(actionEvent: AnActionEvent) {
val inputEvent = actionEvent.inputEvent as? KeyEvent ?: return
when (inputEvent.keyCode) {
VK_ESCAPE -> searchBox!!.exit()
VK_BACKSPACE -> searchBox!!.processBackspaceCommand()
else -> searchBox!!.processRegexCommand(inputEvent.keyCode)
}
}
}

View File

@ -0,0 +1,143 @@
package com.johnlindquist.acejump
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.actionSystem.EditorActionManager
import com.intellij.openapi.editor.colors.EditorColors.CARET_COLOR
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.ui.popup.AbstractPopup
import com.johnlindquist.acejump.keycommands.*
import com.johnlindquist.acejump.search.AceFinder
import com.johnlindquist.acejump.search.Pattern.Companion.REGEX_PREFIX
import com.johnlindquist.acejump.ui.AceCanvas
import com.sun.glass.events.KeyEvent.VK_BACKSPACE
import java.awt.Color.WHITE
import java.awt.event.KeyEvent.*
import javax.swing.JRootPane
import javax.swing.SwingUtilities
import javax.swing.event.ChangeListener
class KeyboardHandler(val finder: AceFinder, var editor: EditorImpl) {
var text = ""
var aceCanvas = AceCanvas(editor)
var keyMap: Map<Int, AceKeyCommand> = hashMapOf()
var popupContainer: AbstractPopup? = null
var defaultKeyCommand = DefaultKeyCommand(finder)
var naturalColor = WHITE
var keyHandler = EditorActionManager.getInstance().typedAction.rawHandler
val specials = intArrayOf(VK_BACKSPACE, VK_LEFT, VK_RIGHT, VK_UP, VK_ESCAPE)
init {
configureKeyMap()
configureEditor()
EditorActionManager.getInstance().typedAction.setupRawHandler {
editor: Editor, c: Char, dataContext: DataContext ->
text += c
defaultKeyCommand.execute(c, text)
}
finder.eventDispatcher.addListener(ChangeListener {
aceCanvas.jumpLocations = finder.jumpLocations
if (finder.hasJumped) {
finder.hasJumped = false
popupContainer?.cancel()
exit()
}
aceCanvas.repaint()
})
//
// val search = "dispatch"
// (' '..'~').forEach { inputMap.put(getKeyStroke(it), search) }
// actionMap.put(search, object : AbstractAction() {
// override fun actionPerformed(e: ActionEvent) {
// if (e.modifiers == 0) {
// text += e.actionCommand
// defaultKeyCommand.execute(e.actionCommand[0], text)
// } else if (e.modifiers == SHIFT_MASK) {
// text += e.actionCommand
// defaultKeyCommand.execute(e.actionCommand[0].toUpperCase(), text)
// }
// }
// })
//
//
// val aja = "AceJumpAction"
// ActionManager.getInstance().getAction(aja).shortcutSet?.shortcuts?.forEach {
// if (it.isKeyboard) {
// val kbs = it as KeyboardShortcut
// inputMap.put(kbs.firstKeyStroke, aja)
// actionMap.put(aja, object : AbstractAction() {
// override fun actionPerformed(e: ActionEvent) {
// if (finder.toggleTargetMode())
// editor.colorsScheme.setColor(CARET_COLOR, RED)
// else
// editor.colorsScheme.setColor(CARET_COLOR, naturalColor)
//
// aceCanvas.repaint()
// }
// })
// }
// }
}
fun processRegexCommand(aceKeyCommand: AceKeyCommand) {
text = REGEX_PREFIX.toString()
aceKeyCommand.execute()
}
fun processRegexCommand(keyCode: Int) {
text = REGEX_PREFIX.toString()
keyMap[keyCode]?.execute()
}
fun processBackspaceCommand() {
text = ""
defaultKeyCommand.execute(0.toChar())
}
private fun configureEditor() {
addAceCanvas()
editor.scrollingModel.addVisibleAreaListener { exit() }
naturalColor = editor.colorsScheme.getColor(CARET_COLOR)
}
private fun configureKeyMap() {
specials.forEach {
ActionManager.getInstance().getAction("AceJumpKeyAction")
.registerCustomShortcutSet(it, 0, editor.component)
}
val showBeginningOfLines = ShowStartOfLines(finder)
val showEndOfLines = ShowEndOfLines(finder)
keyMap = mapOf(VK_HOME to showBeginningOfLines,
VK_LEFT to showBeginningOfLines,
VK_RIGHT to showEndOfLines,
VK_END to showEndOfLines,
VK_UP to ShowFirstLetters(finder),
VK_SPACE to ShowWhiteSpace(finder))
}
fun addAceCanvas() {
editor.contentComponent.add(aceCanvas)
val viewport = editor.scrollPane.viewport
aceCanvas.setBounds(0, 0, viewport.width + 1000, viewport.height + 1000)
val root: JRootPane = editor.component.rootPane
val loc = SwingUtilities.convertPoint(aceCanvas, aceCanvas.location, root)
aceCanvas.setLocation(-loc.x, -loc.y)
}
fun exit() {
val contentComponent = editor.contentComponent
contentComponent.remove(aceCanvas)
contentComponent.repaint()
EditorActionManager.getInstance().typedAction.setupRawHandler(keyHandler)
specials.forEach {
ActionManager.getInstance().getAction("AceJumpKeyAction")
.unregisterCustomShortcutSet(editor.component)
}
popupContainer?.dispose()
finder.reset()
}
}

View File

@ -94,7 +94,8 @@ class AceFinder(val findManager: FindManager, var editor: EditorImpl) {
jumpTo(JumpInfo(last2, query, tagMap[last2]!!, this))
} else if (tagMap.containsKey(last1)) {
val index = tagMap[last1]!!
if (document[index + query.length - 1].toLowerCase() != last1[0])
val charIndex = index + query.length - 1
if (charIndex > document.length || document[charIndex] != last1[0])
jumpTo(JumpInfo(last1, query, index, this))
}
}
@ -167,7 +168,7 @@ class AceFinder(val findManager: FindManager, var editor: EditorImpl) {
var startingFrom = if (oldResults.hasNext()) oldResults.next() else viewTop
var result = findManager.findString(fullText, startingFrom, findModel)
while (result!!.isStringFound && result.startOffset < viewBottom) {
while (result!!.isStringFound && result.startOffset <= viewBottom) {
if (!editor.foldingModel.isOffsetCollapsed(result.startOffset))
indicesToCheck.add(result.startOffset)
@ -347,10 +348,13 @@ class AceFinder(val findManager: FindManager, var editor: EditorImpl) {
val remainingSites = digraphs.asMap().entries.filter {
it.key.first().isLetterOrDigit() || query.isNotEmpty()
}.sortedBy { it.value.size }.flatMap { it.value }.sortedBy {
}.sortedBy { it.value.size }.flatMap { it.value }.sortedWith(compareBy(
// Ensure that the first letter of a word is prioritized for tagging
document[Math.max(0, it - 1)].isLetterOrDigit()
}.iterator()
{ document[Math.max(0, it - 1)].isLetterOrDigit() },
// Longer characters should come first
{ val bounds = getWordBounds(it); -document.substring(bounds.first,
bounds.second).toCharArray().distinct().size}
)).iterator()
if (!findModel.isRegularExpressions || newTagMap.isEmpty())
while (remainingSites.hasNext() && tags.isNotEmpty())

View File

@ -152,7 +152,7 @@ class JumpInfo(private val tag: String, var query: String, val index: Int,
fun surroundTargetWord() {
val (wordStart, wordEnd) = aceFinder.getWordBounds(index)
g2d.color = blue
g2d.color = red
val startPoint = editor.offsetToVisualPosition(wordStart)
val startPointO = getPointFromVisualPosition(editor, startPoint)
@ -170,4 +170,4 @@ class JumpInfo(private val tag: String, var query: String, val index: Int,
surroundTargetWord()
}
}
}
}

View File

@ -1,174 +0,0 @@
package com.johnlindquist.acejump.ui
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.ui.popup.ComponentPopupBuilder
import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.ui.popup.AbstractPopup
import com.johnlindquist.acejump.keycommands.*
import com.johnlindquist.acejump.search.AceFinder
import com.johnlindquist.acejump.search.Pattern.Companion.REGEX_PREFIX
import com.johnlindquist.acejump.search.guessBestLocation
import java.awt.Color.RED
import java.awt.Color.WHITE
import java.awt.Graphics
import java.awt.event.ActionEvent
import java.awt.event.FocusEvent
import java.awt.event.FocusListener
import java.awt.event.KeyEvent
import java.awt.event.KeyEvent.*
import javax.swing.AbstractAction
import javax.swing.JRootPane
import javax.swing.JTextField
import javax.swing.KeyStroke.getKeyStroke
import javax.swing.SwingUtilities
import javax.swing.event.ChangeListener
class SearchBox(val finder: AceFinder, var editor: EditorImpl) : JTextField() {
var aceCanvas = AceCanvas(editor)
var keyMap: Map<Int, AceKeyCommand> = hashMapOf()
var popupContainer: AbstractPopup? = null
var defaultKeyCommand = DefaultKeyCommand(finder)
var naturalColor = WHITE
init {
configureKeyMap()
configurePopup()
finder.eventDispatcher.addListener(ChangeListener {
aceCanvas.jumpLocations = finder.jumpLocations
if (finder.hasJumped) {
finder.hasJumped = false
popupContainer?.cancel()
exit()
}
aceCanvas.repaint()
})
val search = "dispatch"
(' '..'~').forEach { inputMap.put(getKeyStroke(it), search) }
actionMap.put(search, object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
if (e.modifiers == 0) {
text += e.actionCommand
defaultKeyCommand.execute(e.actionCommand[0], text)
} else if (e.modifiers == SHIFT_MASK) {
text += e.actionCommand
defaultKeyCommand.execute(e.actionCommand[0].toUpperCase(), text)
}
}
})
(VK_LEFT..VK_RIGHT).forEach {
val keyName: String = KeyEvent.getKeyText(it)
inputMap.put(getKeyStroke(it, 0), keyName)
actionMap.put(keyName, object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) = processRegexCommand(it)
})
}
val aja = "AceJumpAction"
ActionManager.getInstance().getAction(aja).shortcutSet?.shortcuts?.forEach {
if (it.isKeyboard) {
val kbs = it as KeyboardShortcut
inputMap.put(kbs.firstKeyStroke, aja)
actionMap.put(aja, object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
background = if (finder.toggleTargetMode()) RED else naturalColor
aceCanvas.repaint()
}
})
}
}
}
/*
* For some reason, Swing does not like to pass us actions via the inputMap or
* actionMap registration technique. Until that works reliably, we need to use
* low-level KeyEvents for processing the following keystrokes.
*/
override fun processKeyEvent(keyEvent: KeyEvent) {
if (keyEvent.id == KEY_RELEASED) {
when (keyEvent.keyCode) {
VK_BACK_SPACE -> processBackspaceCommand()
VK_HOME -> processRegexCommand(VK_END)
VK_END -> processRegexCommand(VK_END)
}
}
super.processKeyEvent(keyEvent)
}
fun processRegexCommand(aceKeyCommand: AceKeyCommand) {
text = REGEX_PREFIX.toString()
aceKeyCommand.execute()
}
fun processRegexCommand(keyCode: Int) {
text = REGEX_PREFIX.toString()
keyMap[keyCode]!!.execute()
}
fun processBackspaceCommand() {
text = ""
defaultKeyCommand.execute(0.toChar())
}
private fun configurePopup() {
val pb: ComponentPopupBuilder? =
JBPopupFactory.getInstance()?.createComponentPopupBuilder(this, this)
pb?.setCancelKeyEnabled(true)
val popup = pb?.createPopup() as AbstractPopup?
popup?.show(guessBestLocation(editor))
popup?.setRequestFocus(true)
isFocusable = true
addFocusListener(object : FocusListener {
override fun focusGained(p0: FocusEvent) = addAceCanvas()
override fun focusLost(p0: FocusEvent) = exit()
})
editor.scrollingModel.addVisibleAreaListener { exit() }
popupContainer = popup
naturalColor = background
}
private fun configureKeyMap() {
val showBeginningOfLines = ShowStartOfLines(finder)
val showEndOfLines = ShowEndOfLines(finder)
keyMap = mapOf(VK_HOME to showBeginningOfLines,
VK_LEFT to showBeginningOfLines,
VK_RIGHT to showEndOfLines,
VK_END to showEndOfLines,
VK_UP to ShowFirstLetters(finder),
VK_SPACE to ShowWhiteSpace(finder))
}
override fun requestFocus() {
transferHandler = null
super.requestFocus()
}
override fun paintBorder(p0: Graphics?) = Unit
fun addAceCanvas() {
editor.contentComponent.add(aceCanvas)
val viewport = editor.scrollPane.viewport
aceCanvas.setBounds(0, 0, viewport.width + 1000, viewport.height + 1000)
val root: JRootPane = editor.component.rootPane
val loc = SwingUtilities.convertPoint(aceCanvas, aceCanvas.location, root)
aceCanvas.setLocation(-loc.x, -loc.y)
}
override fun paint(g: Graphics?) {}
fun exit() {
val contentComponent = editor.contentComponent
contentComponent.remove(aceCanvas)
contentComponent.repaint()
popupContainer?.dispose()
finder.reset()
}
}

View File

@ -9,7 +9,7 @@
Simply hit "ctrl+;", type a character, then type the matching character to Ace Jump. ]]>
</description>
<change-notes></change-notes>
<change-notes>No longer tags "folded" regions and minor alignment adjustments.</change-notes>
<depends>com.intellij.modules.platform</depends>
@ -35,5 +35,8 @@
<keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="ctrl shift SEMICOLON"/>
<keyboard-shortcut keymap="$default" first-keystroke="ctrl shift SEMICOLON"/>
</action>
<action id="AceJumpKeyAction"
class="com.johnlindquist.acejump.AceJumpKeyAction"
text="Motion Keys"/>
</actions>
</idea-plugin>
</idea-plugin>