Skip to content

Commit

Permalink
#49: implement semantic highlighting
Browse files Browse the repository at this point in the history
Works for all symbols and keywords. Namespaces are treated as separate highlighted elements. For symbols that was the behaviour by default and for keywords the ns range had to be manually added.
  • Loading branch information
AraneusRota committed Mar 29, 2024
1 parent 91eb0f7 commit 2864e0b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ class ClojureAnnotator : Annotator {
}
}

private fun isNamespaced(element: ClKeyword) =
(element.text?.contains("/") == true) &&
(element.parentOfType<ClSexpComment>(false) == null)

private fun isNsReaderMacro(element: PsiElement) =
(element.prevSibling != null) &&
(element.prevSibling.text == "#:") &&
Expand All @@ -81,4 +77,11 @@ class ClojureAnnotator : Annotator {
(element.nextSibling is LeafPsiElement) &&
((element.nextSibling as LeafPsiElement).elementType.debugName == "ns separator") &&
(element.parentOfType<ClSexpComment>(false) == null)

companion object {
fun isNamespaced(element: ClKeyword) =
(element.text?.contains("/") == true) &&
(element.parentOfType<ClSexpComment>(false) == null)
}

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.github.brcosta.cljstuffplugin.extensions

import com.intellij.codeHighlighting.RainbowHighlighter
import com.intellij.lang.Language
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.options.colors.AttributesDescriptor
import com.intellij.openapi.options.colors.ColorDescriptor
import com.intellij.openapi.options.colors.ColorSettingsPage
import com.intellij.openapi.options.colors.RainbowColorSettingsPage
import cursive.ClojureIcons
import cursive.ClojureLanguage
import cursive.highlighter.ClojureSyntaxHighlighter
import org.jetbrains.annotations.NonNls
import javax.swing.Icon

@Suppress("unused")
class ClojureColorsAndFontsPageEx : ColorSettingsPage {
class ClojureColorsAndFontsPageEx : RainbowColorSettingsPage {

override fun getDisplayName(): String {
return "Clojure Extras"
Expand All @@ -38,18 +41,28 @@ class ClojureColorsAndFontsPageEx : ColorSettingsPage {
}

override fun getAdditionalHighlightingTagToDescriptorMap(): Map<String, TextAttributesKey> {
val map: MutableMap<String, TextAttributesKey> = mutableMapOf()
val map = RainbowHighlighter.createRainbowHLM()
map["keyword-namespace"] = KEYWORD_NAMESPACE
map["symbol-namespace"] = SYMBOL_NAMESPACE
map["head-symbol-namespace"] = HEAD_SYMBOL_NAMESPACE
return map
}

override fun isRainbowType(type: TextAttributesKey?): Boolean {
return type == SEMANTIC_HIGHLIGHTING
}

override fun getLanguage(): Language? {
return ClojureLanguage.getInstance()
}

companion object {
private val ATTRS: Array<AttributesDescriptor>
val KEYWORD_NAMESPACE = TextAttributesKey.createTextAttributesKey("Keyword Namespace")
val SYMBOL_NAMESPACE = TextAttributesKey.createTextAttributesKey("Symbol Namespace")
val HEAD_SYMBOL_NAMESPACE = TextAttributesKey.createTextAttributesKey("Head Symbol Namespace")
val SEMANTIC_HIGHLIGHTING = TextAttributesKey.createTextAttributesKey("Semantic Highlighting")

init {
ATTRS = arrayOf(
AttributesDescriptor("Keyword Namespace", KEYWORD_NAMESPACE),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.github.brcosta.cljstuffplugin.extensions.codeInsight.daemon

import com.github.brcosta.cljstuffplugin.extensions.ClojureAnnotator.Companion.isNamespaced
import com.github.brcosta.cljstuffplugin.extensions.ClojureColorsAndFontsPageEx.Companion.SEMANTIC_HIGHLIGHTING
import com.intellij.codeInsight.daemon.RainbowVisitor
import com.intellij.codeInsight.daemon.UsedColors
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HighlightVisitor
import com.intellij.openapi.util.UserDataHolderEx
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import cursive.psi.api.ClKeyword
import cursive.psi.api.ClojureFile
import cursive.psi.api.symbols.ClSymbol

/**
* Enables semantic highlighting for all symbols and keywords. Namespaces are treated as separate highlighted elements.
*/
class ClojureRainbowVisitor : RainbowVisitor() {
override fun suitableForFile(file: PsiFile): Boolean {
return file is ClojureFile
}

override fun visit(element: PsiElement) {
val maybeName = when (element) {
is ClSymbol -> element.name
is ClKeyword -> element.name
else -> null
}
maybeName?.let { elementName ->
element.context?.let { context ->
fun separateNsHighlighting(keyword: ClKeyword): List<HighlightInfo> {
fun rangedInfo(name: String, start: Int, end: Int): HighlightInfo {
val color =
UsedColors.getOrAddColorIndex((context as UserDataHolderEx), name, highlighter.colorsCount)
return highlighter.getInfo(color, start, end, SEMANTIC_HIGHLIGHTING)
}

val start = keyword.textRange.startOffset
val nsEnd = start + keyword.text.indexOf('/')
return listOf(
rangedInfo(
keyword.namespace,
start,
nsEnd,
),
rangedInfo(
elementName,
nsEnd,
keyword.textRange.endOffset,
)
)
}

if (element is ClKeyword && isNamespaced(element))
separateNsHighlighting(element).forEach(::addInfo)
else
// separate ns highlighting for symbols works by default
addInfo(
getInfo(
context,
element,
elementName,
SEMANTIC_HIGHLIGHTING
)
)

}
}
}

override fun clone(): HighlightVisitor {
return ClojureRainbowVisitor()
}

}
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<externalAnnotator language="Clojure" implementationClass="com.github.brcosta.cljstuffplugin.extensions.CljKondoAnnotator" />

<colorSettingsPage implementation="com.github.brcosta.cljstuffplugin.extensions.ClojureColorsAndFontsPageEx"/>
<highlightVisitor implementation="com.github.brcosta.cljstuffplugin.extensions.codeInsight.daemon.ClojureRainbowVisitor"/>

<additionalTextAttributes file="colors/ClojureStuffDefaultColors.xml" scheme="Default"/>
<additionalTextAttributes file="colors/ClojureStuffDarculaColors.xml" scheme="Darcula"/>
Expand Down

0 comments on commit 2864e0b

Please sign in to comment.