Add Terraform & HCL syntax highlighting (#6882)
Terraform and HCL are almost the same language, but not quite so proposing them as separate languages within Zed. (Terraform is an extension of HCL, with a different formatter.) This is just adding the language definition, parsing and highlighting functionality, not any LSP or formatting beyond that for either language. I've taken a bunch of inspiration from Neovim for having the separate languages, and also lifted some of their `scm` files (with attribution comments in this codebase) as the tree-sitter repo doesn't contain them. (Neovim's code is Apache-2.0 licensed, so should be fine here with attribution from reading Zed's licenses files.) I've then amended to make sure the capture groups are named for things Zed understands. I'd love someone from Zed to confirm that's okay, or if I should clean-room implement the `scm` files. Highlighting in Terraform & HCL with a moderate amount of syntax in a file (Terraform on left, HCL on right.) <img width="1392" alt="Screenshot 2024-01-31 at 18 07 45" src="https://github.com/zed-industries/zed/assets/696/1d3c9a08-588e-4b8f-ad92-98ce1e419659"> Release Notes: - (|Improved) ... ([#5098](https://github.com/zed-industries/zed/issues/5098)).
This commit is contained in:
Generated
+10
@@ -8876,6 +8876,15 @@ dependencies = [
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-hcl"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/MichaHoffmann/tree-sitter-hcl?rev=v1.1.0#636dbe70301ecbab8f353c8c78b3406fe4f185f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-heex"
|
||||
version = "0.0.1"
|
||||
@@ -10394,6 +10403,7 @@ dependencies = [
|
||||
"tree-sitter-gomod",
|
||||
"tree-sitter-gowork",
|
||||
"tree-sitter-haskell",
|
||||
"tree-sitter-hcl",
|
||||
"tree-sitter-heex",
|
||||
"tree-sitter-html",
|
||||
"tree-sitter-json 0.20.0",
|
||||
|
||||
@@ -157,6 +157,7 @@ tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev =
|
||||
tree-sitter-gomod = { git = "https://github.com/camdencheek/tree-sitter-go-mod" }
|
||||
tree-sitter-gowork = { git = "https://github.com/d1y/tree-sitter-go-work" }
|
||||
tree-sitter-haskell = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "cf98de23e4285b8e6bcb57b050ef2326e2cc284b" }
|
||||
tree-sitter-hcl = {git = "https://github.com/MichaHoffmann/tree-sitter-hcl", rev = "v1.1.0"}
|
||||
tree-sitter-heex = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "2e1348c3cf2c9323e87c2744796cf3f3868aa82a" }
|
||||
tree-sitter-html = "0.19.0"
|
||||
tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" }
|
||||
|
||||
@@ -498,6 +498,9 @@
|
||||
"JavaScript": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"Terraform": {
|
||||
"tab_size": 2
|
||||
},
|
||||
"TypeScript": {
|
||||
"tab_size": 2
|
||||
},
|
||||
|
||||
@@ -124,6 +124,7 @@ tree-sitter-go.workspace = true
|
||||
tree-sitter-gomod.workspace = true
|
||||
tree-sitter-gowork.workspace = true
|
||||
tree-sitter-haskell.workspace = true
|
||||
tree-sitter-hcl.workspace = true
|
||||
tree-sitter-heex.workspace = true
|
||||
tree-sitter-html.workspace = true
|
||||
tree-sitter-json.workspace = true
|
||||
|
||||
@@ -322,6 +322,8 @@ pub fn init(
|
||||
vec![Arc::new(uiua::UiuaLanguageServer {})],
|
||||
);
|
||||
language("proto", tree_sitter_proto::language(), vec![]);
|
||||
language("terraform", tree_sitter_hcl::language(), vec![]);
|
||||
language("hcl", tree_sitter_hcl::language(), vec![]);
|
||||
|
||||
if let Ok(children) = std::fs::read_dir(&*PLUGINS_DIR) {
|
||||
for child in children {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "HCL"
|
||||
path_suffixes = ["hcl"]
|
||||
line_comments = ["# ", "// "]
|
||||
block_comment = ["/*", "*/"]
|
||||
autoclose_before = ",}])"
|
||||
brackets = [
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
{ start = "[", end = "]", close = true, newline = true },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
]
|
||||
@@ -0,0 +1,117 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/hcl/highlights.scm
|
||||
; highlights.scm
|
||||
[
|
||||
"!"
|
||||
"\*"
|
||||
"/"
|
||||
"%"
|
||||
"\+"
|
||||
"-"
|
||||
">"
|
||||
">="
|
||||
"<"
|
||||
"<="
|
||||
"=="
|
||||
"!="
|
||||
"&&"
|
||||
"||"
|
||||
] @operator
|
||||
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
"("
|
||||
")"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"."
|
||||
".*"
|
||||
","
|
||||
"[*]"
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(ellipsis)
|
||||
"\?"
|
||||
"=>"
|
||||
] @punctuation.special
|
||||
|
||||
[
|
||||
":"
|
||||
"="
|
||||
] @punctuation
|
||||
|
||||
[
|
||||
"for"
|
||||
"endfor"
|
||||
"in"
|
||||
"if"
|
||||
"else"
|
||||
"endif"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
(quoted_template_start) ; "
|
||||
(quoted_template_end) ; "
|
||||
(template_literal) ; non-interpolation/directive content
|
||||
] @string
|
||||
|
||||
[
|
||||
(heredoc_identifier) ; END
|
||||
(heredoc_start) ; << or <<-
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(template_interpolation_start) ; ${
|
||||
(template_interpolation_end) ; }
|
||||
(template_directive_start) ; %{
|
||||
(template_directive_end) ; }
|
||||
(strip_marker) ; ~
|
||||
] @punctuation.special
|
||||
|
||||
(numeric_lit) @number
|
||||
|
||||
(bool_lit) @boolean
|
||||
|
||||
(null_lit) @constant
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(identifier) @variable
|
||||
|
||||
(body
|
||||
(block
|
||||
(identifier) @keyword))
|
||||
|
||||
(body
|
||||
(block
|
||||
(body
|
||||
(block
|
||||
(identifier) @type))))
|
||||
|
||||
(function_call
|
||||
(identifier) @function)
|
||||
|
||||
(attribute
|
||||
(identifier) @variable)
|
||||
|
||||
; { key: val }
|
||||
;
|
||||
; highlight identifier keys as though they were block attributes
|
||||
(object_elem
|
||||
key:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)))
|
||||
|
||||
; var.foo, data.bar
|
||||
;
|
||||
; first element in get_attr is a variable.builtin or a reference to a variable.builtin
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)
|
||||
(get_attr
|
||||
(identifier) @variable))
|
||||
@@ -0,0 +1,11 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/indents.scm
|
||||
[
|
||||
(block)
|
||||
(object)
|
||||
(tuple)
|
||||
(function_call)
|
||||
] @indent
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
@@ -0,0 +1,6 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/injections.scm
|
||||
|
||||
(heredoc_template
|
||||
(template_literal) @content
|
||||
(heredoc_identifier) @language
|
||||
(#downcase! @language))
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Terraform"
|
||||
path_suffixes = ["tf", "tfvars"]
|
||||
line_comments = ["# ", "// "]
|
||||
block_comment = ["/*", "*/"]
|
||||
autoclose_before = ",}])"
|
||||
brackets = [
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
{ start = "[", end = "]", close = true, newline = true },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
]
|
||||
@@ -0,0 +1,159 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/hcl/highlights.scm
|
||||
; highlights.scm
|
||||
[
|
||||
"!"
|
||||
"\*"
|
||||
"/"
|
||||
"%"
|
||||
"\+"
|
||||
"-"
|
||||
">"
|
||||
">="
|
||||
"<"
|
||||
"<="
|
||||
"=="
|
||||
"!="
|
||||
"&&"
|
||||
"||"
|
||||
] @operator
|
||||
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
"("
|
||||
")"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"."
|
||||
".*"
|
||||
","
|
||||
"[*]"
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(ellipsis)
|
||||
"\?"
|
||||
"=>"
|
||||
] @punctuation.special
|
||||
|
||||
[
|
||||
":"
|
||||
"="
|
||||
] @punctuation
|
||||
|
||||
[
|
||||
"for"
|
||||
"endfor"
|
||||
"in"
|
||||
"if"
|
||||
"else"
|
||||
"endif"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
(quoted_template_start) ; "
|
||||
(quoted_template_end) ; "
|
||||
(template_literal) ; non-interpolation/directive content
|
||||
] @string
|
||||
|
||||
[
|
||||
(heredoc_identifier) ; END
|
||||
(heredoc_start) ; << or <<-
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(template_interpolation_start) ; ${
|
||||
(template_interpolation_end) ; }
|
||||
(template_directive_start) ; %{
|
||||
(template_directive_end) ; }
|
||||
(strip_marker) ; ~
|
||||
] @punctuation.special
|
||||
|
||||
(numeric_lit) @number
|
||||
|
||||
(bool_lit) @boolean
|
||||
|
||||
(null_lit) @constant
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(identifier) @variable
|
||||
|
||||
(body
|
||||
(block
|
||||
(identifier) @keyword))
|
||||
|
||||
(body
|
||||
(block
|
||||
(body
|
||||
(block
|
||||
(identifier) @type))))
|
||||
|
||||
(function_call
|
||||
(identifier) @function)
|
||||
|
||||
(attribute
|
||||
(identifier) @variable)
|
||||
|
||||
; { key: val }
|
||||
;
|
||||
; highlight identifier keys as though they were block attributes
|
||||
(object_elem
|
||||
key:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)))
|
||||
|
||||
; var.foo, data.bar
|
||||
;
|
||||
; first element in get_attr is a variable.builtin or a reference to a variable.builtin
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)
|
||||
(get_attr
|
||||
(identifier) @variable))
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/terraform/highlights.scm
|
||||
; Terraform specific references
|
||||
;
|
||||
;
|
||||
; local/module/data/var/output
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "data" "var" "local" "module" "output"))
|
||||
(get_attr
|
||||
(identifier) @variable))
|
||||
|
||||
; path.root/cwd/module
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#eq? @type "path"))
|
||||
(get_attr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "root" "cwd" "module")))
|
||||
|
||||
; terraform.workspace
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#eq? @type "terraform"))
|
||||
(get_attr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "workspace")))
|
||||
|
||||
; Terraform specific keywords
|
||||
; FIXME: ideally only for identifiers under a `variable` block to minimize false positives
|
||||
((identifier) @type
|
||||
(#any-of? @type "bool" "string" "number" "object" "tuple" "list" "map" "set" "any"))
|
||||
|
||||
(object_elem
|
||||
val:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#any-of? @type "bool" "string" "number" "object" "tuple" "list" "map" "set" "any"))))
|
||||
@@ -0,0 +1,14 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/indents.scm
|
||||
[
|
||||
(block)
|
||||
(object)
|
||||
(tuple)
|
||||
(function_call)
|
||||
] @indent
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/terraform/indents.scm
|
||||
; inherits: hcl
|
||||
@@ -0,0 +1,9 @@
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/injections.scm
|
||||
|
||||
(heredoc_template
|
||||
(template_literal) @content
|
||||
(heredoc_identifier) @language
|
||||
(#downcase! @language))
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/terraform/injections.scm
|
||||
; inherits: hcl
|
||||
Reference in New Issue
Block a user