Skip to content

Commit c4d8d58

Browse files
committed
Fixing HCL and Terraform syntax; updating grammars bundle version
Signed-off-by: Jiri Tyr <jiri.tyr@gmail.com>
1 parent a7f3e0d commit c4d8d58

11 files changed

Lines changed: 588 additions & 7 deletions

File tree

misc/syntax-ts/colors.ini

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,18 @@ comment = brown;
307307
constant = lightgray;
308308
delimiter = brightcyan;
309309
keyword = yellow;
310+
keyword.directive = brightmagenta;
311+
number = lightgray;
312+
operator = brightcyan;
313+
string = green;
314+
type = yellow;
315+
316+
[terraform]
317+
comment = brown;
318+
constant = lightgray;
319+
delimiter = brightcyan;
320+
keyword = yellow;
321+
keyword.directive = brightmagenta;
310322
number = lightgray;
311323
operator = brightcyan;
312324
string = green;

misc/syntax-ts/display-names

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ hack Hack
5656
hare Hare
5757
haskell Haskell Program
5858
haxe Haxe
59-
hcl Terraform/HCL
59+
hcl HCL
60+
terraform Terraform
6061
heex HEEx
6162
hjson HJSON
6263
hlsl HLSL Shader

misc/syntax-ts/extensions

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ hack .hack
5353
hare .hare
5454
haskell .hs .lhs
5555
haxe .hx
56-
hcl .tf .tfvars .hcl
56+
hcl .hcl
57+
terraform .tf .tfvars
5758
heex .heex
5859
hjson .hjson
5960
hlsl .hlsl

misc/syntax-ts/queries-override/hcl-highlights.scm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
;; Tree-sitter highlight queries for HCL (Terraform) language
2-
;; Adapted from helix-editor queries for the tree-sitter-hcl grammar
1+
;; Tree-sitter highlight queries for generic HCL files
2+
;; For Terraform-specific highlighting (.tf/.tfvars), see terraform-highlights.scm
3+
;; HCL is a generic language where block names are arbitrary identifiers.
34

45
[
56
"if"
@@ -57,8 +58,12 @@
5758
((identifier) @type
5859
(#match? @type "^(bool|string|number|object|tuple|list|map|set|any)$"))
5960

60-
((identifier) @keyword
61-
(#match? @keyword "^(var|local|path|module|root|cwd|resource|variable|data|locals|terraform|provider|output)$"))
61+
;; Top-level block names -> brightmagenta (keyword.directive)
62+
(config_file
63+
(body
64+
(block
65+
(identifier) @keyword.directive)))
66+
6267

6368
(comment) @comment
6469
(null_lit) @constant
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
;; Tree-sitter highlight queries for Terraform (.tf/.tfvars) files
2+
;; Uses the HCL grammar with Terraform-specific variable reference prefixes.
3+
;; Block name coloring follows the same generic principle as HCL.
4+
5+
[
6+
"if"
7+
"else"
8+
"endif"
9+
"for"
10+
"endfor"
11+
"in"
12+
] @keyword
13+
14+
[
15+
(ellipsis)
16+
"?"
17+
"=>"
18+
] @operator
19+
20+
[
21+
"!"
22+
"*"
23+
"/"
24+
"%"
25+
"+"
26+
"-"
27+
">"
28+
">="
29+
"<"
30+
"<="
31+
"=="
32+
"!="
33+
"&&"
34+
"||"
35+
] @operator
36+
37+
[
38+
"."
39+
".*"
40+
","
41+
"[*]"
42+
] @delimiter
43+
44+
[
45+
"{"
46+
"}"
47+
"["
48+
"]"
49+
"("
50+
")"
51+
] @delimiter
52+
53+
[
54+
":"
55+
"="
56+
] @operator
57+
58+
((identifier) @type
59+
(#match? @type "^(bool|string|number|object|tuple|list|map|set|any)$"))
60+
61+
;; Top-level block names -> brightmagenta (keyword.directive)
62+
(config_file
63+
(body
64+
(block
65+
(identifier) @keyword.directive)))
66+
67+
68+
;; Terraform variable reference prefixes
69+
(variable_expr
70+
(identifier) @keyword
71+
(#match? @keyword "^(var|local|data|module|path|terraform|count|each|self)$"))
72+
73+
(comment) @comment
74+
(null_lit) @constant
75+
(numeric_lit) @number
76+
(bool_lit) @constant
77+
78+
[
79+
(template_interpolation_start)
80+
(template_interpolation_end)
81+
(template_directive_start)
82+
(template_directive_end)
83+
(strip_marker)
84+
] @operator
85+
86+
[
87+
(heredoc_identifier)
88+
(heredoc_start)
89+
] @string
90+
91+
[
92+
(quoted_template_start)
93+
(quoted_template_end)
94+
(template_literal)
95+
] @string

misc/syntax-ts/symbols

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ dtd xml
1010
html_blade blade
1111
lua nlua
1212
robots robots_txt
13+
terraform hcl
1314
tsx typescript
1415
vbnet tree_sitter_vb_dotnet

scripts/ts-grammars-download.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
set -euo pipefail
44

5-
TS_GRAMMARS_VERSION='2026.04.01'
5+
TS_GRAMMARS_VERSION='2026.04.02'
66
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
77
BASE_URL='https://github.com/jtyr/tree-sitter-grammars/releases/download'
88

tests/syntax/samples/hcl-report.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
HCL syntax highlighting: TS report
2+
====================================
3+
4+
Sample file: `hcl.hcl`
5+
TS query: `misc/syntax-ts/queries-override/hcl-highlights.scm`
6+
TS colors: `misc/syntax-ts/colors.ini` `[hcl]`
7+
Grammar: `hcl` (language: `hcl`)
8+
Legacy reference: none (legacy produces no highlighting for `.hcl`
9+
files)
10+
11+
Note: There is no legacy syntax highlighting for generic HCL files
12+
in MC. This report documents the TS highlighting choices only.
13+
14+
Color assignments
15+
-----------------
16+
17+
- Top-level block names (`service`, `job`, `locals`, `output`,
18+
`variable`, etc.): `brightmagenta` (keyword.directive) — any
19+
identifier that starts a top-level block gets this color. HCL is
20+
a generic language with no reserved block names.
21+
- Nested block names (`group`, `task`, `config`, `resources`, etc.):
22+
DEFAULT — inner blocks are not colored to avoid visual noise.
23+
- Control flow keywords (`if`, `else`, `endif`, `for`, `endfor`,
24+
`in`): `yellow`.
25+
- Comments (`#`, `//`, `/* */`): `brown`.
26+
- Strings (quoted, heredocs): `green`.
27+
- Numbers: `lightgray`.
28+
- Booleans (`true`, `false`): `lightgray` (constant).
29+
- Null (`null`): `lightgray` (constant).
30+
- Type references (`string`, `number`, `bool`, `object`, `tuple`,
31+
`list`, `map`, `set`, `any`): `yellow` (type).
32+
- Operators (`=`, `+`, `-`, `*`, `/`, `%`, `!`, `==`, `!=`, `<`,
33+
`>`, `<=`, `>=`, `&&`, `||`, `?`, `=>`, `:`): `brightcyan`.
34+
- Delimiters (`{`, `}`, `[`, `]`, `(`, `)`, `,`, `.`, `.*`,
35+
`[*]`): `brightcyan`.
36+
- Template interpolation (`${`, `}`): `brightcyan` (operator).
37+
- Heredoc identifiers: `green`.
38+
- Splat expressions (`[*]`, `.*`): `brightcyan` (delimiter).
39+
40+
Design decisions
41+
----------------
42+
43+
- HCL is a generic configuration language with no reserved block
44+
names. All top-level block identifiers are colored uniformly as
45+
`brightmagenta` regardless of their name. This distinguishes
46+
structural blocks from attribute keys without hardcoding any
47+
specific keyword list.
48+
- Nested block names are left as DEFAULT to avoid confusion with
49+
variable references and attribute keys, which also appear as
50+
plain identifiers.
51+
- No variable reference prefixes are colored (unlike Terraform's
52+
`var.`, `local.`, etc.) since HCL itself has no such convention.
53+
Applications that embed HCL may define their own prefixes.
54+
55+
Known shortcomings
56+
------------------
57+
58+
- Legacy MC has no highlighting for `.hcl` files at all, so there
59+
is nothing to compare against.
60+
- Function calls in expressions (e.g. `join()`, `upper()`) are not
61+
colored. The HCL grammar parses them as `function_call` nodes but
62+
the query does not capture them to keep the highlighting minimal
63+
for a generic language.

tests/syntax/samples/hcl.hcl

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Generic HCL sample: demonstrate all syntax features
2+
3+
# Simple block
4+
service "web" {
5+
port = 8080
6+
address = "0.0.0.0"
7+
}
8+
9+
# Nested blocks
10+
job "example" {
11+
group "cache" {
12+
task "redis" {
13+
driver = "docker"
14+
15+
config {
16+
image = "redis:7"
17+
ports = ["redis"]
18+
}
19+
20+
resources {
21+
cpu = 500
22+
memory = 256
23+
}
24+
}
25+
}
26+
}
27+
28+
# Variables and expressions
29+
locals {
30+
environment = "production"
31+
region = "us-east-1"
32+
enabled = true
33+
count = 3
34+
ratio = 0.75
35+
nothing = null
36+
}
37+
38+
# Conditional expression
39+
output "message" {
40+
value = local.enabled ? "yes" : "no"
41+
}
42+
43+
# For expression
44+
output "names" {
45+
value = [for item in local.items : item.name]
46+
}
47+
48+
output "filtered" {
49+
value = {for k, v in local.map : k => v if v != ""}
50+
}
51+
52+
# String interpolation
53+
output "greeting" {
54+
value = "Hello, ${local.environment}!"
55+
}
56+
57+
# Heredoc
58+
output "script" {
59+
value = <<-EOT
60+
#!/bin/bash
61+
echo "Hello"
62+
echo "World"
63+
EOT
64+
}
65+
66+
# Operators
67+
locals {
68+
sum = 1 + 2
69+
diff = 10 - 3
70+
product = 4 * 5
71+
quotient = 10 / 3
72+
remainder = 10 % 3
73+
negative = -1
74+
not_true = !true
75+
and_result = true && false
76+
or_result = true || false
77+
eq = 1 == 1
78+
neq = 1 != 2
79+
gt = 3 > 2
80+
gte = 3 >= 3
81+
lt = 1 < 2
82+
lte = 1 <= 1
83+
}
84+
85+
# Type references
86+
variable "config" {
87+
type = object({
88+
name = string
89+
count = number
90+
enabled = bool
91+
tags = map(string)
92+
ports = list(number)
93+
addrs = set(string)
94+
data = tuple([string, number])
95+
extra = any
96+
})
97+
}
98+
99+
# Splat and index expressions
100+
output "all_ids" {
101+
value = resource.example[*].id
102+
}
103+
104+
output "first" {
105+
value = resource.example[0].id
106+
}
107+
108+
# Collection values
109+
locals {
110+
list_val = [1, 2, 3]
111+
map_val = {key1 = "val1", key2 = "val2"}
112+
empty_map = {}
113+
}
114+
115+
# Block with multiple labels
116+
provisioner "remote-exec" "setup" {
117+
command = "echo hello"
118+
}
119+
120+
# Comments
121+
# Line comment
122+
123+
// Another line comment
124+
125+
/* Block comment */
126+
127+
/*
128+
Multi-line
129+
block comment
130+
*/

0 commit comments

Comments
 (0)