Skip to content

Commit 4836bb3

Browse files
the-mikedavisarchseer
authored andcommitted
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 elixir-lang/tree-sitter-elixir#24 for more information.
1 parent 9d095e0 commit 4836bb3

File tree

5 files changed

+99
-0
lines changed

5 files changed

+99
-0
lines changed

Diff for: book/src/generated/lang-support.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
| graphql || | | |
2727
| haskell || | | `haskell-language-server-wrapper` |
2828
| hcl || || `terraform-ls` |
29+
| heex || | | |
2930
| html || | | `vscode-html-language-server` |
3031
| iex || | | |
3132
| java || | | |

Diff for: languages.toml

+12
Original file line numberDiff line numberDiff line change
@@ -1125,3 +1125,15 @@ indent = { tab-width = 2, unit = " " }
11251125
[[grammar]]
11261126
name = "eex"
11271127
source = { git = "https://github.com/connorlay/tree-sitter-eex", rev = "f742f2fe327463335e8671a87c0b9b396905d1d1" }
1128+
1129+
[[language]]
1130+
name = "heex"
1131+
scope = "source.heex"
1132+
injection-regex = "heex"
1133+
file-types = ["heex"]
1134+
roots = []
1135+
indent = { tab-width = 2, unit = " " }
1136+
1137+
[[grammar]]
1138+
name = "heex"
1139+
source = { git = "https://github.com/connorlay/tree-sitter-heex", rev = "592e22292a367312c35e13de7fdb888f029981d6" }

Diff for: runtime/queries/elixir/injections.scm

+7
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@
77
(#match? @_sigil_name "^(r|R)$")
88
(#set! injection.language "regex")
99
(#set! injection.combined))
10+
11+
((sigil
12+
(sigil_name) @_sigil_name
13+
(quoted_content) @injection.content)
14+
(#match? @_sigil_name "^(h|H)$")
15+
(#set! injection.language "heex")
16+
(#set! injection.combined))

Diff for: runtime/queries/heex/highlights.scm

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/highlights.scm
2+
; HEEx delimiters
3+
[
4+
"<!"
5+
"<!--"
6+
"<"
7+
"<%!--"
8+
"<%#"
9+
">"
10+
"</"
11+
"--%>"
12+
"-->"
13+
"/>"
14+
"{"
15+
"}"
16+
; These could be `@keyword`s but the closing `>` wouldn't be highlighted
17+
; as `@keyword`
18+
"<:"
19+
"</:"
20+
] @punctuation.bracket
21+
22+
; Non-comment or tag delimiters
23+
[
24+
"<%"
25+
"<%="
26+
"<%%="
27+
"%>"
28+
] @keyword
29+
30+
; HEEx operators are highlighted as such
31+
"=" @operator
32+
33+
; HEEx inherits the DOCTYPE tag from HTML
34+
(doctype) @constant
35+
36+
; HEEx comments are highlighted as such
37+
(comment) @comment
38+
39+
; HEEx tags are highlighted as HTML
40+
(tag_name) @tag
41+
42+
; HEEx slots are highlighted as atoms (symbols)
43+
(slot_name) @string.special.symbol
44+
45+
; HEEx attributes are highlighted as HTML attributes
46+
(attribute_name) @attribute
47+
[
48+
(attribute_value)
49+
(quoted_attribute_value)
50+
] @string
51+
52+
; HEEx components are highlighted as Elixir modules and functions
53+
(component_name
54+
[
55+
(module) @module
56+
(function) @function
57+
"." @punctuation.delimiter
58+
])

Diff for: runtime/queries/heex/injections.scm

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/injections.scm
2+
; directives are standalone tags like '<%= @x %>'
3+
;
4+
; partial_expression_values are elixir code that is part of an expression that
5+
; spans multiple directive nodes, so they must be combined. For example:
6+
; <%= if true do %>
7+
; <p>hello, tree-sitter!</p>
8+
; <% end %>
9+
((directive (partial_expression_value) @injection.content)
10+
(#set! injection.language "elixir")
11+
(#set! injection.include-children)
12+
(#set! injection.combined))
13+
14+
; Regular expression_values do not need to be combined
15+
((directive (expression_value) @injection.content)
16+
(#set! injection.language "elixir"))
17+
18+
; expressions live within HTML tags, and do not need to be combined
19+
; <link href={ Routes.static_path(..) } />
20+
((expression (expression_value) @injection.content)
21+
(#set! injection.language "elixir"))

0 commit comments

Comments
 (0)