Unnamed repository; edit this file 'description' to name the repository.
Add Tera templating language support (#12756)
uncenter 2025-02-04
parent 313a647 · commit 75abc23
-rw-r--r--book/src/generated/lang-support.md1
-rw-r--r--languages.toml16
-rw-r--r--runtime/queries/tera/highlights.scm225
-rw-r--r--runtime/queries/tera/injections.scm4
-rw-r--r--runtime/queries/tera/locals.scm7
5 files changed, 253 insertions, 0 deletions
diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md
index 906548e6..9ecf7e70 100644
--- a/book/src/generated/lang-support.md
+++ b/book/src/generated/lang-support.md
@@ -215,6 +215,7 @@
| tcl | ✓ | | ✓ | |
| teal | ✓ | | | `teal-language-server` |
| templ | ✓ | | | `templ` |
+| tera | ✓ | | | |
| textproto | ✓ | ✓ | ✓ | |
| tfvars | ✓ | | ✓ | `terraform-ls` |
| thrift | ✓ | | | |
diff --git a/languages.toml b/languages.toml
index a3cb0cfa..8ce53cfc 100644
--- a/languages.toml
+++ b/languages.toml
@@ -4111,3 +4111,19 @@ indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "ghostty"
source = { git = "https://github.com/bezhermoso/tree-sitter-ghostty" , rev = "8438a93b44367e962b2ea3a3b6511885bebd196a" }
+
+[[language]]
+name = "tera"
+scope = "source.tera"
+file-types = ["tera"]
+block-comment-tokens = [
+ { start = "{#", end = "#}" },
+ { start = "{#-", end = "-#}" },
+ { start = "{#", end = "-#}" },
+ { start = "{#-", end = "#}" },
+]
+indent = { tab-width = 4, unit = " " }
+
+[[grammar]]
+name = "tera"
+source = { git = "https://github.com/uncenter/tree-sitter-tera", rev = "e8d679a29c03e64656463a892a30da626e19ed8e" }
diff --git a/runtime/queries/tera/highlights.scm b/runtime/queries/tera/highlights.scm
new file mode 100644
index 00000000..744bacc9
--- /dev/null
+++ b/runtime/queries/tera/highlights.scm
@@ -0,0 +1,225 @@
+; Variables
+;----------
+
+(identifier) @variable
+
+((identifier) @variable.builtin
+ (#any-of? @variable.builtin
+ "loop"
+ "__tera_context"))
+
+; Properties
+;-----------
+
+(member_expression
+ property: (identifier)? @variable.other.member)
+
+; Literals
+;-----------
+
+(string) @string
+
+(bool) @constant.builtin
+
+(number) @constant.numeric
+
+; Tokens
+;-----------
+
+[
+ "."
+ ","
+] @punctuation.delimiter
+
+[
+ "*"
+ "/"
+ "%"
+ "|"
+ "+"
+ "-"
+ "~"
+ "="
+ "=="
+ "!="
+ "<"
+ ">"
+ "<="
+ ">="
+] @operator
+
+[
+ "("
+ ")"
+ "["
+ "]"
+ "{%"
+ "%}"
+ "-%}"
+ "{%-"
+ "}}"
+ "{{"
+ "-}}"
+ "{{-"
+ "::"
+] @punctuation.bracket
+
+; Tags
+;-----------
+
+(comment_tag) @comment
+
+; Keywords
+;-----------
+
+[
+ "if"
+ "elif"
+ "else"
+ "endif"
+] @keyword.control.conditional
+
+[
+ "for"
+ "endfor"
+] @keyword.control.repeat
+
+[
+ "include"
+ "import"
+ "extends"
+] @keyword.control.import
+
+[
+ "in"
+ "and"
+ "or"
+ "not"
+ "is"
+] @keyword.operator
+
+[
+ "break"
+ "continue"
+] @keyword.control.return
+
+[
+ "set"
+ "set_global"
+ "filter"
+ "endfilter"
+ "block"
+ "endblock"
+ "macro"
+ "endmacro"
+ "raw"
+ "endraw"
+ "as"
+] @keyword
+
+; Functions
+;-----------
+
+(macro_statement
+ name: (identifier) @function
+ (parameter_list
+ parameter: (identifier) @variable.parameter
+ (optional_parameter
+ name: (identifier) @variable.parameter)))
+
+(call_expression
+ scope: (identifier)? @namespace
+ name: (identifier) @function)
+
+(call_expression
+ name: (identifier) @function.builtin
+ (#any-of? @function.builtin
+ ; Functions - https://keats.github.io/tera/docs/#built-in-functions
+ "range"
+ "now"
+ "throw"
+ "get_random"
+ "get_env"))
+
+(test_expression
+ test: (identifier) @function)
+
+(test_expression
+ test: (identifier) @function.builtin
+ (#any-of? @function.builtin
+ ; Tests - https://keats.github.io/tera/docs/#built-in-tests
+ "defined"
+ "undefined"
+ "odd"
+ "even"
+ "string"
+ "number"
+ "divisibleby"
+ "iterable"
+ "object"
+ "starting_with"
+ "ending_with"
+ "containing"
+ "matching"))
+
+(filter_expression
+ filter: (identifier) @function.method)
+
+(filter_expression
+ filter: (identifier) @function.builtin
+ (#any-of? @function.builtin
+ ; Filters - https://keats.github.io/tera/docs/#built-in-filters
+ "lower"
+ "upper"
+ "wordcount"
+ "capitalize"
+ "replace"
+ "addslashes"
+ "slugify"
+ "title"
+ "trim"
+ "trim_start"
+ "trim_end"
+ "trim_start_matches"
+ "trim_end_matches"
+ "truncate"
+ "linebreaksbr"
+ "spaceless"
+ "indent"
+ "striptags"
+ "first"
+ "last"
+ "nth"
+ "join"
+ "length"
+ "reverse"
+ "sort"
+ "unique"
+ "slice"
+ "group_by"
+ "filter"
+ "map"
+ "concat"
+ "urlencode"
+ "urlencode_strict"
+ "abs"
+ "pluralize"
+ "round"
+ "filesizeformat"
+ "date"
+ "escape"
+ "escape_xml"
+ "safe"
+ "get"
+ "split"
+ "int"
+ "float"
+ "json_encode"
+ "as_str"
+ "default"))
+
+; Namespaces
+;-----------
+
+(import_statement
+ scope: (identifier) @namespace)
diff --git a/runtime/queries/tera/injections.scm b/runtime/queries/tera/injections.scm
new file mode 100644
index 00000000..2540c1f9
--- /dev/null
+++ b/runtime/queries/tera/injections.scm
@@ -0,0 +1,4 @@
+(frontmatter (content) @injection.content
+ (#set! injection.language "yaml")
+ (#set! injection.combined)
+)
diff --git a/runtime/queries/tera/locals.scm b/runtime/queries/tera/locals.scm
new file mode 100644
index 00000000..04b09cb0
--- /dev/null
+++ b/runtime/queries/tera/locals.scm
@@ -0,0 +1,7 @@
+(identifier) @local.reference
+(assignment_expression
+ left: (identifier) @local.definition)
+(macro_statement
+ (parameter_list
+ (identifier) @local.definition))
+(macro_statement) @local.scope