From 5dba5713f746cb9fb1b36433be982493bb3905d2 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Mon, 6 Jan 2025 01:09:41 +0100 Subject: [PATCH] feat(langserver): correct highlightning to better highlight python expresseions, escape sequences, environment variable default value and embedded argument regexes --- .../{RobotColors.kt => Colors.kt} | 0 .../RobotCodeHighlighterProvider.kt | 81 ------------- ...HighlightingLexer.kt => RobotCodeLexer.kt} | 103 +++++++++++++++-- .../RobotCodeSyntaxHighlighter.kt | 109 ++++++++++++++++++ .../robotframework/parts/semantic_tokens.py | 32 ++--- syntaxes/robotframework-repl.tmLanguage.json | 67 +++++++---- syntaxes/robotframework.tmLanguage.json | 67 +++++++---- .../robotframework.tmLanguage.template.json | 67 +++++++---- 8 files changed, 360 insertions(+), 166 deletions(-) rename intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/{RobotColors.kt => Colors.kt} (100%) delete mode 100644 intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeHighlighterProvider.kt rename intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/{RobotTextMateHighlightingLexer.kt => RobotCodeLexer.kt} (52%) create mode 100644 intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeSyntaxHighlighter.kt diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotColors.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/Colors.kt similarity index 100% rename from intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotColors.kt rename to intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/Colors.kt diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeHighlighterProvider.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeHighlighterProvider.kt deleted file mode 100644 index b6cf7e3d..00000000 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeHighlighterProvider.kt +++ /dev/null @@ -1,81 +0,0 @@ -package dev.robotcode.robotcode4ij.highlighting - -import com.intellij.openapi.editor.colors.EditorColorsScheme -import com.intellij.openapi.editor.colors.TextAttributesKey -import com.intellij.openapi.editor.ex.util.DataStorage -import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter -import com.intellij.openapi.editor.highlighter.EditorHighlighter -import com.intellij.openapi.fileTypes.EditorHighlighterProvider -import com.intellij.openapi.fileTypes.FileType -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 dev.robotcode.robotcode4ij.psi.ARGUMENT -import dev.robotcode.robotcode4ij.psi.COMMENT_BLOCK -import dev.robotcode.robotcode4ij.psi.COMMENT_LINE -import dev.robotcode.robotcode4ij.psi.CONTINUATION -import dev.robotcode.robotcode4ij.psi.CONTROL_FLOW -import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_BEGIN -import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_END -import dev.robotcode.robotcode4ij.psi.HEADER -import dev.robotcode.robotcode4ij.psi.KEYWORD_CALL -import dev.robotcode.robotcode4ij.psi.KEYWORD_NAME -import dev.robotcode.robotcode4ij.psi.OPERATOR -import dev.robotcode.robotcode4ij.psi.SETTING -import dev.robotcode.robotcode4ij.psi.TESTCASE_NAME -import dev.robotcode.robotcode4ij.psi.VARIABLE -import dev.robotcode.robotcode4ij.psi.VARIABLE_BEGIN -import dev.robotcode.robotcode4ij.psi.VARIABLE_END -import org.jetbrains.plugins.textmate.language.syntax.highlighting.TextMateHighlighter -import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateLexerDataStorage - -class RobotCodeHighlighterProvider : EditorHighlighterProvider { - override fun getEditorHighlighter( - project: Project?, fileType: FileType, virtualFile: VirtualFile?, colors: EditorColorsScheme - ): EditorHighlighter { - val highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, project, virtualFile) - return RobotCodeEditorHighlighter(highlighter, colors) - } -} - -class RobotCodeHighlighter : TextMateHighlighter(RobotTextMateHighlightingLexer()) { - companion object { - val elementTypeMap = mapOf( - COMMENT_LINE to arrayOf(RobotColors.LINE_COMMENT), - COMMENT_BLOCK to arrayOf(RobotColors.BLOCK_COMMENT), - VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN), - VARIABLE_END to arrayOf(RobotColors.VARIABLE_END), - ENVIRONMENT_VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN), - ENVIRONMENT_VARIABLE_END to arrayOf(RobotColors.VARIABLE_END), - TESTCASE_NAME to arrayOf(RobotColors.TESTCASE_NAME), - KEYWORD_NAME to arrayOf(RobotColors.KEYWORD_NAME), - HEADER to arrayOf(RobotColors.HEADER), - SETTING to arrayOf(RobotColors.SETTING), - KEYWORD_CALL to arrayOf(RobotColors.KEYWORD_CALL), - CONTROL_FLOW to arrayOf(RobotColors.CONTROL_FLOW), - VARIABLE to arrayOf(RobotColors.VARIABLE), - OPERATOR to arrayOf(RobotColors.OPERATOR), - ARGUMENT to arrayOf(RobotColors.ARGUMENT), - CONTINUATION to arrayOf(RobotColors.CONTINUATION), - ) - } - - override fun getTokenHighlights(tokenType: IElementType?): Array { - if (tokenType in elementTypeMap) { - val result = elementTypeMap[tokenType] - if (result != null) return result - } - return super.getTokenHighlights(tokenType) - } -} - -class RobotCodeEditorHighlighter(highlighter: SyntaxHighlighter?, scheme: EditorColorsScheme) : - LexerEditorHighlighter(highlighter ?: RobotCodeHighlighter(), scheme) { - - override fun createStorage(): DataStorage { - return TextMateLexerDataStorage() - } - -} diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotTextMateHighlightingLexer.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeLexer.kt similarity index 52% rename from intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotTextMateHighlightingLexer.kt rename to intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeLexer.kt index 5345bff0..7507b1e4 100644 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotTextMateHighlightingLexer.kt +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeLexer.kt @@ -1,6 +1,8 @@ package dev.robotcode.robotcode4ij.highlighting +import com.intellij.lexer.LexerBase import com.intellij.openapi.util.registry.Registry +import com.intellij.psi.TokenType import com.intellij.psi.tree.IElementType import dev.robotcode.robotcode4ij.TextMateBundleHolder import dev.robotcode.robotcode4ij.psi.ARGUMENT @@ -10,6 +12,8 @@ import dev.robotcode.robotcode4ij.psi.CONTINUATION import dev.robotcode.robotcode4ij.psi.CONTROL_FLOW import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_BEGIN import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_END +import dev.robotcode.robotcode4ij.psi.EXPRESSION_VARIABLE_BEGIN +import dev.robotcode.robotcode4ij.psi.EXPRESSION_VARIABLE_END import dev.robotcode.robotcode4ij.psi.HEADER import dev.robotcode.robotcode4ij.psi.KEYWORD_CALL import dev.robotcode.robotcode4ij.psi.KEYWORD_NAME @@ -20,22 +24,25 @@ import dev.robotcode.robotcode4ij.psi.TESTCASE_NAME import dev.robotcode.robotcode4ij.psi.VARIABLE import dev.robotcode.robotcode4ij.psi.VARIABLE_BEGIN import dev.robotcode.robotcode4ij.psi.VARIABLE_END -import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateElementType -import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateHighlightingLexer +import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateLexer +import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateScope +import java.util.* +import kotlin.math.min -class RobotTextMateHighlightingLexer : TextMateHighlightingLexer( - TextMateBundleHolder.descriptor, Registry.get("textmate.line.highlighting.limit").asInteger() -) { +class RobotCodeTextMateHighlightingLexer : LexerBase() { companion object { val mapping by lazy { mapOf( "comment.line.robotframework" to COMMENT_LINE, "comment.line.rest.robotframework" to COMMENT_LINE, "comment.block.robotframework" to COMMENT_BLOCK, + "punctuation.definition.variable.begin.robotframework" to VARIABLE_BEGIN, "punctuation.definition.variable.end.robotframework" to VARIABLE_END, "punctuation.definition.envvar.begin.robotframework" to ENVIRONMENT_VARIABLE_BEGIN, "punctuation.definition.envvar.end.robotframework" to ENVIRONMENT_VARIABLE_END, + "punctuation.definition.expression.begin.robotframework" to EXPRESSION_VARIABLE_BEGIN, + "punctuation.definition.expression.end.robotframework" to EXPRESSION_VARIABLE_END, "entity.name.function.testcase.name.robotframework" to TESTCASE_NAME, "entity.name.function.keyword.name.robotframework" to KEYWORD_NAME, @@ -63,16 +70,94 @@ class RobotTextMateHighlightingLexer : TextMateHighlightingLexer( "string.unquoted.argument.robotframework" to ARGUMENT, "keyword.operator.continue.robotframework" to CONTINUATION, + + "punctuation.definition.variable.python.begin.robotframework" to VARIABLE_BEGIN, ) } } + + private val myLexer = + TextMateLexer( + TextMateBundleHolder.descriptor, Registry.get("textmate.line.highlighting.limit").asInteger(), + true + ) + private var currentLineTokens = LinkedList() + private lateinit var buffer: CharSequence + private var endOffset = 0 + private var currentOffset = 0 + private var tokenType: IElementType? = null + private var tokenStart = 0 + private var tokenEnd = 0 + private var restartable = false + + override fun start(buffer: CharSequence, startOffset: Int, endOffset: Int, initialState: Int) { + this.buffer = buffer + this.endOffset = endOffset + this.currentOffset = startOffset + this.endOffset = endOffset + this.currentLineTokens.clear() + this.restartable = initialState == 0 + myLexer.init(buffer, startOffset) + this.advance() + } + + override fun getState(): Int { + return if (restartable) 0 else 1 + } + override fun getTokenType(): IElementType? { - val result = super.getTokenType() ?: return null - if (result is TextMateElementType) { - return mapping[result.scope.scopeName] ?: RobotTextMateElementType(result) + return tokenType + } + + override fun getTokenStart(): Int { + return tokenStart + } + + override fun getTokenEnd(): Int { + return tokenEnd + } + + override fun advance() { + if (this.currentOffset >= this.endOffset) { + this.updateState(null as TextMateLexer.Token?, this.endOffset) + } else { + if (currentLineTokens.isEmpty()) { + myLexer.advanceLine(this.currentLineTokens) + } + + this.updateState( + currentLineTokens.poll(), + myLexer.currentOffset + ) } - return result + } + + private fun updateState(token: TextMateLexer.Token?, fallbackOffset: Int) { + if (token != null) { + this.tokenType = + (if (token.scope === TextMateScope.WHITESPACE) TokenType.WHITE_SPACE else mapping[token.scope.scopeName] + ?: RobotTextMateElementType.create(token.scope)) + + tokenStart = token.startOffset + tokenEnd = min(token.endOffset.toDouble(), endOffset.toDouble()).toInt() + currentOffset = token.endOffset + restartable = token.restartable + } else { + tokenType = null + tokenStart = fallbackOffset + tokenEnd = fallbackOffset + currentOffset = fallbackOffset + restartable = true + } + } + + override fun getBufferSequence(): CharSequence { + return buffer + } + + override fun getBufferEnd(): Int { + return endOffset } } diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeSyntaxHighlighter.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeSyntaxHighlighter.kt new file mode 100644 index 00000000..a1c47aff --- /dev/null +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/highlighting/RobotCodeSyntaxHighlighter.kt @@ -0,0 +1,109 @@ +package dev.robotcode.robotcode4ij.highlighting + +import com.intellij.lexer.Lexer +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.PlainSyntaxHighlighter +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase +import com.intellij.psi.tree.IElementType +import com.intellij.util.containers.ContainerUtil +import dev.robotcode.robotcode4ij.psi.ARGUMENT +import dev.robotcode.robotcode4ij.psi.COMMENT_BLOCK +import dev.robotcode.robotcode4ij.psi.COMMENT_LINE +import dev.robotcode.robotcode4ij.psi.CONTINUATION +import dev.robotcode.robotcode4ij.psi.CONTROL_FLOW +import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_BEGIN +import dev.robotcode.robotcode4ij.psi.ENVIRONMENT_VARIABLE_END +import dev.robotcode.robotcode4ij.psi.HEADER +import dev.robotcode.robotcode4ij.psi.KEYWORD_CALL +import dev.robotcode.robotcode4ij.psi.KEYWORD_NAME +import dev.robotcode.robotcode4ij.psi.OPERATOR +import dev.robotcode.robotcode4ij.psi.RobotTextMateElementType +import dev.robotcode.robotcode4ij.psi.SETTING +import dev.robotcode.robotcode4ij.psi.TESTCASE_NAME +import dev.robotcode.robotcode4ij.psi.VARIABLE +import dev.robotcode.robotcode4ij.psi.VARIABLE_BEGIN +import dev.robotcode.robotcode4ij.psi.VARIABLE_END +import org.jetbrains.plugins.textmate.TextMateService +import org.jetbrains.plugins.textmate.language.TextMateScopeComparator +import org.jetbrains.plugins.textmate.language.syntax.highlighting.TextMateTheme +import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateScope +import java.util.function.Function + + +class RobotCodeHighlighter : SyntaxHighlighterBase() { + companion object { + val elementTypeMap = mapOf( + COMMENT_LINE to arrayOf(RobotColors.LINE_COMMENT), + COMMENT_BLOCK to arrayOf(RobotColors.BLOCK_COMMENT), + VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN), + VARIABLE_END to arrayOf(RobotColors.VARIABLE_END), + ENVIRONMENT_VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN), + ENVIRONMENT_VARIABLE_END to arrayOf(RobotColors.VARIABLE_END), + TESTCASE_NAME to arrayOf(RobotColors.TESTCASE_NAME), + KEYWORD_NAME to arrayOf(RobotColors.KEYWORD_NAME), + HEADER to arrayOf(RobotColors.HEADER), + SETTING to arrayOf(RobotColors.SETTING), + KEYWORD_CALL to arrayOf(RobotColors.KEYWORD_CALL), + CONTROL_FLOW to arrayOf(RobotColors.CONTROL_FLOW), + VARIABLE to arrayOf(RobotColors.VARIABLE), + OPERATOR to arrayOf(RobotColors.OPERATOR), + ARGUMENT to arrayOf(RobotColors.ARGUMENT), + CONTINUATION to arrayOf(RobotColors.CONTINUATION), + ) + + val PLAIN_SYNTAX_HIGHLIGHTER: PlainSyntaxHighlighter = PlainSyntaxHighlighter() + } + + private val myLexer = RobotTextMateHighlightingLexer() + + override fun getHighlightingLexer(): Lexer { + return myLexer + } + + override fun getTokenHighlights(tokenType: IElementType?): Array { + val result = elementTypeMap[tokenType] + if (result != null) return result + + if (tokenType !is RobotTextMateElementType) return PLAIN_SYNTAX_HIGHLIGHTER.getTokenHighlights(tokenType) + + val service = TextMateService.getInstance() + val customHighlightingColors = service.customHighlightingColors + + val highlightingRules = ContainerUtil.union(customHighlightingColors.keys, TextMateTheme.INSTANCE.rules) + + val textMateScope = trimEmbeddedScope(tokenType) + val selectors: List = ContainerUtil.reverse( + TextMateScopeComparator(textMateScope, Function.identity()) + .sortAndFilter(highlightingRules) + ) + val result1 = ContainerUtil.map2Array( + selectors, + TextAttributesKey::class.java + ) { rule: CharSequence -> + val customTextAttributes = customHighlightingColors[rule] + customTextAttributes?.getTextAttributesKey(TextMateTheme.INSTANCE) + ?: TextMateTheme.INSTANCE.getTextAttributesKey(rule) + } + + return result1 + } + + private fun trimEmbeddedScope(tokenType: RobotTextMateElementType): TextMateScope { + var current: TextMateScope? = tokenType.scope + val trail: MutableList = ArrayList() + while (current != null) { + val scopeName = current.scopeName + if (scopeName != null && scopeName.contains(".embedded.")) { + var result = TextMateScope.EMPTY + for (i in trail.indices.reversed()) { + result = result.add(trail[i]) + } + return result + } + trail.add(scopeName) + current = current.parent + } + return tokenType.scope + } +} + diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py index 23c4c2ba..9b849232 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py @@ -32,6 +32,7 @@ ResourceImport, Statement, Template, + TemplateArguments, TestTemplate, Variable, VariablesImport, @@ -163,8 +164,6 @@ def __init__(self, parent: "RobotLanguageServerProtocol") -> None: parent.semantic_tokens.token_modifiers += list(RobotSemTokenModifiers) parent.semantic_tokens.collect_full.add(self.collect_full) - # parent.semantic_tokens.collect_range.add(self.collect_range) - # parent.semantic_tokens.collect_full_delta.add(self.collect_full_delta) self.parent.on_initialized.add(self._on_initialized) @@ -345,9 +344,8 @@ def mapping(cls) -> Dict[str, Tuple[Enum, Optional[Set[Enum]]]]: BUILTIN_MATCHER: ClassVar = KeywordMatcher("BuiltIn", is_namespace=True) - @classmethod def generate_sem_sub_tokens( - cls, + self, namespace: Namespace, builtin_library_doc: Optional[LibraryDoc], token: Token, @@ -356,7 +354,8 @@ def generate_sem_sub_tokens( length: Optional[int] = None, yield_arguments: bool = False, ) -> Iterator[SemTokenInfo]: - sem_info = cls.mapping().get(token.type, None) if token.type is not None else None + + sem_info = self.mapping().get(token.type, None) if token.type is not None else None if sem_info is not None: sem_type, sem_mod = sem_info @@ -419,7 +418,7 @@ def generate_sem_sub_tokens( bdd_len = 0 if get_robot_version() < (6, 0): - bdd_match = cls.BDD_TOKEN_REGEX.match(token.value) + bdd_match = self.BDD_TOKEN_REGEX.match(token.value) if bdd_match: bdd_len = len(bdd_match.group(1)) else: @@ -489,7 +488,7 @@ def generate_sem_sub_tokens( col_offset, len(kw_namespace), RobotSemTokenTypes.NAMESPACE, - {RobotSemTokenModifiers.BUILTIN} if kw_namespace == cls.BUILTIN_MATCHER else None, + {RobotSemTokenModifiers.BUILTIN} if kw_namespace == self.BUILTIN_MATCHER else None, ) yield SemTokenInfo( token.lineno, @@ -499,7 +498,11 @@ def generate_sem_sub_tokens( ) if builtin_library_doc is not None and kw in builtin_library_doc.keywords: - if kw_doc is not None and kw_doc.libname == cls.BUILTIN_MATCHER and kw_doc.matcher.match_string(kw): + if ( + kw_doc is not None + and kw_doc.libname == self.BUILTIN_MATCHER + and kw_doc.matcher.match_string(kw) + ): if not sem_mod: sem_mod = set() sem_mod.add(RobotSemTokenModifiers.BUILTIN) @@ -534,9 +537,7 @@ def generate_sem_sub_tokens( ignore_errors=True, identifiers="$@&%", ): - for e in cls.generate_sem_sub_tokens( - namespace, builtin_library_doc, sub_token, node, yield_arguments=True - ): + for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, sub_token, node): e.sem_modifiers = {RobotSemTokenModifiers.EMBEDDED} yield e @@ -558,7 +559,7 @@ def generate_sem_sub_tokens( if col_offset is None: col_offset = token.col_offset - for g in cls.ESCAPE_REGEX.finditer(token.value): + for g in self.ESCAPE_REGEX.finditer(token.value): yield SemTokenInfo.from_token( token, RobotSemTokenTypes.NAMESPACE if g.group("x") is None else RobotSemTokenTypes.ESCAPE, @@ -626,6 +627,7 @@ def generate_sem_sub_tokens( if ( yield_arguments or token.type != Token.ARGUMENT + or (token.type == Token.ARGUMENT and cached_isinstance(node, TemplateArguments)) or (token.type != Token.NAME and cached_isinstance(node, Metadata)) ): yield SemTokenInfo.from_token(token, sem_type, sem_mod, col_offset, length) @@ -699,13 +701,11 @@ def generate_sem_tokens( ignore_errors=True, identifiers="$" if token.type == Token.KEYWORD_NAME else "$@&%", ): - for e in self.generate_sem_sub_tokens( - namespace, builtin_library_doc, sub_token, node, yield_arguments=True - ): + for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, sub_token, node): yield e else: - for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, token, node, yield_arguments=True): + for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, token, node): yield e def generate_run_kw_tokens( diff --git a/syntaxes/robotframework-repl.tmLanguage.json b/syntaxes/robotframework-repl.tmLanguage.json index 2e442c55..5bf8d5a7 100644 --- a/syntaxes/robotframework-repl.tmLanguage.json +++ b/syntaxes/robotframework-repl.tmLanguage.json @@ -35,14 +35,15 @@ }, "variables": { "patterns": [ + { "include": "#expression_var" }, { "include": "#simple_var" }, { "include": "#env_var" } ] }, "expression_var": { - "name": "meta.variables.robotframework", - "begin": "\\{", - "end": "\\}", + "name": "meta.variables.expression.robotframework", + "begin": "[$@&]\\{\\{", + "end": "\\}\\}", "beginCaptures": { "0": { "name": "punctuation.definition.expression.begin.robotframework" } }, "endCaptures": { "0": { "name": "punctuation.definition.expression.end.robotframework" } }, "patterns": [ @@ -50,13 +51,26 @@ { "include": "#simple_var" } ] }, - "only_dollar_var": { - "name": "meta.variables.robotframework", - "contentName": "variable.name.readwrite.robotframework", + "embedded_argument": { + "name": "meta.embedded_argument.robotframework", "begin": "[$]\\{", "end": "(\\})|(?= {2}| ?\\t| ?$)", "beginCaptures": { "0": { "name": "punctuation.definition.variable.begin.robotframework" } }, - "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } } + "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } }, + "patterns": [ { "include": "#embedded_argument_key_pair" } ] + }, + "embedded_argument_key_pair": { + "begin": "([^=:}]*)(:)?", + "end": "(?=\\}| {2}| ?\\t| ?$)", + "contentName": "string.unquoted.argument.robotframework", + "beginCaptures": { + "1": { + "name": "variable.name.readwrite.robotframework", + "patterns": [ { "include": "#variables" } ] + }, + "2": { "name": "keyword.operator.robotframework" } + }, + "patterns": [ { "include": "#variables" } ] }, "simple_var": { "name": "meta.variables.robotframework", @@ -76,9 +90,9 @@ "patterns": [ { "include": "#env_key_value_pair" } ] }, "env_key_value_pair": { - "begin": "([^=\\}]*)(=)?", + "begin": "([^=\\=]*)(=)?", "end": "(?=\\}| {2}| ?\\t| ?$)", - "contentName": "constant.character.robotframework", + "contentName": "string.unquoted.argument.robotframework", "beginCaptures": { "1": { "name": "variable.name.readwrite.robotframework", @@ -169,13 +183,12 @@ "3": { "name": "punctuation.definition.italic.markdown" } } }, - "testcase_name": { + "testcase_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.testcase.name.robotframework", - "patterns": [ { "include": "#variables" } ] + "patterns": [ { "include": "#testcase_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -187,13 +200,20 @@ { "include": "#line_continuation" } ] }, - "keyword_name": { + "testcase_name": { + "contentName": "entity.name.function.testcase.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#variables" } + ] + }, + "keyword_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.keyword.name.robotframework", - "patterns": [ { "include": "#only_dollar_var" } ] + "patterns": [ { "include": "#keyword_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -205,6 +225,14 @@ { "include": "#line_continuation" } ] }, + "keyword_name": { + "contentName": "entity.name.function.keyword.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#embedded_argument" } + ] + }, "block_statements": { "patterns": [ { "include": "#returning_keyword_call" }, @@ -221,7 +249,7 @@ "beginCaptures": { "1": { "name": "keyword.other.header.testcase.robotframework" } }, "end": "^(?=\\*)", "patterns": [ - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -231,7 +259,7 @@ "beginCaptures": { "1": { "name": "keyword.other.header.task.robotframework" } }, "end": "^(?=\\*)", "patterns": [ - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -241,7 +269,7 @@ "beginCaptures": { "1": { "name": "keyword.other.header.keyword.robotframework" } }, "end": "^(?=\\*)", "patterns": [ - { "include": "#keyword_name" }, + { "include": "#keyword_name_def" }, { "include": "#block_statements" } ] }, @@ -353,7 +381,6 @@ "beginCaptures": { "1": { "name": "keyword.control.flow.robotframework" }, "5": { - "name": "meta.python-expression.robotframework", "patterns": [ { "include": "#expression" } ] } }, @@ -1142,7 +1169,7 @@ "robot-expression-variable": { "match": "(\\$)([[:alpha:]_]\\w*)", "captures": { - "1": { "name": "punctuation.definition.variable.begin.robotframework" }, + "1": { "name": "punctuation.definition.variable.python.begin.robotframework" }, "2": { "name": "variable.name.readwrite.robotframework" } } }, diff --git a/syntaxes/robotframework.tmLanguage.json b/syntaxes/robotframework.tmLanguage.json index d99a203b..2afdd417 100644 --- a/syntaxes/robotframework.tmLanguage.json +++ b/syntaxes/robotframework.tmLanguage.json @@ -35,14 +35,15 @@ }, "variables": { "patterns": [ + { "include": "#expression_var" }, { "include": "#simple_var" }, { "include": "#env_var" } ] }, "expression_var": { - "name": "meta.variables.robotframework", - "begin": "\\{", - "end": "\\}", + "name": "meta.variables.expression.robotframework", + "begin": "[$@&]\\{\\{", + "end": "\\}\\}", "beginCaptures": { "0": { "name": "punctuation.definition.expression.begin.robotframework" } }, "endCaptures": { "0": { "name": "punctuation.definition.expression.end.robotframework" } }, "patterns": [ @@ -50,13 +51,26 @@ { "include": "#simple_var" } ] }, - "only_dollar_var": { - "name": "meta.variables.robotframework", - "contentName": "variable.name.readwrite.robotframework", + "embedded_argument": { + "name": "meta.embedded_argument.robotframework", "begin": "[$]\\{", "end": "(\\})|(?= {2}| ?\\t| ?$)", "beginCaptures": { "0": { "name": "punctuation.definition.variable.begin.robotframework" } }, - "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } } + "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } }, + "patterns": [ { "include": "#embedded_argument_key_pair" } ] + }, + "embedded_argument_key_pair": { + "begin": "([^=:}]*)(:)?", + "end": "(?=\\}| {2}| ?\\t| ?$)", + "contentName": "string.unquoted.argument.robotframework", + "beginCaptures": { + "1": { + "name": "variable.name.readwrite.robotframework", + "patterns": [ { "include": "#variables" } ] + }, + "2": { "name": "keyword.operator.robotframework" } + }, + "patterns": [ { "include": "#variables" } ] }, "simple_var": { "name": "meta.variables.robotframework", @@ -76,9 +90,9 @@ "patterns": [ { "include": "#env_key_value_pair" } ] }, "env_key_value_pair": { - "begin": "([^=\\}]*)(=)?", + "begin": "([^=\\=]*)(=)?", "end": "(?=\\}| {2}| ?\\t| ?$)", - "contentName": "constant.character.robotframework", + "contentName": "string.unquoted.argument.robotframework", "beginCaptures": { "1": { "name": "variable.name.readwrite.robotframework", @@ -169,13 +183,12 @@ "3": { "name": "punctuation.definition.italic.markdown" } } }, - "testcase_name": { + "testcase_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.testcase.name.robotframework", - "patterns": [ { "include": "#variables" } ] + "patterns": [ { "include": "#testcase_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -187,13 +200,20 @@ { "include": "#line_continuation" } ] }, - "keyword_name": { + "testcase_name": { + "contentName": "entity.name.function.testcase.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#variables" } + ] + }, + "keyword_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.keyword.name.robotframework", - "patterns": [ { "include": "#only_dollar_var" } ] + "patterns": [ { "include": "#keyword_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -205,6 +225,14 @@ { "include": "#line_continuation" } ] }, + "keyword_name": { + "contentName": "entity.name.function.keyword.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#embedded_argument" } + ] + }, "block_statements": { "patterns": [ { "include": "#testcase_settings" }, @@ -222,7 +250,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -233,7 +261,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -244,7 +272,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#keyword_name" }, + { "include": "#keyword_name_def" }, { "include": "#block_statements" } ] }, @@ -356,7 +384,6 @@ "beginCaptures": { "1": { "name": "keyword.control.flow.robotframework" }, "5": { - "name": "meta.python-expression.robotframework", "patterns": [ { "include": "#expression" } ] } }, @@ -1155,7 +1182,7 @@ "robot-expression-variable": { "match": "(\\$)([[:alpha:]_]\\w*)", "captures": { - "1": { "name": "punctuation.definition.variable.begin.robotframework" }, + "1": { "name": "punctuation.definition.variable.python.begin.robotframework" }, "2": { "name": "variable.name.readwrite.robotframework" } } }, diff --git a/syntaxes/robotframework.tmLanguage.template.json b/syntaxes/robotframework.tmLanguage.template.json index 587c019b..e536e0b3 100644 --- a/syntaxes/robotframework.tmLanguage.template.json +++ b/syntaxes/robotframework.tmLanguage.template.json @@ -35,14 +35,15 @@ }, "variables": { "patterns": [ + { "include": "#expression_var" }, { "include": "#simple_var" }, { "include": "#env_var" } ] }, "expression_var": { - "name": "meta.variables.robotframework", - "begin": "\\{", - "end": "\\}", + "name": "meta.variables.expression.robotframework", + "begin": "[$@&]\\{\\{", + "end": "\\}\\}", "beginCaptures": { "0": { "name": "punctuation.definition.expression.begin.robotframework" } }, "endCaptures": { "0": { "name": "punctuation.definition.expression.end.robotframework" } }, "patterns": [ @@ -50,13 +51,26 @@ { "include": "#simple_var" } ] }, - "only_dollar_var": { - "name": "meta.variables.robotframework", - "contentName": "variable.name.readwrite.robotframework", + "embedded_argument": { + "name": "meta.embedded_argument.robotframework", "begin": "[$]\\{", "end": "(\\})|(?= {2}| ?\\t| ?$)", "beginCaptures": { "0": { "name": "punctuation.definition.variable.begin.robotframework" } }, - "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } } + "endCaptures": { "1": { "name": "punctuation.definition.variable.end.robotframework" } }, + "patterns": [ { "include": "#embedded_argument_key_pair" } ] + }, + "embedded_argument_key_pair": { + "begin": "([^=:}]*)(:)?", + "end": "(?=\\}| {2}| ?\\t| ?$)", + "contentName": "string.unquoted.argument.robotframework", + "beginCaptures": { + "1": { + "name": "variable.name.readwrite.robotframework", + "patterns": [ { "include": "#variables" } ] + }, + "2": { "name": "keyword.operator.robotframework" } + }, + "patterns": [ { "include": "#variables" } ] }, "simple_var": { "name": "meta.variables.robotframework", @@ -76,9 +90,9 @@ "patterns": [ { "include": "#env_key_value_pair" } ] }, "env_key_value_pair": { - "begin": "([^=\\}]*)(=)?", + "begin": "([^=\\=]*)(=)?", "end": "(?=\\}| {2}| ?\\t| ?$)", - "contentName": "constant.character.robotframework", + "contentName": "string.unquoted.argument.robotframework", "beginCaptures": { "1": { "name": "variable.name.readwrite.robotframework", @@ -169,13 +183,12 @@ "3": { "name": "punctuation.definition.italic.markdown" } } }, - "testcase_name": { + "testcase_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.testcase.name.robotframework", - "patterns": [ { "include": "#variables" } ] + "patterns": [ { "include": "#testcase_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -187,13 +200,20 @@ { "include": "#line_continuation" } ] }, - "keyword_name": { + "testcase_name": { + "contentName": "entity.name.function.testcase.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#variables" } + ] + }, + "keyword_name_def": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", "beginCaptures": { "1": { - "name": "entity.name.function.keyword.name.robotframework", - "patterns": [ { "include": "#only_dollar_var" } ] + "patterns": [ { "include": "#keyword_name" } ] } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -205,6 +225,14 @@ { "include": "#line_continuation" } ] }, + "keyword_name": { + "contentName": "entity.name.function.keyword.name.robotframework", + "begin": "", + "while": ".", + "patterns": [ + { "include": "#embedded_argument" } + ] + }, "block_statements": { "patterns": [ { "include": "#testcase_settings" }, @@ -222,7 +250,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -233,7 +261,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#testcase_name" }, + { "include": "#testcase_name_def" }, { "include": "#block_statements" } ] }, @@ -244,7 +272,7 @@ "end": "^(?=\\*)", "patterns": [ { "include": "#comment_line" }, - { "include": "#keyword_name" }, + { "include": "#keyword_name_def" }, { "include": "#block_statements" } ] }, @@ -356,7 +384,6 @@ "beginCaptures": { "1": { "name": "keyword.control.flow.robotframework" }, "5": { - "name": "meta.python-expression.robotframework", "patterns": [ { "include": "#expression" } ] } }, @@ -1155,7 +1182,7 @@ "robot-expression-variable": { "match": "(\\$)([[:alpha:]_]\\w*)", "captures": { - "1": { "name": "punctuation.definition.variable.begin.robotframework" }, + "1": { "name": "punctuation.definition.variable.python.begin.robotframework" }, "2": { "name": "variable.name.readwrite.robotframework" } } },