From 0d3d7fc0d633fd05b658f1faebfb04c7c6a3b5fd Mon Sep 17 00:00:00 2001 From: Ben Cho Date: Mon, 8 Jul 2024 15:45:33 +0900 Subject: [PATCH] Syntax: Update QML syntax definiton Update grammar and language configuration file to support more cases like, * attached signal handler * group notation of grouped properties * type annotation on function parameters and return value * inline component syntax * pragma statement other than Signleton * QML type with prefix from qualified import (e.g. T.Button {}) * JS template string * addtional auto closing pairs. etc Task-number: VSCODEEXT-13 Change-Id: If7f05f9a436a55e5002e0ccfc6bd7bf06614efbc Reviewed-by: Marcus Tillmanns --- package.json | 2 +- res/lang/qml/language-configuration.json | 10 +- res/lang/qml/qml.qmlproject.tmLanguage | 317 --------------- res/lang/qml/qml.qmlproject.tmLanguage.json | 415 ++++++++++++++++++++ 4 files changed, 424 insertions(+), 320 deletions(-) delete mode 100644 res/lang/qml/qml.qmlproject.tmLanguage create mode 100644 res/lang/qml/qml.qmlproject.tmLanguage.json diff --git a/package.json b/package.json index f74389e..2053dc5 100644 --- a/package.json +++ b/package.json @@ -350,7 +350,7 @@ { "language": "qml", "scopeName": "source.qml", - "path": "./res/lang/qml/qml.qmlproject.tmLanguage" + "path": "./res/lang/qml/qml.qmlproject.tmLanguage.json" }, { "language": "qmldir", diff --git a/res/lang/qml/language-configuration.json b/res/lang/qml/language-configuration.json index b155bf5..88824e7 100644 --- a/res/lang/qml/language-configuration.json +++ b/res/lang/qml/language-configuration.json @@ -13,13 +13,19 @@ ["[", "]"], ["(", ")"], ["\"", "\""], - ["'", "'"] + ["'", "'"], + ["`", "`"], + ["/*", "*/"], + ["/**", "*/"], + ["/*!", "*/"] ], "surroundingPairs": [ ["{", "}"], ["[", "]"], ["(", ")"], + ["<", ">"], ["\"", "\""], - ["'", "'"] + ["'", "'"], + ["`", "`"] ] } diff --git a/res/lang/qml/qml.qmlproject.tmLanguage b/res/lang/qml/qml.qmlproject.tmLanguage deleted file mode 100644 index 509929e..0000000 --- a/res/lang/qml/qml.qmlproject.tmLanguage +++ /dev/null @@ -1,317 +0,0 @@ - - - - - fileTypes - - qml - qmlproject - - name - QML - patterns - - - begin - /\*(?!/) - comment - Block comment. - end - \*/ - name - comment.block.documentation.qml - - - comment - Line comment. - match - //.*$ - name - comment.line.double-slash.qml - - - begin - \b(import)\s+ - beginCaptures - - 1 - - name - keyword.other.import.qml - - - comment - import statement. - end - $ - name - meta.import.qml - patterns - - - captures - - 1 - - name - entity.name.class.qml - - 2 - - name - constant.numeric.qml - - 3 - - name - keyword.other.import.qml - - 4 - - name - entity.name.class.qml - - - comment - import Namespace VersionMajor.VersionMinor [as SingletonTypeIdentifier] - match - ([\w\d\.]+)\s+(\d+\.\d+)(?:\s+(as)\s+([A-Z][\w\d]*))? - name - meta.import.namespace.qml - - - captures - - 1 - - name - string.quoted.double.qml - - 2 - - name - keyword.other.import.qml - - 3 - - name - entity.name.class.qml - - - comment - import <string> [as Script] - match - (\"[^\"]+\")(?:\s+(as)\s+([A-Z][\w\d]*))? - name - meta.import.dirjs.qml - - - - - comment - Capitalized word (class or enum). - match - \b[A-Z]\w*\b - name - support.class.qml - - - comment - onSomething - handler. - match - (((^|\{)\s*)|\b)on[A-Z]\w*\b - name - support.class.qml - - - captures - - 1 - - name - keyword.other.qml - - 2 - - name - storage.modifier.qml - - - comment - id: <something> - match - (?:^|\{)\s*(id)\s*\:\s*([^;\s]+)\b - name - meta.id.qml - - - captures - - 1 - - name - keyword.other.qml - - 2 - - name - keyword.other.qml - - 3 - - name - keyword.other.qml - - 4 - - name - storage.type.qml - - 5 - - name - entity.other.attribute-name.qml - - - comment - property definition. - match - ^\s*(?:(default|readonly)\s+)?(property)\s+(?:(alias)|([\w\<\>]+))\s+(\w+) - name - meta.propertydef.qml - - - begin - \b(signal)\s+(\w+)\s* - beginCaptures - - 1 - - name - keyword.other.qml - - 2 - - name - support.function.qml - - - comment - signal <signalName>[([<type> <parameter>[, ...]])] - end - ;|(?=/)|$ - name - meta.signal.qml - patterns - - - captures - - 1 - - name - storage.type.qml - - 2 - - name - variable.parameter.qml - - - match - (\w+)\s+(\w+) - name - meta.signal.parameters.qml - - - - - captures - - 1 - - name - constant.language.qml - - 2 - - name - storage.type.qml - - 3 - - name - keyword.control.qml - - - comment - js keywords. - match - (?:\b|\s+)(?:(true|false|null|undefined)|(var|void)|(on|as|enum|connect|break|case|catch|continue|debugger|default|delete|do|else|finally|for|if|in|instanceof|new|return|switch|this|throw|try|typeof|while|with))\b - name - meta.keyword.qml - - - captures - - 1 - - name - storage.type.qml - - 2 - - name - entity.name.function.untitled - - - comment - function definition. - match - \b(function)\s+([\w_]+)\s*(?=\() - name - meta.function.qml - - - comment - function call. - match - \b[\w_]+\s*(?=\() - name - support.function.qml - - - comment - property (property: <something>). - match - (?:^|\{|;)\s*[a-z][\w\.]*\s*(?=\:) - name - entity.other.attribute-name.qml - - - comment - property of the variable (name.property). - match - (?<=\.)\b\w* - name - entity.other.attribute-name.qml - - - comment - All non-colored words are assumed to be variables. - match - \b([a-z_]\w*)\b - name - variable.parameter - - - include - source.js - - - scopeName - source.qml - uuid - 13a281e0-0507-45b4-bb6c-a57177630f10 - - diff --git a/res/lang/qml/qml.qmlproject.tmLanguage.json b/res/lang/qml/qml.qmlproject.tmLanguage.json new file mode 100644 index 0000000..8f90012 --- /dev/null +++ b/res/lang/qml/qml.qmlproject.tmLanguage.json @@ -0,0 +1,415 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "qml", + "scopeName": "source.qml", + "patterns": [ + { + "include": "#pragma" + }, + { + "include": "#import" + }, + { + "include": "#object" + }, + { + "include": "#comment" + } + ], + "repository": { + "pragma": { + "begin": "\\b(pragma)\\s+([A-Z]\\w*)(\\s*:\\s*[a-zA-Z]+)?\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.pragma.qml" + }, + "2": { + "name": "variable.parameter.pragma.qml" + }, + "3": { + "name": "entity.name.pragma.qml" + } + }, + "end": "$", + "patterns": [ + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "import": { + "begin": "\\b(import)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.import.qml" + } + }, + "end": "$", + "patterns": [ + { + "match": "\\b([A-Z][\\w\\.]*)\\s+(\\d+\\.\\d+)?", + "captures": { + "1": { + "name": "entity.name.section.import.module.qml" + }, + "2": { + "name": "constant.numeric.import.version.qml" + } + } + }, + { + "match": "\\b(as)\\s+([A-Z]\\w*)", + "captures": { + "1": { + "name": "keyword.control.import.as.qml" + }, + "2": { + "name": "entity.name.type.import.type.qml" + } + } + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "object": { + "begin": "\\b([A-Z][\\w\\.]*)\\s*(\\{|$)", + "beginCaptures": { + "1": { + "name": "entity.name.type.object.qml" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "$self" + }, + { + "include": "#signal" + }, + { + "include": "#prop-custom" + }, + { + "include": "#prop-force-required" + }, + { + "include": "#method" + }, + { + "include": "#on-prop" + }, + { + "include": "#comp-inline" + }, + { + "include": "#attr-general" + }, + { + "include": "#attr-group-notation" + }, + { + "name": "keyword.ohter.enum.qml", + "match": "\\b(enum)\\b" + } + ] + }, + "signal": { + "patterns": [ + { + "begin": "\\b(signal)\\s*([_a-zA-Z]\\w*)\\s*\\(", + "beginCaptures": { + "1": { + "name": "storage.type.signal.qml" + }, + "2": { + "name": "entity.name.function.signal.name.qml" + } + }, + "end": "\\)", + "patterns": [ + { + "match": "(\\w+)\\s*:\\s*(\\w+)\\s*,?", + "captures": { + "1": { + "name": "variable.parameter.signal.param-name.qml" + }, + "2": { + "name": "entity.name.type.signal.param-type.qml" + } + } + }, + { + "match": "(\\w+)\\s+(\\w+)\\s*,?", + "captures": { + "1": { + "name": "entity.name.type.signal.param-type.qml" + }, + "2": { + "name": "variable.parameter.signal.param-name.qml" + } + } + } + ] + }, + { + "match": "\\b(signal)\\s*([_a-zA-Z]\\w*)\\s*", + "captures": { + "1": { + "name": "storage.type.signal.qml" + }, + "2": { + "name": "entity.name.function.signal.name.qml" + } + } + } + ] + }, + "prop-custom": { + "patterns": [ + { + "name": "storage.modifier.prop-custom.qml", + "match": "\\b(default|readonly|required)\\s+(?=property)" + }, + { + "match": "\\b(property)\\s+([\\w<>]+)(?=\\s+\\w+\\s*:)", + "captures": { + "1": { + "name": "keyword.other.prop-custom.qml" + }, + "2": { + "name": "storage.type.prop-custom.type.qml" + } + } + }, + { + "match": "\\b(property)\\s+([\\w<>]+)\\s+(\\w+)\\s*$", + "captures": { + "1": { + "name": "keyword.other.prop-custom.qml" + }, + "2": { + "name": "storage.type.prop-custom.type.qml" + }, + "3": { + "name": "variable.parameter.prop-custom.name.qml" + } + } + } + ] + }, + "prop-force-required": { + "match": "\\b(required)\\s+(\\w+)\\s*", + "captures": { + "1": { + "name": "storage.modifier.prop-force-required.qml" + }, + "2": { + "name": "variable.parameter.prop-force-required.name.qml" + } + } + }, + "method": { + "begin": "\\b(?=function)\\b", + "end": "(?<=\\})", + "patterns": [ + { + "include": "source.js" + } + ] + }, + "on-prop": { + "begin": "\\b([A-Z]\\w*)\\s+(on)\\s+(\\w+)\\s*{", + "beginCaptures": { + "1": { + "name": "entity.name.type.on-prop.qml" + }, + "2": { + "name": "keyword.control.on-prop.on.qml" + }, + "3": { + "name": "variable.parameter.on-prop.prop.qml" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#object" + }, + { + "include": "#attr-general" + } + ] + }, + "comp-inline": { + "begin": "\\b(component)\\s+([A-Z]\\w*)\\s*:", + "beginCaptures": { + "1": { + "name": "keyword.other.comp-inline.qml" + }, + "2": { + "name": "entity.name.type.comp-line.name.qml" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#object" + } + ] + }, + "attr-group-notation": { + "begin": "\\b(\\w*)\\s*\\{", + "beginCaptures": { + "1": { + "name": "variable.parameter.attr-group-notation.qml" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#attr-general" + }, + { + "include": "#comment" + } + ] + }, + "attr-general": { + "patterns": [ + { + "include": "#attr-object" + }, + { + "include": "#attr-list" + }, + { + "include": "#attr-block" + }, + { + "include": "#attr-expr" + } + ], + "repository": { + "attr-object": { + "begin": "\\b([\\w\\.]*)\\s*:\\s*(?=[A-Z]\\w*\\s*\\{)", + "beginCaptures": { + "1": { + "name": "variable.parameter.attr-object.qml" + } + }, + "end": "(?=\\})", + "patterns": [ + { + "include": "#object" + } + ] + }, + "attr-list": { + "begin": "\\b([\\w\\.]*)\\s*:\\s*\\[\\s*", + "beginCaptures": { + "1": { + "name": "variable.parameter.attr-list.qml" + } + }, + "end": "\\]", + "patterns": [ + { + "include": "#object" + }, + { + "include": "source.js" + } + ] + }, + "attr-block": { + "begin": "\\b([\\w\\.]*)\\s*:\\s*\\{\\s*", + "beginCaptures": { + "1": { + "name": "variable.parameter.attr-block.qml" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "source.js" + } + ] + }, + "attr-expr": { + "begin": "\\b([\\w\\.]*)\\s*:\\s*(?=[^\\s]+)", + "beginCaptures": { + "1": { + "name": "variable.parameter.attr-expr.qml" + } + }, + "end": ";|$", + "patterns": [ + { + "include": "source.js" + } + ] + } + } + }, + "string": { + "patterns": [ + { + "name": "string.quoted.single.qml", + "begin": "'", + "end": "'" + }, + { + "name": "string.quoted.double.qml", + "begin": "\"", + "end": "\"" + } + ] + }, + "comment": { + "patterns": [ + { + "name": "comment.line.qml", + "begin": "(\\/\\/)", + "end": "$", + "patterns": [ + { + "include": "#comment-contents" + } + ] + }, + { + "name": "comment.block.qml", + "begin": "(\\/\\*)", + "end": "(\\*\\/)", + "patterns": [ + { + "include": "#comment-contents" + } + ] + } + ], + "repository": { + "comment-contents": { + "patterns": [ + { + "name": "constant.language.qml", + "match": "\\b(NOTE|TODO|DEBUG|XXX)\\b" + }, + { + "name": "invalid", + "match": "\\b(BUG|FIXME|WARNING)\\b" + } + ] + } + } + } + } +}