From 4836bb38d3c13c9f1ebd3533bc35a54f80c7e118 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 12 Apr 2022 20:57:07 -0500 Subject: add tree-sitter-heex HEEx is a templating engine on top of Elixir's EEx templating language specific to HTML that is included in Phoenix.LiveView (though I think the plan is to eventually include it in base Phoenix). It's a superset of EEx with some additional features like components and slots. The injections don't work perfectly because the Elixir grammar is newline sensitive (the _terminator rule). See https://github.com/elixir-lang/tree-sitter-elixir/issues/24 for more information. --- book/src/generated/lang-support.md | 1 + languages.toml | 12 ++++++++ runtime/queries/elixir/injections.scm | 7 +++++ runtime/queries/heex/highlights.scm | 58 +++++++++++++++++++++++++++++++++++ runtime/queries/heex/injections.scm | 21 +++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 runtime/queries/heex/highlights.scm create mode 100644 runtime/queries/heex/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index a58c1595..63f02d84 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -26,6 +26,7 @@ | graphql | ✓ | | | | | haskell | ✓ | | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | +| heex | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | | iex | ✓ | | | | | java | ✓ | | | | diff --git a/languages.toml b/languages.toml index 79738db1..7f2a17ab 100644 --- a/languages.toml +++ b/languages.toml @@ -1125,3 +1125,15 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "eex" source = { git = "https://github.com/connorlay/tree-sitter-eex", rev = "f742f2fe327463335e8671a87c0b9b396905d1d1" } + +[[language]] +name = "heex" +scope = "source.heex" +injection-regex = "heex" +file-types = ["heex"] +roots = [] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "heex" +source = { git = "https://github.com/connorlay/tree-sitter-heex", rev = "592e22292a367312c35e13de7fdb888f029981d6" } diff --git a/runtime/queries/elixir/injections.scm b/runtime/queries/elixir/injections.scm index 8370a0d8..c8882534 100644 --- a/runtime/queries/elixir/injections.scm +++ b/runtime/queries/elixir/injections.scm @@ -7,3 +7,10 @@ (#match? @_sigil_name "^(r|R)$") (#set! injection.language "regex") (#set! injection.combined)) + +((sigil + (sigil_name) @_sigil_name + (quoted_content) @injection.content) + (#match? @_sigil_name "^(h|H)$") + (#set! injection.language "heex") + (#set! injection.combined)) diff --git a/runtime/queries/heex/highlights.scm b/runtime/queries/heex/highlights.scm new file mode 100644 index 00000000..301f57c8 --- /dev/null +++ b/runtime/queries/heex/highlights.scm @@ -0,0 +1,58 @@ +; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/highlights.scm +; HEEx delimiters +[ + "" + "" + "-->" + "/>" + "{" + "}" + ; These could be `@keyword`s but the closing `>` wouldn't be highlighted + ; as `@keyword` + "<:" + "" +] @keyword + +; HEEx operators are highlighted as such +"=" @operator + +; HEEx inherits the DOCTYPE tag from HTML +(doctype) @constant + +; HEEx comments are highlighted as such +(comment) @comment + +; HEEx tags are highlighted as HTML +(tag_name) @tag + +; HEEx slots are highlighted as atoms (symbols) +(slot_name) @string.special.symbol + +; HEEx attributes are highlighted as HTML attributes +(attribute_name) @attribute +[ + (attribute_value) + (quoted_attribute_value) +] @string + +; HEEx components are highlighted as Elixir modules and functions +(component_name + [ + (module) @module + (function) @function + "." @punctuation.delimiter + ]) diff --git a/runtime/queries/heex/injections.scm b/runtime/queries/heex/injections.scm new file mode 100644 index 00000000..ad4e4faa --- /dev/null +++ b/runtime/queries/heex/injections.scm @@ -0,0 +1,21 @@ +; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/injections.scm +; directives are standalone tags like '<%= @x %>' +; +; partial_expression_values are elixir code that is part of an expression that +; spans multiple directive nodes, so they must be combined. For example: +; <%= if true do %> +;

hello, tree-sitter!

+; <% end %> +((directive (partial_expression_value) @injection.content) + (#set! injection.language "elixir") + (#set! injection.include-children) + (#set! injection.combined)) + +; Regular expression_values do not need to be combined +((directive (expression_value) @injection.content) + (#set! injection.language "elixir")) + +; expressions live within HTML tags, and do not need to be combined +; +((expression (expression_value) @injection.content) + (#set! injection.language "elixir")) -- cgit v1.2.3-70-g09d2