1
0
mirror of https://github.com/chylex/IntelliJ-AceJump.git synced 2025-09-15 14:32:08 +02:00

16 Commits

16 changed files with 136 additions and 134 deletions

View File

@@ -4,23 +4,26 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.9.10"
id("org.jetbrains.intellij") version "1.16.1"
id("org.jetbrains.intellij") version "1.17.3"
}
group = "org.acejump"
version = "chylex-16"
version = "chylex-21"
repositories {
mavenCentral()
}
intellij {
version.set("2023.3")
version.set("2024.2")
updateSinceUntilBuild.set(false)
plugins.add("IdeaVIM:chylex-22")
// plugins.add("IdeaVIM:chylex-40")
// plugins.add("com.intellij.classic.ui:242.20224.159")
pluginsRepositories {
custom("https://intellij.chylex.com")
// custom("https://intellij.chylex.com")
// marketplace()
}
}
@@ -33,7 +36,7 @@ dependencies {
}
tasks.patchPluginXml {
sinceBuild.set("233")
sinceBuild.set("242")
}
tasks.buildSearchableOptions {

View File

@@ -7,8 +7,6 @@ import com.intellij.openapi.project.Project
import com.intellij.util.IncorrectOperationException
import it.unimi.dsi.fastutil.ints.IntArrayList
annotation class ExternalUsage
/**
* Returns an immutable version of the currently edited document.
*/
@@ -52,57 +50,6 @@ fun CharSequence.countMatchingCharacters(selfOffset: Int, otherText: String): In
return i
}
/**
* Determines which characters form a "word" for the purposes of functions below.
*/
val Char.isWordPart
get() = this in 'a'..'z' || this.isJavaIdentifierPart()
/**
* Finds index of the first character in a word.
*/
inline fun CharSequence.wordStart(pos: Int, isPartOfWord: (Char) -> Boolean = Char::isWordPart): Int {
var start = pos
while (start > 0 && isPartOfWord(this[start - 1])) {
--start
}
return start
}
/**
* Finds index of the last character in a word.
*/
inline fun CharSequence.wordEnd(pos: Int, isPartOfWord: (Char) -> Boolean = Char::isWordPart): Int {
var end = pos
val limit = length - 1
while (end < limit && isPartOfWord(this[end + 1])) {
++end
}
return end
}
/**
* Finds index of the first word character following a sequence of non-word characters following the end of a word.
*/
inline fun CharSequence.wordEndPlus(pos: Int, isPartOfWord: (Char) -> Boolean = Char::isWordPart): Int {
var end = this.wordEnd(pos, isPartOfWord)
val limit = length - 1
while (end < limit && !isPartOfWord(this[end + 1])) {
++end
}
if (end < limit && isPartOfWord(this[end + 1])) {
++end
}
return end
}
fun MutableMap<Editor, IntArrayList>.clone(): MutableMap<Editor, IntArrayList> {
val clone = HashMap<Editor, IntArrayList>(size)

View File

@@ -10,13 +10,12 @@ 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.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 com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import org.acejump.boundaries.StandardBoundaries.AFTER_CARET
import org.acejump.boundaries.StandardBoundaries.BEFORE_CARET
@@ -52,12 +51,11 @@ sealed class AceVimAction : DumbAwareAction() {
}
else {
val vim = editor.vim
val commandState = vim.vimStateMachine
if (commandState.isOperatorPending) {
val key = commandState.commandBuilder.keys.singleOrNull()?.keyChar
val keyHandler = KeyHandler.getInstance()
if (keyHandler.isOperatorPending(vim.mode, keyHandler.keyHandlerState)) {
val key = keyHandler.keyHandlerState.commandBuilder.keys.singleOrNull()?.keyChar
commandState.reset()
KeyHandler.getInstance().fullReset(vim)
keyHandler.fullReset(vim)
AceVimUtil.enterVisualMode(vim, SelectionType.CHARACTER_WISE)
caret.vim.vimSetSelection(caret.offset, initialOffset, moveCaretToSelectionEnd = true)
@@ -72,15 +70,16 @@ sealed class AceVimAction : DumbAwareAction() {
if (action != null) {
ApplicationManager.getApplication().invokeLater {
WriteAction.run<Nothing> {
commandState.commandBuilder.pushCommandPart(action)
keyHandler.keyHandlerState.commandBuilder.pushCommandPart(action)
val cmd = commandState.commandBuilder.buildCommand()
val operatorArguments = OperatorArguments(commandState.mappingState.mappingMode == OP_PENDING, cmd.rawCount, commandState.mode)
val cmd = keyHandler.keyHandlerState.commandBuilder.buildCommand()
val operatorArguments = OperatorArguments(vim.mode is Mode.OP_PENDING, cmd.rawCount, injector.vimState.mode)
commandState.executingCommand = cmd
injector.vimState.executingCommand = cmd
injector.actionExecutor.executeVimAction(vim, action, context, operatorArguments)
// TODO does not update status
}
keyHandler.reset(vim)
}
}
}

View File

@@ -20,6 +20,7 @@ class AceConfig : PersistentStateComponent<AceSettings> {
val layout get() = settings.layout
val minQueryLength get() = settings.minQueryLength
val editorFadeOpacity get() = settings.editorFadeOpacity
val jumpModeColor get() = settings.jumpModeColor
val tagForegroundColor1 get() = settings.tagForegroundColor1
val tagForegroundColor2 get() = settings.tagForegroundColor2

View File

@@ -16,6 +16,7 @@ class AceConfigurable : Configurable {
panel.prefixChars != settings.prefixChars ||
panel.keyboardLayout != settings.layout ||
panel.minQueryLengthInt != settings.minQueryLength ||
panel.editorFadeOpacityPercent != settings.editorFadeOpacity ||
panel.jumpModeColor != settings.jumpModeColor ||
panel.tagForegroundColor1 != settings.tagForegroundColor1 ||
panel.tagForegroundColor2 != settings.tagForegroundColor2 ||
@@ -26,6 +27,7 @@ class AceConfigurable : Configurable {
settings.prefixChars = panel.prefixChars
settings.layout = panel.keyboardLayout
settings.minQueryLength = panel.minQueryLengthInt ?: settings.minQueryLength
settings.editorFadeOpacity = panel.editorFadeOpacityPercent
panel.jumpModeColor?.let { settings.jumpModeColor = it }
panel.tagForegroundColor1?.let { settings.tagForegroundColor1 = it }
panel.tagForegroundColor2?.let { settings.tagForegroundColor2 = it }

View File

@@ -10,6 +10,7 @@ data class AceSettings(
var allowedChars: String = layout.allChars,
var prefixChars: String = ";",
var minQueryLength: Int = 1,
var editorFadeOpacity: Int = 70,
@OptionTag("jumpModeRGB", converter = ColorConverter::class)
var jumpModeColor: Color = Color(0xFFFFFF),

View File

@@ -2,6 +2,7 @@ package org.acejump.config
import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.ColorPanel
import com.intellij.ui.components.JBSlider
import com.intellij.ui.components.JBTextArea
import com.intellij.ui.components.JBTextField
import com.intellij.ui.layout.Cell
@@ -11,9 +12,12 @@ import com.intellij.ui.layout.panel
import org.acejump.input.KeyLayout
import java.awt.Color
import java.awt.Font
import java.util.Hashtable
import javax.swing.JCheckBox
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JSlider
import javax.swing.text.JTextComponent
import kotlin.reflect.KProperty
@@ -27,6 +31,14 @@ internal class AceSettingsPanel {
private val keyboardLayoutCombo = ComboBox<KeyLayout>()
private val keyboardLayoutArea = JBTextArea().apply { isEditable = false }
private val minQueryLengthField = JBTextField()
private val editorFadeOpacitySlider = JBSlider(0, 10).apply {
labelTable = Hashtable((0..10).associateWith { JLabel("${it * 10}") })
paintTrack = true
paintLabels = true
paintTicks = true
minorTickSpacing = 1
majorTickSpacing = 1
}
private val jumpModeColorWheel = ColorPanel()
private val tagForeground1ColorWheel = ColorPanel()
private val tagForeground2ColorWheel = ColorPanel()
@@ -71,6 +83,9 @@ internal class AceSettingsPanel {
component(searchHighlightColorWheel)
}
}
row("Editor fade opacity (%):") {
medium(editorFadeOpacitySlider)
}
}
}
@@ -80,6 +95,7 @@ internal class AceSettingsPanel {
internal var keyboardLayout by keyboardLayoutCombo
internal var keyChars by keyboardLayoutArea
internal var minQueryLength by minQueryLengthField
internal var editorFadeOpacity by editorFadeOpacitySlider
internal var jumpModeColor by jumpModeColorWheel
internal var tagForegroundColor1 by tagForeground1ColorWheel
internal var tagForegroundColor2 by tagForeground2ColorWheel
@@ -89,11 +105,16 @@ internal class AceSettingsPanel {
get() = minQueryLength.toIntOrNull()?.coerceIn(1, 10)
set(value) { minQueryLength = value.toString() }
internal var editorFadeOpacityPercent
get() = editorFadeOpacity * 10
set(value) { editorFadeOpacity = value / 10 }
fun reset(settings: AceSettings) {
allowedChars = settings.allowedChars
prefixChars = settings.prefixChars
keyboardLayout = settings.layout
minQueryLength = settings.minQueryLength.toString()
editorFadeOpacityPercent = settings.editorFadeOpacity
jumpModeColor = settings.jumpModeColor
tagForegroundColor1 = settings.tagForegroundColor1
tagForegroundColor2 = settings.tagForegroundColor2
@@ -111,6 +132,9 @@ internal class AceSettingsPanel {
private operator fun JCheckBox.getValue(a: AceSettingsPanel, p: KProperty<*>) = isSelected
private operator fun JCheckBox.setValue(a: AceSettingsPanel, p: KProperty<*>, selected: Boolean) = setSelected(selected)
private operator fun JSlider.getValue(a: AceSettingsPanel, p: KProperty<*>) = value
private operator fun JSlider.setValue(a: AceSettingsPanel, p: KProperty<*>, value: Int) = setValue(value)
private operator fun <T> ComboBox<T>.getValue(a: AceSettingsPanel, p: KProperty<*>) = selectedItem as T
private operator fun <T> ComboBox<T>.setValue(a: AceSettingsPanel, p: KProperty<*>, item: T) = setSelectedItem(item)

View File

@@ -4,13 +4,25 @@ package org.acejump.input
* Defines common keyboard layouts. Each layout has a key priority order, based on each key's distance from the home row and how
* ergonomically difficult they are to press.
*/
@Suppress("unused")
enum class KeyLayout(internal val rows: Array<String>, priority: String) {
@Suppress("unused", "SpellCheckingInspection")
enum class KeyLayout(internal val rows: Array<String>, priority: String, internal val characterRemapping: Map<Char, Char> = emptyMap()) {
COLEMK(arrayOf("1234567890", "qwfpgjluy", "arstdhneio", "zxcvbkm"), priority = "tndhseriaovkcmbxzgjplfuwyq5849673210"),
WORKMN(arrayOf("1234567890", "qdrwbjfup", "ashtgyneoi", "zxmcvkl"), priority = "tnhegysoaiclvkmxzwfrubjdpq5849673210"),
DVORAK(arrayOf("1234567890", "pyfgcrl", "aoeuidhtns", "qjkxbmwvz"), priority = "uhetidonasxkbjmqwvzgfycprl5849673210"),
QWERTY(arrayOf("1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"), priority = "fjghdkslavncmbxzrutyeiwoqp5849673210"),
QWERTZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210"),
QWERTZ_CZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210", characterRemapping = mapOf(
'+' to '1',
'ě' to '2',
'š' to '3',
'č' to '4',
'ř' to '5',
'ž' to '6',
'ý' to '7',
'á' to '8',
'í' to '9',
'é' to '0'
)),
QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"),
QGMLWB(arrayOf("1234567890", "qgmlwbyuv", "dstnriaeoh", "zxcfjkp"), priority = "naterisodhfkcpjxzlymuwbgvq5849673210"),
NORMAN(arrayOf("1234567890", "qwdfkjurl", "asetgynioh", "zxcvbpm"), priority = "tneigysoahbvpcmxzjkufrdlwq5849673210");

View File

@@ -7,13 +7,6 @@ import org.acejump.config.AceSettings
* with repeated keys (ex. FF, JJ) or adjacent keys (ex. GH, UJ).
*/
internal object KeyLayoutCache {
/**
* Sorts tags according to current keyboard layout settings, and some predefined rules that force tags with digits, and tags with two
* keys far apart, to be sorted after other (easier to type) tags.
*/
lateinit var tagOrder: Comparator<String>
private set
/**
* Returns all possible two key tags, pre-sorted according to [tagOrder].
*/
@@ -24,7 +17,7 @@ internal object KeyLayoutCache {
* Called before any lazily initialized properties are used, to ensure that they are initialized even if the settings are missing.
*/
fun ensureInitialized(settings: AceSettings) {
if (!::tagOrder.isInitialized) {
if (!::allPossibleTagsLowercase.isInitialized) {
reset(settings)
}
}
@@ -33,15 +26,16 @@ internal object KeyLayoutCache {
* Re-initializes cached data according to updated settings.
*/
fun reset(settings: AceSettings) {
tagOrder = compareBy(
String::length,
settings.layout.priority(String::last)
)
@Suppress("ConvertLambdaToReference")
val allSuffixChars = processCharList(settings.allowedChars).ifEmpty { processCharList(settings.layout.allChars).toList() }
val allPrefixChars = processCharList(settings.prefixChars).filterNot(allSuffixChars::contains).plus("")
val tagOrder = compareBy(
String::length,
{ if (it.length == 1) Int.MIN_VALUE else allPrefixChars.indexOf(it.first().toString()) },
settings.layout.priority(String::last)
)
allPossibleTagsLowercase = allSuffixChars
.flatMap { suffix -> allPrefixChars.map { prefix -> "$prefix$suffix" } }
.sortedWith(tagOrder)

View File

@@ -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.
*/
class SearchProcessor private constructor(query: SearchQuery, private val results: MutableMap<Editor, IntArrayList>) {
companion object {
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()) {
class SearchProcessor private constructor(query: SearchQuery, val boundaries: Boundaries, private val results: MutableMap<Editor, IntArrayList>) {
internal constructor(editors: List<Editor>, query: SearchQuery, boundaries: Boundaries) : this(query, boundaries, mutableMapOf()) {
val regex = query.toRegex()
if (regex != null) {
@@ -39,7 +29,7 @@ class SearchProcessor private constructor(query: SearchQuery, private val result
if (highlightEnd > offsetRange.last) {
break
}
else if (boundaries.isOffsetInside(editor, index)) {
else if (boundaries.isOffsetInside(editor, index) && !editor.foldingModel.isOffsetCollapsed(index)) {
offsets.add(index)
}
@@ -65,7 +55,7 @@ class SearchProcessor private constructor(query: SearchQuery, private val result
return true
}
else {
query = SearchQuery.Literal(query.rawText + char)
query = query.refine(char)
removeObsoleteResults()
return isQueryFinished
}

View File

@@ -8,6 +8,11 @@ import org.acejump.countMatchingCharacters
internal sealed class SearchQuery {
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.
*/
@@ -19,29 +24,42 @@ internal sealed class SearchQuery {
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
* case-insensitive.
*
* 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.
* Searches for all occurrences of a literal text query.
* 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.
*/
class Literal(override val rawText: String) : SearchQuery() {
class Literal(override val rawText: String, val excludeMiddlesOfWords: Boolean) : SearchQuery() {
init {
require(rawText.isNotEmpty())
}
override fun refine(char: Char): SearchQuery {
return Literal(rawText + char, excludeMiddlesOfWords)
}
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
return text.countMatchingCharacters(offset, rawText)
}
override fun toRegex(): Regex {
val options = mutableSetOf(RegexOption.MULTILINE)
if (rawText.first().isLowerCase()) {
options.add(RegexOption.IGNORE_CASE)
val firstChar = rawText.first()
val pattern = if (firstChar.isLowerCase()) {
if (excludeMiddlesOfWords) {
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() {
override val rawText = ""
override fun refine(char: Char): SearchQuery {
return Literal(char.toString(), excludeMiddlesOfWords = false)
}
override fun getHighlightLength(text: CharSequence, offset: Int): Int {
return 1
}

View File

@@ -5,13 +5,10 @@ import com.intellij.openapi.editor.Editor
import it.unimi.dsi.fastutil.ints.IntList
import org.acejump.boundaries.EditorOffsetCache
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
import org.acejump.immutableText
import org.acejump.input.KeyLayoutCache
import org.acejump.isWordPart
import org.acejump.view.TagMarker
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.math.max
import kotlin.math.min
/**
@@ -92,26 +89,24 @@ class Tagger(private val editors: List<Editor>, results: Map<Editor, IntList>) {
return@Comparator if (aEditorIndex < bEditorIndex) -1 else 1
}
val aIsVisible = VISIBLE_ON_SCREEN.isOffsetInside(aEditor, a.offset, caches.getValue(aEditor))
val bIsVisible = VISIBLE_ON_SCREEN.isOffsetInside(bEditor, b.offset, caches.getValue(bEditor))
val aCaches = caches.getValue(aEditor)
val bCaches = caches.getValue(bEditor)
val aIsVisible = VISIBLE_ON_SCREEN.isOffsetInside(aEditor, a.offset, aCaches)
val bIsVisible = VISIBLE_ON_SCREEN.isOffsetInside(bEditor, b.offset, bCaches)
if (aIsVisible != bIsVisible) {
// Sites in immediate view should come first.
return@Comparator if (aIsVisible) -1 else 1
}
val aIsNotWordStart = aEditor.immutableText[max(0, a.offset - 1)].isWordPart
val bIsNotWordStart = bEditor.immutableText[max(0, b.offset - 1)].isWordPart
if (aIsNotWordStart != bIsNotWordStart) {
// Ensure that the first letter of a word is prioritized for tagging.
return@Comparator if (bIsNotWordStart) -1 else 1
}
val aPosition = aCaches.offsetToXY(aEditor, a.offset)
val bPosition = bCaches.offsetToXY(bEditor, b.offset)
when {
a.offset < b.offset -> -1
a.offset > b.offset -> 1
else -> 0
}
val caretPosition = editorPriority[0].offsetToXY(editorPriority[0].caretModel.offset)
val aDistance = aPosition.distanceSq(caretPosition)
val bDistance = bPosition.distanceSq(caretPosition)
return@Comparator aDistance.compareTo(bDistance)
}
}
}

View File

@@ -128,7 +128,7 @@ class Session(private val mainEditor: Editor, private val jumpEditors: List<Edit
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)
state = SessionState.SelectTag(actions, jumpEditors, processor)

View File

@@ -2,7 +2,9 @@ package org.acejump.session
import com.intellij.openapi.editor.Editor
import org.acejump.boundaries.Boundaries
import org.acejump.config.AceConfig
import org.acejump.search.SearchProcessor
import org.acejump.search.SearchQuery
import org.acejump.search.Tagger
import org.acejump.search.TaggingResult
@@ -15,7 +17,7 @@ sealed interface SessionState {
private val defaultBoundary: Boundaries,
) : SessionState {
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) {
TypeResult.ChangeState(SelectTag(actions, jumpEditors, searchProcessor))
@@ -49,8 +51,8 @@ sealed interface SessionState {
class SelectTag internal constructor(
private val actions: SessionActions,
jumpEditors: List<Editor>,
searchProcessor: SearchProcessor,
private val jumpEditors: List<Editor>,
private val searchProcessor: SearchProcessor,
) : SessionState {
private val tagger = Tagger(jumpEditors, searchProcessor.resultsCopy)
@@ -59,7 +61,16 @@ sealed interface SessionState {
}
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.Accept -> TypeResult.AcceptTag(result.tag)
is TaggingResult.Mark -> {

View File

@@ -5,6 +5,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.ui.ColorUtil
import org.acejump.boundaries.EditorOffsetCache
import org.acejump.boundaries.StandardBoundaries
import org.acejump.config.AceConfig
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.Rectangle
@@ -53,7 +54,7 @@ internal class TagCanvas(private val editor: Editor) : JComponent() {
return
}
g.color = ColorUtil.withAlpha(editor.colorsScheme.defaultBackground, 0.6)
g.color = ColorUtil.withAlpha(editor.colorsScheme.defaultBackground, (AceConfig.editorFadeOpacity * 0.01).coerceIn(0.0, 1.0))
g.fillRect(0, 0, width - 1, height - 1)
if (markers.isEmpty()) {