zed/extensions/terraform/languages/terraform-vars/highlights.scm

160 lines
2.7 KiB
Scheme
Raw Normal View History

Support Terraform Variable Definitions as separate language (#7524) With https://github.com/zed-industries/zed/pull/6882 basic syntax highlighting support for Terraform has arrived in Zed. To fully support all features of the language server (when it lands), it's necessary to handle `*.tfvars` slightly differently. TL;DR: [terraform-ls](https://github.com/hashicorp/terraform-ls) expects `terraform` as language id for `*.tf` files and `terraform-vars` as language id for `*.tfvars` files because the allowed configuration inside the files is different. Duplicating the Terraform language configuration was the only way I could see to achieve this. --- In the [LSP](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem), text documents have a language identifier to identify a document on the server side to avoid reinterpreting the file extension. The Terraform language server currently uses two different language identifiers: * `terraform` - for `*.tf` files * `terraform-vars` - for `*.tfvars` files Both file types contain HCL and can be highlighted using the same grammar and tree-sitter configuration files. The difference in the file content is that `*.tfvars` files only allow top-level attributes and no blocks. [_So you could argue that `*.tfvars` can use a stripped down version of the grammar_]. To set the right context (which affects completion, hover, validation...) for each file, we need to send a different language id. The only way I could see to achieve this with the current architecture was to copy the Terraform language configuration with a different `name` and different `path_suffixes`. Everything else is the same. A Terraform LSP adapter implementation would then map the language configurations to their specific language ids: ```rust fn language_ids(&self) -> HashMap<String, String> { HashMap::from_iter([ ("Terraform".into(), "terraform".into()), ("Terraform Vars".into(), "terraform-vars".into()), ]) } ``` I think it might be helpful in the future to have another way to map file extensions to specific language ids without having to create a new language configuration. ### UX Before ![CleanShot 2024-02-07 at 23 00 56@2x](https://github.com/zed-industries/zed/assets/45985/2c40f477-99a2-4dc1-86de-221acccfcedb) ### UX After ![CleanShot 2024-02-07 at 22 58 40@2x](https://github.com/zed-industries/zed/assets/45985/704c9cca-ae14-413a-be1f-d2439ae1ae22) Release Notes: - N/A --- * Part of https://github.com/zed-industries/zed/issues/5098
2024-02-08 18:12:12 +00:00
; 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"))))