Skip to content

Commit

Permalink
feat: color settings page
Browse files Browse the repository at this point in the history
Features/#431 color settings page
  • Loading branch information
dakochik authored Nov 20, 2021
2 parents 1fca68b + 01311d6 commit 3804194
Show file tree
Hide file tree
Showing 14 changed files with 431 additions and 136 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Released on ...
- TODO (see [#NNN](https://github.com/JetBrains-Research/snakecharm/issues/NNN))

### Added
- Color Settings Page (see [#431](https://github.com/JetBrains-Research/snakecharm/issues/431))
- Inspection: highlights 'use rule' section which overrides several rules as one (see [#411](https://github.com/JetBrains-Research/snakecharm/issues/411))
- Weak warnings for unused 'log' sections in 'use rule' (see [#414](https://github.com/JetBrains-Research/snakecharm/issues/414))
- Weak warnings for unused 'log' sections (see [#300](https://github.com/JetBrains-Research/snakecharm/issues/300))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.jetbrains.snakecharm.lang.highlighter

import com.intellij.codeHighlighting.RainbowHighlighter
import com.intellij.lang.Language
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
import com.intellij.openapi.options.colors.AttributesDescriptor
import com.intellij.openapi.options.colors.ColorDescriptor
import com.intellij.openapi.options.colors.RainbowColorSettingsPage
import com.jetbrains.python.PythonLanguage
import com.jetbrains.python.highlighting.PyRainbowVisitor
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.snakecharm.SnakemakeBundle
import com.jetbrains.snakecharm.SnakemakeIcons
import com.jetbrains.snakecharm.lang.SnakemakeLanguageDialect
import com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLSyntaxHighlighter
import javax.swing.Icon

class SmkColorSettingsPage : RainbowColorSettingsPage {
override fun getAttributeDescriptors(): Array<AttributesDescriptor> = arrayOf(
AttributesDescriptor(
SnakemakeBundle.message("smk.color.keyword"),
SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.definition"),
SnakemakeSyntaxHighlighterFactory.SMK_FUNC_DEFINITION
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.subsection"),
SnakemakeSyntaxHighlighterFactory.SMK_DECORATOR
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.run"),
SnakemakeSyntaxHighlighterFactory.SMK_PREDEFINED_DEFINITION
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.keyword.arg"),
SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD_ARGUMENT
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.text"),
SnakemakeSyntaxHighlighterFactory.SMK_TEXT
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.tqs"),
SnakemakeSyntaxHighlighterFactory.SMK_TRIPLE_QUOTED_STRING
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.SL.content"),
SmkSLSyntaxHighlighter.STRING_CONTENT
),
AttributesDescriptor(SnakemakeBundle.message("smk.color.string.SL.braces"), SmkSLSyntaxHighlighter.BRACES),
AttributesDescriptor(SnakemakeBundle.message("smk.color.string.SL.comma"), SmkSLSyntaxHighlighter.COMMA),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.SL.format"),
SmkSLSyntaxHighlighter.FORMAT_SPECIFIER
),
AttributesDescriptor(SnakemakeBundle.message("smk.color.string.SL.key"), SmkSLSyntaxHighlighter.ACCESS_KEY),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.SL.reference"),
SmkSLSyntaxHighlighter.IDENTIFIER
),
AttributesDescriptor(
SnakemakeBundle.message("smk.color.string.SL.wildcard"),
SmkSLSyntaxHighlighter.HIGHLIGHTING_WILDCARDS_KEY
)
)

override fun getColorDescriptors(): Array<ColorDescriptor> = ColorDescriptor.EMPTY_ARRAY

override fun getDisplayName(): String = SnakemakeBundle.message("snakemake.settings.name")

override fun getIcon(): Icon = SnakemakeIcons.FILE

override fun getHighlighter(): SyntaxHighlighter {
val lang = SnakemakeLanguageDialect.baseLanguage ?: PythonLanguage.getInstance()
val factory = SyntaxHighlighterFactory.LANGUAGE_FACTORY.forLanguage(lang)
if (factory is SnakemakeSyntaxHighlighterFactory) {
return factory.getSyntaxHighlighterForLanguageLevel(LanguageLevel.getLatest())
}
return factory.getSyntaxHighlighter(null, null)
}

override fun getDemoText(): String =
"""
<keyword>configfile</keyword>: <text>"config/config.yaml"</text>
<keyword>localrules</keyword>: NAME
""".trimIndent() +
"\n<keyword>rule</keyword> <identifiers>NAME</identifiers>:\n" +
" <TQS>\"\"\"\n" +
" Syntax Highlighting Demo" +
RainbowHighlighter.generatePaletteExample("\n ") +
"\n \"\"\"</TQS>\n" +
"""
<sectionName>input</sectionName>:
<text>"</text><injectedText>file_</injectedText><braces>{</braces><wildcard>number</wildcard><braces>}</braces><injectedText>.txt</injectedText><text>"</text>,
<keywordArg>arg</keywordArg> = <text>"file_1.txt"</text>
<sectionName>output</sectionName>:
<text>"</text><injectedText>file_</injectedText><braces>{</braces><wildcard>number</wildcard><braces>}</braces><injectedText>.txt</injectedText><text>"</text>
<run>run</run>:
<localVar>x</localVar> = 2
shell(<text>"</text><injectedText>touch </injectedText><braces>{</braces><reference>output</reference><braces>}</braces><text>"</text>)
<localVar>number</localVar> = 0.451 # Python elements are configured in Python color settings
<keyword>use</keyword> <keyword>rule</keyword> NAME <keyword>as</keyword> <identifiers>NAME_2</identifiers> <keyword>with</keyword>:
<sectionName>message</sectionName>:
<text>"</text><injectedText>Float number: </injectedText><braces>{</braces><reference>number</reference><formatSpecifier>:2f</formatSpecifier><braces>}</braces><text>"</text>
""".trimIndent()

override fun getAdditionalHighlightingTagToDescriptorMap(): MutableMap<String, TextAttributesKey> =
mutableMapOf<String, TextAttributesKey>().also {
it["keyword"] = SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD
it["identifiers"] = SnakemakeSyntaxHighlighterFactory.SMK_FUNC_DEFINITION
it["sectionName"] = SnakemakeSyntaxHighlighterFactory.SMK_DECORATOR
it["run"] = SnakemakeSyntaxHighlighterFactory.SMK_PREDEFINED_DEFINITION
it["text"] = SnakemakeSyntaxHighlighterFactory.SMK_TEXT
it["TQS"] = SnakemakeSyntaxHighlighterFactory.SMK_TRIPLE_QUOTED_STRING
it["keywordArg"] = SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD_ARGUMENT

it["injectedText"] = SmkSLSyntaxHighlighter.STRING_CONTENT
it["braces"] = SmkSLSyntaxHighlighter.BRACES
it["comma"] = SmkSLSyntaxHighlighter.COMMA
it["formatSpecifier"] = SmkSLSyntaxHighlighter.FORMAT_SPECIFIER
it["accessKey"] = SmkSLSyntaxHighlighter.ACCESS_KEY
it["reference"] = SmkSLSyntaxHighlighter.IDENTIFIER
it["wildcard"] = SmkSLSyntaxHighlighter.HIGHLIGHTING_WILDCARDS_KEY

it["localVar"] = DefaultLanguageHighlighterColors.LOCAL_VARIABLE
it.putAll(RainbowHighlighter.createRainbowHLM())
}

override fun isRainbowType(type: TextAttributesKey?): Boolean =
PyRainbowVisitor.Holder.HIGHLIGHTING_KEYS.contains(type)

override fun getLanguage(): Language = SnakemakeLanguageDialect
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.jetbrains.snakecharm.lang.highlighter

import com.jetbrains.python.PyTokenTypes
import com.jetbrains.python.highlighting.PyHighlighter
import com.jetbrains.python.highlighting.PyHighlighter.PY_FUNC_DEFINITION
import com.jetbrains.snakecharm.lang.parser.SmkTokenTypes
import com.jetbrains.snakecharm.lang.psi.*
import com.jetbrains.snakecharm.lang.psi.elementTypes.SmkElementTypes
Expand Down Expand Up @@ -36,10 +34,10 @@ object SmkSyntaxAnnotator : SmkAnnotator() {
SmkTokenTypes.RULE_KEYWORD, SmkTokenTypes.SMK_FROM_KEYWORD,
SmkTokenTypes.SMK_AS_KEYWORD, SmkTokenTypes.SMK_WITH_KEYWORD -> addHighlightingAnnotation(
next,
PyHighlighter.PY_KEYWORD
SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD
)
SmkElementTypes.USE_NAME_IDENTIFIER, PyTokenTypes.IDENTIFIER -> addHighlightingAnnotation(
next, PY_FUNC_DEFINITION
next, SnakemakeSyntaxHighlighterFactory.SMK_FUNC_DEFINITION
)
PyTokenTypes.COLON -> done = true
}
Expand All @@ -61,7 +59,7 @@ object SmkSyntaxAnnotator : SmkAnnotator() {

override fun visitSmkRunSection(st: SmkRunSection) {
st.getSectionKeywordNode()?.let {
addHighlightingAnnotation(it, PyHighlighter.PY_PREDEFINED_DEFINITION)
addHighlightingAnnotation(it, SnakemakeSyntaxHighlighterFactory.SMK_PREDEFINED_DEFINITION)
}
}

Expand All @@ -85,19 +83,29 @@ object SmkSyntaxAnnotator : SmkAnnotator() {
highlightWorkflowSection(ruleLike)

ruleLike.nameIdentifier?.let { nameElement ->
addHighlightingAnnotation(nameElement, PY_FUNC_DEFINITION)
addHighlightingAnnotation(nameElement, SnakemakeSyntaxHighlighterFactory.SMK_FUNC_DEFINITION)
}
}

private fun highlightWorkflowSection(st: SmkSection) {
st.getSectionKeywordNode()?.let {
addHighlightingAnnotation(it, PyHighlighter.PY_KEYWORD)
addHighlightingAnnotation(it, SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD)
}
}

private fun highlightRuleLikeSection(st: SmkSection) {
st.getSectionKeywordNode()?.let {
addHighlightingAnnotation(it, PyHighlighter.PY_DECORATOR)
addHighlightingAnnotation(it, SnakemakeSyntaxHighlighterFactory.SMK_DECORATOR)
}
if (st is SmkArgsSection) {
st.keywordArguments?.forEach {
it.keywordNode?.psi?.let { name ->
addHighlightingAnnotation(
name,
SnakemakeSyntaxHighlighterFactory.SMK_KEYWORD_ARGUMENT
)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.snakecharm.lang.psi.impl.SmkPsiUtil
import com.jetbrains.snakecharm.lang.psi.types.SmkWildcardsType
import com.jetbrains.snakecharm.lang.validation.SmkAnnotator
import com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLWildcardsAnnotator.HIGHLIGHTING_WILDCARDS_KEY
import com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLSyntaxHighlighter.Companion.HIGHLIGHTING_WILDCARDS_KEY

object SmkWildcardsAnnotator : SmkAnnotator() {
override fun visitPyReferenceExpression(expr: PyReferenceExpression) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.jetbrains.snakecharm.lang.highlighter

import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.tree.IElementType
import com.intellij.util.containers.FactoryMap
import com.jetbrains.python.PyTokenTypes
import com.jetbrains.python.highlighting.PyHighlighter
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher
Expand All @@ -14,18 +18,57 @@ import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher
* @date 2018-12-31
*/
class SnakemakeSyntaxHighlighterFactory : SyntaxHighlighterFactory() {
companion object {
val SMK_KEYWORD = TextAttributesKey.createTextAttributesKey(
"SMK_KEYWORD",
DefaultLanguageHighlighterColors.KEYWORD
)
val SMK_FUNC_DEFINITION = TextAttributesKey.createTextAttributesKey(
"SMK_FUNC_DEFINITION",
DefaultLanguageHighlighterColors.FUNCTION_DECLARATION
)
val SMK_DECORATOR = TextAttributesKey.createTextAttributesKey(
"SMK_DECORATOR",
DefaultLanguageHighlighterColors.METADATA
)
val SMK_PREDEFINED_DEFINITION: TextAttributesKey =
PyHighlighter.PY_PREDEFINED_DEFINITION // IDK why, but explicit creating via '.createText...' works improperly
val SMK_KEYWORD_ARGUMENT = TextAttributesKey.createTextAttributesKey(
"SMK_KEYWORD_ARGUMENT",
DefaultLanguageHighlighterColors.PARAMETER
)
val SMK_TEXT = TextAttributesKey.createTextAttributesKey("SMK_TEXT", DefaultLanguageHighlighterColors.STRING)
val SMK_TRIPLE_QUOTED_STRING = TextAttributesKey.createTextAttributesKey(
"SMK_TRIPLE_QUOTED_STRING",
DefaultLanguageHighlighterColors.STRING
)
}

private val myMap = FactoryMap.create<LanguageLevel, PyHighlighter> { key ->
object : PyHighlighter(key) {
override fun getTokenHighlights(tokenType: IElementType?): Array<TextAttributesKey> {
return when (tokenType) {
PyTokenTypes.SINGLE_QUOTED_UNICODE -> arrayOf(SMK_TEXT)
PyTokenTypes.TRIPLE_QUOTED_UNICODE -> arrayOf(SMK_TRIPLE_QUOTED_STRING)
else -> super.getTokenHighlights(tokenType)
}
}

override fun createHighlightingLexer(level: LanguageLevel) = SnakemakeHighlightingLexer(level)
}
}

override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter {
val level = when {
project != null && virtualFile != null -> PythonLanguageLevelPusher.getLanguageLevelForVirtualFile(project, virtualFile)
project != null && virtualFile != null -> PythonLanguageLevelPusher.getLanguageLevelForVirtualFile(
project,
virtualFile
)
else -> LanguageLevel.getDefault()
}

return myMap[level]!!
return getSyntaxHighlighterForLanguageLevel(level)
}

fun getSyntaxHighlighterForLanguageLevel(level: LanguageLevel): SyntaxHighlighter = myMap[level]!!
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jetbrains.snakecharm.stringLanguage.lang.highlighter

import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
Expand All @@ -10,21 +11,25 @@ import com.jetbrains.snakecharm.stringLanguage.lang.parser.SmkSLTokenTypes

class SmkSLSyntaxHighlighter : SyntaxHighlighterBase() {
companion object {
val BRACES = arrayOf(createTextAttributesKey("SMKSL_BRACES", PyHighlighter.PY_FSTRING_FRAGMENT_BRACES))
val COMMA = arrayOf(createTextAttributesKey("SMKSL_COMMA", PyHighlighter.PY_FSTRING_FRAGMENT_COLON))
val STRING_CONTENT = arrayOf(createTextAttributesKey("SMKSL_STRING_CONTENT", PyHighlighter.PY_BYTE_STRING))
val FORMAT_SPECIFIER = arrayOf(createTextAttributesKey("SMKSL_FORMAT_SPECIFIER", PyHighlighter.PY_NUMBER))
val ACCESS_KEY = arrayOf(createTextAttributesKey("SMKSL_ACCESS_KEY", PyHighlighter.PY_KEYWORD_ARGUMENT))
val BRACES = createTextAttributesKey("SMKSL_BRACES", PyHighlighter.PY_FSTRING_FRAGMENT_BRACES)
val COMMA = createTextAttributesKey("SMKSL_COMMA", PyHighlighter.PY_FSTRING_FRAGMENT_COLON)
val STRING_CONTENT = createTextAttributesKey("SMKSL_STRING_CONTENT", PyHighlighter.PY_BYTE_STRING)
val FORMAT_SPECIFIER = createTextAttributesKey("SMKSL_FORMAT_SPECIFIER", PyHighlighter.PY_NUMBER)
val ACCESS_KEY = createTextAttributesKey("SMKSL_ACCESS_KEY", PyHighlighter.PY_KEYWORD_ARGUMENT)
val IDENTIFIER = createTextAttributesKey("SMKSL_IDENTIFIER", DefaultLanguageHighlighterColors.IDENTIFIER)
val HIGHLIGHTING_WILDCARDS_KEY =
createTextAttributesKey("SMKSL_WILDCARD", DefaultLanguageHighlighterColors.NUMBER)
}

override fun getTokenHighlights(tokenType: IElementType?): Array<TextAttributesKey> =
when {
tokenType === SmkSLTokenTypes.LBRACE ||
tokenType === SmkSLTokenTypes.RBRACE -> BRACES
tokenType === SmkSLTokenTypes.COMMA -> COMMA
tokenType === SmkSLTokenTypes.STRING_CONTENT -> STRING_CONTENT
tokenType === SmkSLTokenTypes.FORMAT_SPECIFIER -> FORMAT_SPECIFIER
tokenType === SmkSLTokenTypes.ACCESS_KEY -> ACCESS_KEY
tokenType === SmkSLTokenTypes.RBRACE -> arrayOf(BRACES)
tokenType === SmkSLTokenTypes.COMMA -> arrayOf(COMMA)
tokenType === SmkSLTokenTypes.STRING_CONTENT -> arrayOf(STRING_CONTENT)
tokenType === SmkSLTokenTypes.FORMAT_SPECIFIER -> arrayOf(FORMAT_SPECIFIER)
tokenType === SmkSLTokenTypes.ACCESS_KEY -> arrayOf(ACCESS_KEY)
tokenType === SmkSLTokenTypes.IDENTIFIER -> arrayOf(IDENTIFIER)
else -> emptyArray()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.jetbrains.snakecharm.stringLanguage.lang.highlighter

import com.intellij.lang.annotation.HighlightSeverity
import com.jetbrains.python.highlighting.PyHighlighter
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.snakecharm.lang.psi.types.SmkWildcardsType
import com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLSyntaxHighlighter.Companion.HIGHLIGHTING_WILDCARDS_KEY
import com.jetbrains.snakecharm.stringLanguage.lang.psi.SmkSLReferenceExpressionImpl

object SmkSLWildcardsAnnotator : AbstractSmkSLAnnotator() {
val HIGHLIGHTING_WILDCARDS_KEY = PyHighlighter.PY_NUMBER!!

override fun visitSmkSLReferenceExpression(expr: SmkSLReferenceExpressionImpl) {
val exprIdentifier = expr.nameIdentifier
Expand Down
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 @@ -72,6 +72,7 @@
<lang.syntaxHighlighterFactory language="Snakemake" implementationClass="com.jetbrains.snakecharm.lang.highlighter.SnakemakeSyntaxHighlighterFactory"/>
<lang.syntaxHighlighterFactory language="SnakemakeSL"
implementationClass="com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLSyntaxHighlighterFactory"/>
<colorSettingsPage implementation="com.jetbrains.snakecharm.lang.highlighter.SmkColorSettingsPage"/>
<annotator language="Python" implementationClass="com.jetbrains.snakecharm.lang.SmkDumbAwareAnnotatorManager"/>
<annotator language="Python" implementationClass="com.jetbrains.snakecharm.lang.SmkStandardAnnotatorManager"/>
<annotator language="RegExp" implementationClass="com.jetbrains.snakecharm.stringLanguage.lang.highlighter.SmkSLRegExpHighlightingAnnotator"/>
Expand Down
Loading

0 comments on commit 3804194

Please sign in to comment.