mirror of
https://github.com/chylex/IntelliJ-AceJump.git
synced 2024-11-25 17:42:46 +01:00
Compare commits
3 Commits
575283b2be
...
1f76a8bd25
Author | SHA1 | Date | |
---|---|---|---|
1f76a8bd25 | |||
2e31ddd504 | |||
47a34f6f14 |
@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "org.acejump"
|
group = "org.acejump"
|
||||||
version = "chylex-18"
|
version = "chylex-19"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -11,18 +11,8 @@ import org.acejump.matchesAt
|
|||||||
/**
|
/**
|
||||||
* Searches editor text for matches of a [SearchQuery], and updates previous results when the user [refineQuery]s a character.
|
* Searches editor text for matches of a [SearchQuery], and updates previous results when the user [refineQuery]s a character.
|
||||||
*/
|
*/
|
||||||
class SearchProcessor private constructor(query: SearchQuery, private val results: MutableMap<Editor, IntArrayList>) {
|
class SearchProcessor private constructor(query: SearchQuery, val boundaries: Boundaries, private val results: MutableMap<Editor, IntArrayList>) {
|
||||||
companion object {
|
internal constructor(editors: List<Editor>, query: SearchQuery, boundaries: Boundaries) : this(query, boundaries, mutableMapOf()) {
|
||||||
fun fromString(editors: List<Editor>, query: String, boundaries: Boundaries): SearchProcessor {
|
|
||||||
return SearchProcessor(editors, SearchQuery.Literal(query), boundaries)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromRegex(editors: List<Editor>, pattern: String, boundaries: Boundaries): SearchProcessor {
|
|
||||||
return SearchProcessor(editors, SearchQuery.RegularExpression(pattern), boundaries)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private constructor(editors: List<Editor>, query: SearchQuery, boundaries: Boundaries) : this(query, mutableMapOf()) {
|
|
||||||
val regex = query.toRegex()
|
val regex = query.toRegex()
|
||||||
|
|
||||||
if (regex != null) {
|
if (regex != null) {
|
||||||
@ -65,7 +55,7 @@ class SearchProcessor private constructor(query: SearchQuery, private val result
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
query = SearchQuery.Literal(query.rawText + char)
|
query = query.refine(char)
|
||||||
removeObsoleteResults()
|
removeObsoleteResults()
|
||||||
return isQueryFinished
|
return isQueryFinished
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,11 @@ import org.acejump.countMatchingCharacters
|
|||||||
internal sealed class SearchQuery {
|
internal sealed class SearchQuery {
|
||||||
abstract val rawText: String
|
abstract val rawText: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new query with the given character appended.
|
||||||
|
*/
|
||||||
|
abstract fun refine(char: Char): SearchQuery
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns how many characters the search occurrence highlight should cover.
|
* Returns how many characters the search occurrence highlight should cover.
|
||||||
*/
|
*/
|
||||||
@ -19,29 +24,42 @@ internal sealed class SearchQuery {
|
|||||||
abstract fun toRegex(): Regex?
|
abstract fun toRegex(): Regex?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for all occurrences of a literal text query. If the first character of the query is lowercase, then the entire query will be
|
* Searches for all occurrences of a literal text query.
|
||||||
* case-insensitive.
|
* If the first character of the query is lowercase, then the entire query will be case-insensitive,
|
||||||
*
|
* and only beginnings of words and camel humps will be matched.
|
||||||
* Each occurrence must either match the entire query, or match the query up to a point so that the rest of the query matches the
|
|
||||||
* beginning of a tag at the location of the occurrence.
|
|
||||||
*/
|
*/
|
||||||
class Literal(override val rawText: String) : SearchQuery() {
|
class Literal(override val rawText: String, val excludeMiddlesOfWords: Boolean) : SearchQuery() {
|
||||||
init {
|
init {
|
||||||
require(rawText.isNotEmpty())
|
require(rawText.isNotEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun refine(char: Char): SearchQuery {
|
||||||
|
return Literal(rawText + char, excludeMiddlesOfWords)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
|
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
|
||||||
return text.countMatchingCharacters(offset, rawText)
|
return text.countMatchingCharacters(offset, rawText)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toRegex(): Regex {
|
override fun toRegex(): Regex {
|
||||||
val options = mutableSetOf(RegexOption.MULTILINE)
|
val firstChar = rawText.first()
|
||||||
|
val pattern = if (firstChar.isLowerCase()) {
|
||||||
if (rawText.first().isLowerCase()) {
|
if (excludeMiddlesOfWords) {
|
||||||
options.add(RegexOption.IGNORE_CASE)
|
val firstCharUppercasePattern = Regex.escape(firstChar.uppercaseChar().toString())
|
||||||
|
val firstCharPattern = Regex.escape(firstChar.toString())
|
||||||
|
val remainingPattern = if (rawText.length > 1) Regex.escape(rawText.drop(1)) else ""
|
||||||
|
"(?:$firstCharUppercasePattern|(?<![a-zA-Z])$firstCharPattern)$remainingPattern"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val fullPattern = Regex.escape(rawText)
|
||||||
|
"(?i)$fullPattern"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Regex.escape(rawText)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Regex(Regex.escape(rawText), options)
|
return Regex(pattern, setOf(RegexOption.MULTILINE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +69,10 @@ internal sealed class SearchQuery {
|
|||||||
class RegularExpression(private val pattern: String) : SearchQuery() {
|
class RegularExpression(private val pattern: String) : SearchQuery() {
|
||||||
override val rawText = ""
|
override val rawText = ""
|
||||||
|
|
||||||
|
override fun refine(char: Char): SearchQuery {
|
||||||
|
return Literal(char.toString(), excludeMiddlesOfWords = false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
|
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ class Session(private val mainEditor: Editor, private val jumpEditors: List<Edit
|
|||||||
val state = state ?: return
|
val state = state ?: return
|
||||||
|
|
||||||
editorSettings.startEditing(editor)
|
editorSettings.startEditing(editor)
|
||||||
val result = mode.type(state, AceConfig.layout.characterRemapping.getOrDefault(charTyped, charTyped), acceptedTag)
|
val result = mode.type(state, charTyped, acceptedTag)
|
||||||
editorSettings.stopEditing(editor)
|
editorSettings.stopEditing(editor)
|
||||||
|
|
||||||
when (result) {
|
when (result) {
|
||||||
@ -128,7 +128,7 @@ class Session(private val mainEditor: Editor, private val jumpEditors: List<Edit
|
|||||||
canvas.setMarkers(emptyList())
|
canvas.setMarkers(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
val processor = SearchProcessor.fromRegex(jumpEditors, pattern.regex, defaultBoundary)
|
val processor = SearchProcessor(jumpEditors, SearchQuery.RegularExpression(pattern.regex), defaultBoundary)
|
||||||
textHighlighter.renderOccurrences(processor.resultsCopy, processor.query)
|
textHighlighter.renderOccurrences(processor.resultsCopy, processor.query)
|
||||||
|
|
||||||
state = SessionState.SelectTag(actions, jumpEditors, processor)
|
state = SessionState.SelectTag(actions, jumpEditors, processor)
|
||||||
|
@ -2,7 +2,9 @@ package org.acejump.session
|
|||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import org.acejump.boundaries.Boundaries
|
import org.acejump.boundaries.Boundaries
|
||||||
|
import org.acejump.config.AceConfig
|
||||||
import org.acejump.search.SearchProcessor
|
import org.acejump.search.SearchProcessor
|
||||||
|
import org.acejump.search.SearchQuery
|
||||||
import org.acejump.search.Tagger
|
import org.acejump.search.Tagger
|
||||||
import org.acejump.search.TaggingResult
|
import org.acejump.search.TaggingResult
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ sealed interface SessionState {
|
|||||||
private val defaultBoundary: Boundaries,
|
private val defaultBoundary: Boundaries,
|
||||||
) : SessionState {
|
) : SessionState {
|
||||||
override fun type(char: Char): TypeResult {
|
override fun type(char: Char): TypeResult {
|
||||||
val searchProcessor = SearchProcessor.fromString(jumpEditors, char.toString(), defaultBoundary)
|
val searchProcessor = SearchProcessor(jumpEditors, SearchQuery.Literal(char.toString(), excludeMiddlesOfWords = true), defaultBoundary)
|
||||||
|
|
||||||
return if (searchProcessor.isQueryFinished) {
|
return if (searchProcessor.isQueryFinished) {
|
||||||
TypeResult.ChangeState(SelectTag(actions, jumpEditors, searchProcessor))
|
TypeResult.ChangeState(SelectTag(actions, jumpEditors, searchProcessor))
|
||||||
@ -49,8 +51,8 @@ sealed interface SessionState {
|
|||||||
|
|
||||||
class SelectTag internal constructor(
|
class SelectTag internal constructor(
|
||||||
private val actions: SessionActions,
|
private val actions: SessionActions,
|
||||||
jumpEditors: List<Editor>,
|
private val jumpEditors: List<Editor>,
|
||||||
searchProcessor: SearchProcessor,
|
private val searchProcessor: SearchProcessor,
|
||||||
) : SessionState {
|
) : SessionState {
|
||||||
private val tagger = Tagger(jumpEditors, searchProcessor.resultsCopy)
|
private val tagger = Tagger(jumpEditors, searchProcessor.resultsCopy)
|
||||||
|
|
||||||
@ -59,7 +61,16 @@ sealed interface SessionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun type(char: Char): TypeResult {
|
override fun type(char: Char): TypeResult {
|
||||||
return when (val result = tagger.type(char)) {
|
if (char == ' ') {
|
||||||
|
val query = searchProcessor.query
|
||||||
|
if (query is SearchQuery.Literal && query.excludeMiddlesOfWords) {
|
||||||
|
val newQuery = SearchQuery.Literal(query.rawText, excludeMiddlesOfWords = false)
|
||||||
|
val newSearchProcessor = SearchProcessor(jumpEditors, newQuery, searchProcessor.boundaries)
|
||||||
|
return TypeResult.ChangeState(SelectTag(actions, jumpEditors, newSearchProcessor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (val result = tagger.type(AceConfig.layout.characterRemapping.getOrDefault(char, char))) {
|
||||||
is TaggingResult.Nothing -> TypeResult.Nothing
|
is TaggingResult.Nothing -> TypeResult.Nothing
|
||||||
is TaggingResult.Accept -> TypeResult.AcceptTag(result.tag)
|
is TaggingResult.Accept -> TypeResult.AcceptTag(result.tag)
|
||||||
is TaggingResult.Mark -> {
|
is TaggingResult.Mark -> {
|
||||||
|
Loading…
Reference in New Issue
Block a user