mirror of
https://github.com/chylex/IntelliJ-AceJump.git
synced 2025-04-09 17:15:43 +02:00
separation of concerns
This commit is contained in:
parent
a56b14c429
commit
a2858d235e
src/main/kotlin/com/johnlindquist/acejump
@ -1,6 +1,5 @@
|
||||
package com.johnlindquist.acejump.control
|
||||
|
||||
import com.intellij.find.FindModel
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet
|
||||
import com.intellij.openapi.editor.Editor
|
||||
@ -11,6 +10,7 @@ import com.intellij.util.SmartList
|
||||
import com.johnlindquist.acejump.config.AceConfig.Companion.settings
|
||||
import com.johnlindquist.acejump.search.*
|
||||
import com.johnlindquist.acejump.search.Pattern.*
|
||||
import com.johnlindquist.acejump.search.Searcher.search
|
||||
import com.johnlindquist.acejump.search.Skipper.restoreScroll
|
||||
import com.johnlindquist.acejump.search.Skipper.storeScroll
|
||||
import com.johnlindquist.acejump.view.Canvas
|
||||
@ -27,58 +27,38 @@ import javax.swing.JComponent
|
||||
|
||||
object Handler {
|
||||
private var enabled = false
|
||||
private var text = ""
|
||||
private val editorTypeAction = EditorActionManager.getInstance().typedAction
|
||||
private val handler = editorTypeAction.rawHandler
|
||||
private var isShiftDown = false
|
||||
private val keyMap = mapOf(
|
||||
VK_HOME to { findPattern(START_OF_LINE) },
|
||||
VK_LEFT to { findPattern(START_OF_LINE) },
|
||||
VK_RIGHT to { findPattern(END_OF_LINE) },
|
||||
VK_END to { findPattern(END_OF_LINE) },
|
||||
VK_UP to { findPattern(CODE_INDENTS) },
|
||||
VK_HOME to { search(START_OF_LINE) },
|
||||
VK_LEFT to { search(START_OF_LINE) },
|
||||
VK_RIGHT to { search(END_OF_LINE) },
|
||||
VK_END to { search(END_OF_LINE) },
|
||||
VK_UP to { search(CODE_INDENTS) },
|
||||
VK_ESCAPE to { reset() },
|
||||
VK_BACK_SPACE to { processBackspaceCommand() },
|
||||
VK_ENTER to { Finder.maybeJumpIfJustOneTagRemains() },
|
||||
VK_ENTER to { Tagger.maybeJumpIfJustOneTagRemains() },
|
||||
VK_TAB to { Skipper.doesQueryExistIfSoSkipToIt(!isShiftDown) }
|
||||
)
|
||||
|
||||
private fun findOrDropLast() =
|
||||
if (!Finder.isQueryDeadEnd(text)) {
|
||||
find(text)
|
||||
} else {
|
||||
text = text.dropLast(1)
|
||||
}
|
||||
|
||||
private fun find(key: String, doSkim: Boolean = false) =
|
||||
Highlighter.search(FindModel().apply { stringToFind = key; skim = doSkim })
|
||||
|
||||
fun findPattern(pattern: Pattern) =
|
||||
Highlighter.search(FindModel().apply {
|
||||
stringToFind = pattern.string
|
||||
isRegularExpressions = true
|
||||
skim = false
|
||||
Finder.reset()
|
||||
})
|
||||
|
||||
fun activate() = runNow { if (!enabled) start() else toggleTargetMode() }
|
||||
|
||||
fun processCommand(keyCode: Int) = keyMap[keyCode]?.invoke()
|
||||
|
||||
private fun processBackspaceCommand() {
|
||||
text = ""
|
||||
Finder.reset()
|
||||
Highlighter.discard()
|
||||
Tagger.reset()
|
||||
Searcher.discard()
|
||||
updateUIState()
|
||||
}
|
||||
|
||||
private fun interceptPrintableKeystrokes() =
|
||||
editorTypeAction.setupRawHandler { _, key, _ ->
|
||||
text += key
|
||||
if (text.length < 2) {
|
||||
find(text, doSkim = true)
|
||||
Trigger.restart(400L) { find(text, doSkim = false) }
|
||||
} else findOrDropLast()
|
||||
Searcher.query += key
|
||||
if (Searcher.query.length < 2) {
|
||||
Searcher.skim()
|
||||
Trigger.restart(400L) { Searcher.search() }
|
||||
} else Searcher.findOrDropLast(Searcher.query)
|
||||
}
|
||||
|
||||
private fun configureEditor() =
|
||||
@ -123,7 +103,7 @@ object Handler {
|
||||
Jumper.hasJumped = false
|
||||
reset()
|
||||
} else {
|
||||
Canvas.jumpLocations = Finder.markers
|
||||
Canvas.jumpLocations = Tagger.markers
|
||||
Canvas.repaint()
|
||||
}
|
||||
|
||||
@ -133,9 +113,9 @@ object Handler {
|
||||
Canvas.bindToEditor(editor)
|
||||
}
|
||||
|
||||
if (text.isNotEmpty() || Finder.isRegex)
|
||||
if (Searcher.query.isNotEmpty() || Tagger.isRegex)
|
||||
runLater {
|
||||
Finder.find()
|
||||
Tagger.mark()
|
||||
updateUIState()
|
||||
}
|
||||
}
|
||||
@ -145,15 +125,14 @@ object Handler {
|
||||
editor.component.uninstallCustomShortCutHandler()
|
||||
editorTypeAction.setupRawHandler(handler)
|
||||
enabled = false
|
||||
text = ""
|
||||
Finder.reset()
|
||||
Highlighter.discard()
|
||||
Tagger.reset()
|
||||
Searcher.discard()
|
||||
editor.restoreSettings()
|
||||
}
|
||||
|
||||
fun toggleTargetMode(status: Boolean? = null) =
|
||||
editor.colorsScheme.run {
|
||||
if (Finder.toggleTargetMode(status))
|
||||
if (Tagger.toggleTargetMode(status))
|
||||
setColor(CARET_COLOR, settings.targetModeColor)
|
||||
else
|
||||
setColor(CARET_COLOR, settings.jumpModeColor)
|
||||
|
@ -8,7 +8,7 @@ import com.intellij.openapi.editor.event.VisibleAreaEvent
|
||||
import com.intellij.openapi.editor.event.VisibleAreaListener
|
||||
import com.johnlindquist.acejump.control.Handler.redoFind
|
||||
import com.johnlindquist.acejump.control.Handler.reset
|
||||
import com.johnlindquist.acejump.search.Finder
|
||||
import com.johnlindquist.acejump.search.Tagger
|
||||
import com.johnlindquist.acejump.search.getView
|
||||
import com.johnlindquist.acejump.view.Model.editor
|
||||
import com.johnlindquist.acejump.view.Model.viewBounds
|
||||
@ -48,8 +48,8 @@ internal object Listener : CaretListener, FocusListener, AncestorListener,
|
||||
private fun canTagsSurviveViewResize() =
|
||||
editor.getView().run {
|
||||
if (first in viewBounds && last in viewBounds) return true
|
||||
else if (Finder.isRegex) return false
|
||||
else !Finder.hasMatchBetweenOldAndNewView(viewBounds, this)
|
||||
else if (Tagger.isRegex) return false
|
||||
else !Tagger.hasMatchBetweenOldAndNewView(viewBounds, this)
|
||||
}
|
||||
|
||||
override fun globalSchemeChange(scheme: EditorColorsScheme?) = redoFind()
|
||||
|
@ -15,9 +15,9 @@ import java.lang.Math.max
|
||||
import java.lang.Math.min
|
||||
|
||||
var FindModel.skim: Boolean
|
||||
get() = Finder.skim
|
||||
get() = Tagger.skim
|
||||
set(value) {
|
||||
Finder.skim = value
|
||||
Tagger.skim = value
|
||||
}
|
||||
|
||||
operator fun Point.component1() = x
|
||||
|
@ -24,9 +24,9 @@ object Jumper {
|
||||
var hasJumped = false
|
||||
|
||||
fun jump(marker: Marker) = editor.run {
|
||||
if (Finder.findModel.stringToFind.last().isUpperCase())
|
||||
if (Tagger.findModel.stringToFind.last().isUpperCase())
|
||||
selectFromToOffset(caretModel.offset, marker.index)
|
||||
else if (Finder.targetModeEnabled) {
|
||||
else if (Tagger.targetModeEnabled) {
|
||||
// Moving the caret will trigger a reset, flipping targetModeEnabled, so
|
||||
// we need to move the caret and select the word in one single transaction
|
||||
moveCaret(marker.index)
|
||||
|
@ -8,21 +8,29 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.editor.colors.EditorColors
|
||||
import com.johnlindquist.acejump.control.Handler
|
||||
import com.johnlindquist.acejump.view.Model.editor
|
||||
import com.johnlindquist.acejump.view.Model.editorText
|
||||
import com.johnlindquist.acejump.view.Model.project
|
||||
import java.awt.Color
|
||||
|
||||
object Highlighter : Disposable, SearchResults.SearchResultsListener {
|
||||
private var model: FindModel = FindModel()
|
||||
object Searcher : Disposable, SearchResults.SearchResultsListener {
|
||||
var query: String = ""
|
||||
set(value) {
|
||||
model = FindModel().apply { stringToFind = value }
|
||||
field = value
|
||||
}
|
||||
|
||||
var model: FindModel = FindModel()
|
||||
|
||||
override fun searchResultsUpdated(sr: SearchResults?) {
|
||||
results?.occurrences
|
||||
?.filter { it.startOffset in editor.getView() }
|
||||
.let { resultsInView = it }
|
||||
|
||||
if (!model.skim) doFind()
|
||||
doFind()
|
||||
}
|
||||
|
||||
private fun SearchResults.filterOrNarrowInView() =
|
||||
resultsInView?.partition { Finder.hasTagsAtIndex(it.startOffset) }?.run {
|
||||
resultsInView?.partition { Tagger.hasTagsAtIndex(it.startOffset) }?.run {
|
||||
second.forEach { exclude(it) }
|
||||
resultsInView = first
|
||||
}
|
||||
@ -36,26 +44,43 @@ object Highlighter : Disposable, SearchResults.SearchResultsListener {
|
||||
|
||||
private lateinit var livePreviewController: LivePreviewController
|
||||
|
||||
fun skim() = search(model.apply { skim = true })
|
||||
|
||||
fun search(string: String = query) = search(FindModel().apply { stringToFind = string })
|
||||
|
||||
fun search(pattern: Pattern) =
|
||||
Searcher.search(FindModel().apply {
|
||||
stringToFind = pattern.string
|
||||
isRegularExpressions = true
|
||||
skim = false
|
||||
Tagger.reset()
|
||||
})
|
||||
|
||||
fun search(findModel: FindModel) {
|
||||
model = findModel
|
||||
if (results == null) init()
|
||||
|
||||
results?.filterOrNarrowInView()
|
||||
|
||||
val hasTags = Finder.hasTagsStartingWithChar(model.stringToFind.last())
|
||||
if (!hasTags) livePreviewController.updateInBackground(model, false)
|
||||
if (hasTags) doFind()
|
||||
livePreviewController.updateInBackground(model, false)
|
||||
}
|
||||
|
||||
private fun doFind() =
|
||||
runLater {
|
||||
Finder.findOrJump(model, results?.occurrences?.map { it.startOffset })
|
||||
Tagger.markOrJump(model, results?.occurrences?.map { it.startOffset })
|
||||
results?.filterOrNarrowInView()
|
||||
Handler.updateUIState()
|
||||
}
|
||||
|
||||
fun findOrDropLast(text: String = query) =
|
||||
if (!isQueryDeadEnd(text)) {
|
||||
search(text)
|
||||
} else {
|
||||
query = text.dropLast(1)
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
results = SearchResults(editor, project).apply { addListener(Highlighter) }
|
||||
results = SearchResults(editor, project).apply { addListener(Searcher) }
|
||||
|
||||
editor.colorsScheme.run {
|
||||
setAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES,
|
||||
@ -67,9 +92,15 @@ object Highlighter : Disposable, SearchResults.SearchResultsListener {
|
||||
livePreviewController.on()
|
||||
}
|
||||
|
||||
fun isQueryDeadEnd(query: String) =
|
||||
results?.occurrences?.any { editorText.regionMatches(it.startOffset, query, 0, query.length) } ?: true ||
|
||||
!Tagger.hasTagSuffix(query)
|
||||
|
||||
fun getResultsInView() = resultsInView?.map { it.startOffset }
|
||||
|
||||
fun discard() {
|
||||
query = ""
|
||||
model = FindModel()
|
||||
results?.removeListener(this)
|
||||
results?.dispose()
|
||||
livePreviewController.off()
|
@ -3,7 +3,7 @@ package com.johnlindquist.acejump.search
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.LogicalPosition
|
||||
import com.intellij.openapi.editor.ScrollType.CENTER
|
||||
import com.johnlindquist.acejump.search.Finder.textMatches
|
||||
import com.johnlindquist.acejump.search.Tagger.textMatches
|
||||
import com.johnlindquist.acejump.view.Model.editor
|
||||
import com.johnlindquist.acejump.view.Model.viewBounds
|
||||
|
||||
|
@ -7,9 +7,9 @@ import com.google.common.collect.Multimap
|
||||
import com.intellij.find.FindModel
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.johnlindquist.acejump.config.AceConfig.Companion.settings
|
||||
import com.johnlindquist.acejump.search.Finder.textMatches
|
||||
import com.johnlindquist.acejump.search.Pattern.Companion.distance
|
||||
import com.johnlindquist.acejump.search.Pattern.Companion.priotity
|
||||
import com.johnlindquist.acejump.search.Tagger.textMatches
|
||||
import com.johnlindquist.acejump.view.Marker
|
||||
import com.johnlindquist.acejump.view.Model.editor
|
||||
import com.johnlindquist.acejump.view.Model.editorText
|
||||
@ -21,7 +21,7 @@ import java.util.*
|
||||
* Singleton that searches for text in the editor and tags matching results.
|
||||
*/
|
||||
|
||||
object Finder {
|
||||
object Tagger {
|
||||
var targetModeEnabled = false
|
||||
var markers: Collection<Marker> = emptyList()
|
||||
private set
|
||||
@ -34,12 +34,12 @@ object Finder {
|
||||
private var tagMap: BiMap<String, Int> = HashBiMap.create()
|
||||
private var unseen2grams: LinkedHashSet<String> = linkedSetOf()
|
||||
private var digraphs: Multimap<String, Int> = LinkedListMultimap.create()
|
||||
private val logger = Logger.getInstance(Finder::class.java)
|
||||
private val logger = Logger.getInstance(Tagger::class.java)
|
||||
var findModel = FindModel()
|
||||
var skim = false
|
||||
|
||||
fun findOrJump(findModel: FindModel, results: List<Int>?) {
|
||||
if (results != null && results.isNotEmpty()) textMatches = results
|
||||
fun markOrJump(findModel: FindModel, results: List<Int>?) {
|
||||
if (results != null) textMatches = results
|
||||
else return
|
||||
|
||||
if (!isRegex) isRegex = findModel.isRegularExpressions
|
||||
@ -49,7 +49,7 @@ object Finder {
|
||||
Regex.escape(findModel.stringToFind.toLowerCase())
|
||||
query = (if (isRegex) " " else "") + findModel.stringToFind.toLowerCase()
|
||||
|
||||
find()
|
||||
mark()
|
||||
}
|
||||
|
||||
fun toggleTargetMode(status: Boolean? = null): Boolean {
|
||||
@ -62,8 +62,8 @@ object Finder {
|
||||
|
||||
private fun jumpTo(marker: Marker) = Jumper.jump(marker)
|
||||
|
||||
fun find() {
|
||||
computeMarkers()
|
||||
fun mark() {
|
||||
if (textMatches.isNotEmpty()) computeMarkers()
|
||||
|
||||
// TODO: Clean up this ugliness.
|
||||
if (markers.size > 1 || query.length < 2) return
|
||||
@ -282,7 +282,7 @@ object Finder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Finder contains a match in the new view, that is not
|
||||
* Returns true if the Tagger contains a match in the new view, that is not
|
||||
* contained (visible) in the old view. This method assumes that textMatches
|
||||
* are sorted from least to greatest.
|
||||
*
|
||||
@ -304,6 +304,10 @@ object Finder {
|
||||
return textMatches.isEmpty() && markers.isEmpty()
|
||||
}
|
||||
|
||||
fun hasTagsStartingWithChar(c: Char) = tagMap.any { it.key.startsWith(c.toLowerCase()) }
|
||||
fun hasTagSuffix(query: String) = tagMap.any {
|
||||
query.endsWith(it.key.first(), true) ||
|
||||
query.endsWith(it.key, true)
|
||||
}
|
||||
|
||||
fun hasTagsAtIndex(i: Int) = tagMap.containsValue(i)
|
||||
}
|
@ -2,7 +2,7 @@ package com.johnlindquist.acejump.view
|
||||
|
||||
import com.johnlindquist.acejump.config.AceConfig.Companion.settings
|
||||
import com.johnlindquist.acejump.search.*
|
||||
import com.johnlindquist.acejump.search.Finder.isRegex
|
||||
import com.johnlindquist.acejump.search.Tagger.isRegex
|
||||
import com.johnlindquist.acejump.view.Marker.Alignment.*
|
||||
import com.johnlindquist.acejump.view.Model.arcD
|
||||
import com.johnlindquist.acejump.view.Model.editor
|
||||
@ -54,7 +54,7 @@ class Marker(val query: String, val tag: String?, val index: Int) {
|
||||
?.apply { Canvas.registerTag(this, tag) }
|
||||
?.let { highlightTag(it); drawTagForeground(it) }
|
||||
|
||||
if (Finder.isRegex)
|
||||
if (Tagger.isRegex)
|
||||
highlightText()
|
||||
}
|
||||
|
||||
@ -150,6 +150,6 @@ class Marker(val query: String, val tag: String?, val index: Int) {
|
||||
highlightAlreadyTyped()
|
||||
highlightRemaining()
|
||||
|
||||
if (Finder.targetModeEnabled) surroundTargetWord()
|
||||
if (Tagger.targetModeEnabled) surroundTargetWord()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user