From 5806e6e7872e80ac4cd9e6a530492b65991bd4a7 Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Sat, 16 Mar 2024 21:39:08 +0100 Subject: [PATCH 1/8] feat: add support for ember .hbs (glimmer) templates --- book/src/generated/lang-support.md | 1 + languages.toml | 25 +++++++- runtime/queries/glimmer/highlights.scm | 88 ++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/glimmer/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 47f8057e006f..b74a8cdb7cd5 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -60,6 +60,7 @@ | git-ignore | ✓ | | | | | git-rebase | ✓ | | | | | gleam | ✓ | ✓ | | `gleam` | +| glimmer | ✓ | | | `ember-language-server` | | glsl | ✓ | ✓ | ✓ | | | gn | ✓ | | | | | go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` | diff --git a/languages.toml b/languages.toml index ccd546fa7de7..537737069aff 100644 --- a/languages.toml +++ b/languages.toml @@ -100,6 +100,7 @@ blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] } typst-lsp = { command = "typst-lsp" } pkgbuild-language-server = { command = "pkgbuild-language-server" } helm_ls = { command = "helm_ls", args = ["serve"] } +ember-language-server = { command = "ember-language-server", args = ["--stdio"] } [language-server.ansible-language-server] command = "ansible-language-server" @@ -3390,4 +3391,26 @@ scope = "source.helm" roots = ["Chart.yaml"] comment-token = "#" language-servers = ["helm_ls"] -file-types = [ { glob = "templates/*.yaml" }, { glob = "templates/_helpers.tpl"}, { glob = "templates/NOTES.txt" } ] \ No newline at end of file +file-types = [ { glob = "templates/*.yaml" }, { glob = "templates/_helpers.tpl"}, { glob = "templates/NOTES.txt" } ] + +[[language]] +name = "glimmer" +scope = "source.glimmer" +injection-regex = "hbs" +file-types = [{ glob = "{app,addon}/{components,templates}/*.hbs" }] +block-comment-tokens = { start = "{{!", end = "}}" } +roots = ["package.json", "ember-cli-build.js"] +grammar = "glimmer" +language-servers = ["ember-language-server"] +formatter = { command = "prettier", args = ['--parser', 'glimmer'] } + +[language.auto-pairs] +'"' = '"' +'{' = '}' +'(' = ')' +'<' = '>' +"'" = "'" + +[[grammar]] +name = "glimmer" +source = { git = "https://github.com/ember-tooling/tree-sitter-glimmer", rev = "5dc6d1040e8ff8978ff3680e818d85447bbc10aa" } \ No newline at end of file diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm new file mode 100644 index 000000000000..248067073ae7 --- /dev/null +++ b/runtime/queries/glimmer/highlights.scm @@ -0,0 +1,88 @@ +; === Tag Names === + +; Tags that start with a lower case letter are HTML tags +; We'll also use this highlighting for named blocks (which start with `:`) +((tag_name) @tag + (#match? @tag "^(:)?[a-z]")) +; Tags that start with a capital letter are Glimmer components +((tag_name) @constructor + (#match? @constructor "^[A-Z]")) + +(attribute_name) @property + +(string_literal) @string +(number_literal) @number +(boolean_literal) @boolean + +(concat_statement) @string + +; === Block Statements === + +; Highlight the brackets +(block_statement_start) @tag.delimiter +(block_statement_end) @tag.delimiter + +; Highlight `if`/`each`/`let` +(block_statement_start path: (identifier) @conditional) +(block_statement_end path: (identifier) @conditional) +((mustache_statement (identifier) @conditional) + (#match? @conditional "else")) + +; == Mustache Statements === + +; Hightlight the whole statement, to color brackets and separators +(mustache_statement) @tag.delimiter + +; An identifier in a mustache expression is a variable +((mustache_statement [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) + (#not-match? @variable "yield|outlet|this|else")) +; As are arguments in a block statement +(block_statement_start argument: [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) +; As is an identifier in a block param +(block_params (identifier) @variable) +; As are helper arguments +((helper_invocation argument: [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) + (#not-match? @variable "this")) +; `this` should be highlighted as a built-in variable +((identifier) @variable.builtin + (#match? @variable.builtin "this")) + +; If the identifier is just "yield" or "outlet", it's a keyword +((mustache_statement (identifier) @keyword) + (#match? @keyword "yield|outlet")) + +; Helpers are functions +((helper_invocation helper: [ + (path_expression (identifier) @function) + (identifier) @function + ]) + (#not-match? @function "if|yield")) +((helper_invocation helper: (identifier) @conditional) + (#match? @conditional "if")) +((helper_invocation helper: (identifier) @keyword) + (#match? @keyword "yield")) + +(hash_pair key: (identifier) @property) + +(comment_statement) @comment + +(attribute_node "=" @operator) + +(block_params "as" @keyword) +(block_params "|" @operator) + +[ + "<" + ">" + "" +] @tag.delimiter \ No newline at end of file From ab2497b48fd5ebdaed4bc2fef83348be0c926e5a Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Sun, 17 Mar 2024 18:16:07 +0100 Subject: [PATCH 2/8] adjust highlights to helix --- runtime/queries/glimmer/highlights.scm | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index 248067073ae7..453c2f320709 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -8,30 +8,30 @@ ((tag_name) @constructor (#match? @constructor "^[A-Z]")) -(attribute_name) @property +(attribute_name) @variable.other.member (string_literal) @string -(number_literal) @number -(boolean_literal) @boolean +(number_literal) @constant.numeric.integer +(boolean_literal) @constant.builtin.boolean (concat_statement) @string ; === Block Statements === ; Highlight the brackets -(block_statement_start) @tag.delimiter -(block_statement_end) @tag.delimiter +(block_statement_start) @punctuation.delimiter +(block_statement_end) @punctuation.delimiter ; Highlight `if`/`each`/`let` -(block_statement_start path: (identifier) @conditional) -(block_statement_end path: (identifier) @conditional) -((mustache_statement (identifier) @conditional) - (#match? @conditional "else")) +(block_statement_start path: (identifier) @keyword.control.conditional) +(block_statement_end path: (identifier) @keyword.control.conditional) +((mustache_statement (identifier) @keyword.control.conditional) + (#match? @keyword.control.conditional "else")) ; == Mustache Statements === ; Hightlight the whole statement, to color brackets and separators -(mustache_statement) @tag.delimiter +(mustache_statement) @punctuation.delimiter ; An identifier in a mustache expression is a variable ((mustache_statement [ @@ -57,8 +57,8 @@ (#match? @variable.builtin "this")) ; If the identifier is just "yield" or "outlet", it's a keyword -((mustache_statement (identifier) @keyword) - (#match? @keyword "yield|outlet")) +((mustache_statement (identifier) @keyword.control.return) + (#match? @keyword.control.return "yield|outlet")) ; Helpers are functions ((helper_invocation helper: [ @@ -66,18 +66,18 @@ (identifier) @function ]) (#not-match? @function "if|yield")) -((helper_invocation helper: (identifier) @conditional) - (#match? @conditional "if")) -((helper_invocation helper: (identifier) @keyword) - (#match? @keyword "yield")) +((helper_invocation helper: (identifier) @keyword.control.conditional) + (#match? @keyword.control.conditional "if")) +((helper_invocation helper: (identifier) @keyword.control.conditional) + (#match? @keyword.control.conditional "yield")) -(hash_pair key: (identifier) @property) +(hash_pair key: (identifier) @variable.parameter) (comment_statement) @comment (attribute_node "=" @operator) -(block_params "as" @keyword) +(block_params "as" @keyword.control) (block_params "|" @operator) [ @@ -85,4 +85,4 @@ ">" "" -] @tag.delimiter \ No newline at end of file +] @punctuation.delimiter \ No newline at end of file From 668d909607c1d41c4fde1b2f30290fa1e9b3a09f Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Sun, 17 Mar 2024 18:26:41 +0100 Subject: [PATCH 3/8] highlight this correctly in block statements --- runtime/queries/glimmer/highlights.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index 453c2f320709..ce0b88906d75 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -40,10 +40,11 @@ ]) (#not-match? @variable "yield|outlet|this|else")) ; As are arguments in a block statement -(block_statement_start argument: [ +((block_statement_start argument: [ (path_expression (identifier) @variable) (identifier) @variable ]) + (#not-match? @variable "this")) ; As is an identifier in a block param (block_params (identifier) @variable) ; As are helper arguments From 022a8451714d2fb778d36e39836d2fd67378cfdf Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Sun, 17 Mar 2024 18:45:08 +0100 Subject: [PATCH 4/8] correctly highlight attributes --- runtime/queries/glimmer/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index ce0b88906d75..973ebea1fca1 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -8,7 +8,7 @@ ((tag_name) @constructor (#match? @constructor "^[A-Z]")) -(attribute_name) @variable.other.member +(attribute_name) @attribute (string_literal) @string (number_literal) @constant.numeric.integer From 4a0437166ab6a6c52fb022d56df3dda80488e852 Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Sun, 17 Mar 2024 19:11:13 +0100 Subject: [PATCH 5/8] correctly highlight hash_pair --- runtime/queries/glimmer/highlights.scm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index 973ebea1fca1..31b2307ab668 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -72,7 +72,12 @@ ((helper_invocation helper: (identifier) @keyword.control.conditional) (#match? @keyword.control.conditional "yield")) -(hash_pair key: (identifier) @variable.parameter) +(hash_pair key: (identifier) @variable) +(hash_pair value: (identifier) @variable) +(hash_pair [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) (comment_statement) @comment From 802fc747c38e70e56f0c55722e6ec0e738bdfe90 Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Tue, 19 Mar 2024 15:15:51 +0100 Subject: [PATCH 6/8] add newline to highlights.scm --- runtime/queries/glimmer/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index 31b2307ab668..e2f987253c6c 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -91,4 +91,4 @@ ">" "" -] @punctuation.delimiter \ No newline at end of file +] @punctuation.delimiter From 88ebcf010892a4dcdb429abcb0c95abadb2fa45f Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Tue, 19 Mar 2024 15:25:43 +0100 Subject: [PATCH 7/8] refactor: use #any-of and #eq instead of #match --- runtime/queries/glimmer/highlights.scm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/queries/glimmer/highlights.scm b/runtime/queries/glimmer/highlights.scm index e2f987253c6c..789722ad0736 100644 --- a/runtime/queries/glimmer/highlights.scm +++ b/runtime/queries/glimmer/highlights.scm @@ -26,7 +26,7 @@ (block_statement_start path: (identifier) @keyword.control.conditional) (block_statement_end path: (identifier) @keyword.control.conditional) ((mustache_statement (identifier) @keyword.control.conditional) - (#match? @keyword.control.conditional "else")) + (#eq? @keyword.control.conditional "else")) ; == Mustache Statements === @@ -38,13 +38,13 @@ (path_expression (identifier) @variable) (identifier) @variable ]) - (#not-match? @variable "yield|outlet|this|else")) + (#not-any-of? @variable "yield" "outlet" "this" "else")) ; As are arguments in a block statement ((block_statement_start argument: [ (path_expression (identifier) @variable) (identifier) @variable ]) - (#not-match? @variable "this")) + (#not-eq? @variable "this")) ; As is an identifier in a block param (block_params (identifier) @variable) ; As are helper arguments @@ -52,25 +52,24 @@ (path_expression (identifier) @variable) (identifier) @variable ]) - (#not-match? @variable "this")) + (#not-eq? @variable "this")) ; `this` should be highlighted as a built-in variable ((identifier) @variable.builtin - (#match? @variable.builtin "this")) + (#eq? @variable.builtin "this")) ; If the identifier is just "yield" or "outlet", it's a keyword ((mustache_statement (identifier) @keyword.control.return) - (#match? @keyword.control.return "yield|outlet")) + (#any-of? @keyword.control.return "yield" "outlet")) ; Helpers are functions ((helper_invocation helper: [ (path_expression (identifier) @function) (identifier) @function ]) - (#not-match? @function "if|yield")) -((helper_invocation helper: (identifier) @keyword.control.conditional) - (#match? @keyword.control.conditional "if")) + (#not-any-of? @function "if" "yield")) + ((helper_invocation helper: (identifier) @keyword.control.conditional) - (#match? @keyword.control.conditional "yield")) + (#any-of? @keyword.control.conditional "if" "yield")) (hash_pair key: (identifier) @variable) (hash_pair value: (identifier) @variable) @@ -92,3 +91,4 @@ "" ] @punctuation.delimiter + From 7ef40502f87aa97cb7663f42cf33b6fce1a5ae8a Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Tue, 19 Mar 2024 15:29:29 +0100 Subject: [PATCH 8/8] chore: add newline to languages.toml --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 537737069aff..5ce10bf0ee9e 100644 --- a/languages.toml +++ b/languages.toml @@ -3413,4 +3413,4 @@ formatter = { command = "prettier", args = ['--parser', 'glimmer'] } [[grammar]] name = "glimmer" -source = { git = "https://github.com/ember-tooling/tree-sitter-glimmer", rev = "5dc6d1040e8ff8978ff3680e818d85447bbc10aa" } \ No newline at end of file +source = { git = "https://github.com/ember-tooling/tree-sitter-glimmer", rev = "5dc6d1040e8ff8978ff3680e818d85447bbc10aa" }