diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index bdc2e476c..56c1e2a9c 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -7,6 +7,7 @@ - Increase the required version of VS Code to 1.82.0. [#2877](https://github.com/github/vscode-codeql/pull/2877) - Fix a bug where the query server was restarted twice after configuration changes. [#2884](https://github.com/github/vscode-codeql/pull/2884). - Add support for the `telemetry.telemetryLevel` setting. For more information, see the [telemetry documentation](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-telemetry-in-codeql-for-visual-studio-code). [#2824](https://github.com/github/vscode-codeql/pull/2824). +- Fix syntax highlighting directly after import statements with instantiation arguments. [#2792](https://github.com/github/vscode-codeql/pull/2792) ## 1.9.1 - 29 September 2023 diff --git a/extensions/ql-vscode/syntaxes/ql.tmLanguage.yml b/extensions/ql-vscode/syntaxes/ql.tmLanguage.yml index d7f8ac071..fe10a86d0 100644 --- a/extensions/ql-vscode/syntaxes/ql.tmLanguage.yml +++ b/extensions/ql-vscode/syntaxes/ql.tmLanguage.yml @@ -170,6 +170,14 @@ repository: match: '\]' name: punctuation.squarebracket.close.ql + open-angle: + match: '<' + name: punctuation.anglebracket.open.ql + + close-angle: + match: '>' + name: punctuation.anglebracket.close.ql + operator-or-punctuation: patterns: - include: '#relational-operator' @@ -186,6 +194,8 @@ repository: - include: '#close-brace' - include: '#open-bracket' - include: '#close-bracket' + - include: '#open-angle' + - include: '#close-angle' # Keywords dont-care: @@ -651,18 +661,36 @@ repository: - include: '#non-context-sensitive' - include: '#annotation' + # The argument list of an instantiation, enclosed in angle brackets. + instantiation-args: + beginPattern: '#open-angle' + endPattern: '#close-angle' + name: meta.type.parameters.ql + patterns: + # Include `#instantiation-args` first so that `#open-angle` and `#close-angle` take precedence + # over `#relational-operator`. + - include: '#instantiation-args' + - include: '#non-context-sensitive' + - match: '(?#simple-id)' + name: entity.name.type.namespace.ql + # An `import` directive. Note that we parse the optional `as` clause as a separate top-level # directive, because otherwise it's too hard to figure out where the `import` directive ends. import-directive: beginPattern: '#import' - # Ends with a simple-id that is not followed by a `.` or a `::`. This does not handle comments or - # line breaks between the simple-id and the `.` or `::`. - end: '(?#simple-id) (?!\s*(\.|\:\:))' - endCaptures: - '0': - name: entity.name.type.namespace.ql + # TextMate makes it tricky to tell whether an identifier that we encounter is part of the + # `import` directive or whether it's the first token of the next module-level declaration. + # To find the end of the import directive, we'll look for a zero-width match where the previous + # token is either an identifier (other than `import`) or a `>`, and the next token is not a `.`, + # `<`, `,`, or `::`. This works for nearly all real-world `import` directives, but it will end the + # `import` directive too early if there is a comment or line break between two components of the + # module expression. + end: '(?)|[A-Za-z0-9_]) (?!\s*(\.|\:\:|\,|(?#open-angle)))' name: meta.block.import-directive.ql patterns: + # Include `#instantiation-args` first so that `#open-angle` and `#close-angle` take precedence + # over `#relational-operator`. + - include: '#instantiation-args' - include: '#non-context-sensitive' - match: '(?#simple-id)' name: entity.name.type.namespace.ql @@ -703,7 +731,6 @@ repository: - match: '(?#simple-id)|(?#at-lower-id)' name: entity.name.type.ql - # A `module` declaration, whether a module definition or an alias declaration. module-declaration: # Starts with the `module` keyword. diff --git a/syntaxes/ql.tmLanguage.json b/syntaxes/ql.tmLanguage.json index 66e1cc8ec..a8b5c3909 100644 --- a/syntaxes/ql.tmLanguage.json +++ b/syntaxes/ql.tmLanguage.json @@ -108,6 +108,14 @@ "match": "(?x)\\]", "name": "punctuation.squarebracket.close.ql" }, + "open-angle": { + "match": "(?x)<", + "name": "punctuation.anglebracket.open.ql" + }, + "close-angle": { + "match": "(?x)>", + "name": "punctuation.anglebracket.close.ql" + }, "operator-or-punctuation": { "patterns": [ { @@ -151,6 +159,12 @@ }, { "include": "#close-bracket" + }, + { + "include": "#open-angle" + }, + { + "include": "#close-angle" } ] }, @@ -661,9 +675,9 @@ "begin": "(?x)(?<=/\\*\\*)([^*]|\\*(?!/))*$", "while": "(?x)(^|\\G)\\s*([^*]|\\*(?!/))(?=([^*]|[*](?!/))*$)", "patterns": [ - - - + + + { "match": "(?x)\\G\\s* (@\\S+)", "name": "keyword.tag.ql" @@ -723,15 +737,48 @@ } ] }, - "import-directive": { - "end": "(?x)(?:\\b [A-Za-z][0-9A-Za-z_]* (?:(?!(?:[0-9A-Za-z_])))) (?!\\s*(\\.|\\:\\:))", - "endCaptures": { - "0": { + "instantiation-args": { + "name": "meta.type.parameters.ql", + "patterns": [ + { + "include": "#instantiation-args" + }, + { + "include": "#non-context-sensitive" + }, + { + "match": "(?x)(?:\\b [A-Za-z][0-9A-Za-z_]* (?:(?!(?:[0-9A-Za-z_]))))", "name": "entity.name.type.namespace.ql" } + ], + "begin": "(?x)((?:<))", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#open-angle" + } + ] + } }, + "end": "(?x)((?:>))", + "endCaptures": { + "1": { + "patterns": [ + { + "include": "#close-angle" + } + ] + } + } + }, + "import-directive": { + "end": "(?x)(?)|[A-Za-z0-9_]) (?!\\s*(\\.|\\:\\:|\\,|(?:<)))", "name": "meta.block.import-directive.ql", "patterns": [ + { + "include": "#instantiation-args" + }, { "include": "#non-context-sensitive" }, @@ -1493,4 +1540,4 @@ "name": "constant.character.escape.ql" } } -} \ No newline at end of file +}