mdsvexrs/assets/tf.sublime-syntax
2025-07-08 18:53:34 +02:00

552 lines
No EOL
20 KiB
YAML

%YAML 1.2
#
# This syntax definition is based on the Terraform guide:
# https://www.terraform.io/docs/configuration/index.html
#
# As well as the HCL Native Syntax Spec:
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md
#
# For documentation on the .subline-syntax format:
# https://www.sublimetext.com/docs/3/syntax.html
#
# Regex's in this file support the Oniguruma regex engine:
# https://raw.githubusercontent.com/kkos/oniguruma/5.9.6/doc/RE
#
---
name: Terraform
# File Extensions:
#
# - ".tf": the standard file extension
# https://www.terraform.io/docs/configuration/index.html#code-organization
#
# - ".tfvars": variables definitions file
# https://www.terraform.io/docs/configuration/variables.html#variable-definitions-tfvars-files
#
# - ".hcl": non-terraform tools often use this HCL syntax, i.e. Vault
# https://www.vaultproject.io/docs/configuration/
file_extensions:
- tf
- tfvars
- hcl
scope: source.terraform
variables:
# Identifiers: (UTF-8) (ID_Continue | '-')*;
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#identifiers
identifer: \b(?!null|false|true)[[:alpha:]][[:alnum:]_-]*\b
# Exponent: "e" or "E" followed by an optional sign
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#numeric-literals
exponent: ([Ee][+-]?)
# Character Escapes:
#
# - \n: newline
# - \r: carriage return
# - \t: tab
# - \": quote
# - \\: backslash
# - \uNNNN: unicode char (NNNN is 4 hex digits)
# - \uNNNNNNNN: unicode char (NNNNNNNN us 8 digits)
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#template-expressions
char_escapes: \\[nrt"\\]|\\u(\h{8}|\h{4})
# Terraform Named Values
#
# https://www.terraform.io/docs/configuration/expressions.html#references-to-named-values
named_values: var|local|module|data|path|terraform
# Block types that are known to Terraform.
#
# resource: https://www.terraform.io/docs/configuration/resources.html
# provider: https://www.terraform.io/docs/configuration/providers.html
# variable: https://www.terraform.io/docs/configuration/variables.html
# output: https://www.terraform.io/docs/configuration/outputs.html
# locals: https://www.terraform.io/docs/configuration/locals.html
# module: https://www.terraform.io/docs/configuration/modules.html
# data: https://www.terraform.io/docs/configuration/data-sources.html
# terraform: https://www.terraform.io/docs/configuration/terraform.html#terraform-block-syntax
terraform_known_blocks: resource|provider|variable|output|locals|module|data|terraform
# Terraform built-in type keywords
#
# https://www.terraform.io/docs/configuration/types.html#primitive-types
# https://www.terraform.io/docs/configuration/types.html#dynamic-types-the-quot-any-quot-constraint
terraform_type_keywords: any|string|number|bool
# Built-In Functions
#
# https://www.terraform.io/docs/configuration/functions.html
predeclared_funcs: abs|ceil|floor|log|max|min|pow|signum|chomp|format|formatlist|indent|join|lower|regex|regexall|replace|split|strrev|substr|title|trimspace|upper|chunklist|coalesce|coalescelist|compact|concat|contains|distinct|element|flatten|index|keys|length|list|lookup|map|matchkeys|merge|range|reverse|setintersection|setproduct|setunion|slice|sort|transpose|values|zipmap|base64decode|base64encode|base64gzip|csvdecode|jsondecode|jsonencode|urlencode|yamldecode|yamlencode|abspath|dirname|pathexpand|basename|file|fileexists|fileset|filebase64|templatefile|formatdate|timeadd|timestamp|base64sha256|base64sha512|bcrypt|filebase64sha256|filebase64sha512|filemd5|filemd1|filesha256|filesha512|md5|rsadecrypt|sha1|sha256|sha512|uuid|uuidv5|cidrhost|cidrnetmask|cidrsubnet|tobool|tolist|tomap|tonumber|toset|tostring
contexts:
main:
- include: comments
- include: attribute_definition
- include: imports
- include: block
- include: expressions
comments:
- include: inline_comments
- include: block_comments
# Expressions:
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#expression-terms
expressions:
- include: literal_values
- include: operators
- include: brackets
- include: objects
- include: attribute_access
- include: functions
- include: parens
comma:
- match: \,
comment: Commas - used in certain expressions
scope: punctuation.separator.terraform
parens:
- match: \(
scope: punctuation.section.parens.begin.terraform
comment: Parens - matched *after* function syntax
push:
- match: \)
scope: punctuation.section.parens.end.terraform
pop: true
- include: expressions
- match: "{{identifer}}"
comment: Local Identifiers
scope: variable.other.readwrite.terraform
# Literal Values: Numbers, Language Constants, and Strings
#
# Strings are _technically_ part of the "expression sub-language",
# but make the most sense to be part of this stack.
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#literal-values
literal_values:
- include: numeric_literals
- include: language_constants
- include: string_literals
- include: heredoc
- include: type_keywords
- include: named_value_references
named_value_references:
- match: '\b({{named_values}})\b'
comment: Constant values available only to Terraform.
scope: support.constant.terraform
type_keywords:
- match: '\b({{terraform_type_keywords}})\b'
comment: Type keywords known to Terraform.
scope: storage.type.terraform
# Inline Comments: begin at the operator, end at the end of the line.
#
# https://www.terraform.io/docs/configuration/syntax.html#comments
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#comments-and-whitespace
inline_comments:
- match: '#|//'
comment: Inline Comments
scope: punctuation.definition.comment.terraform
push:
- meta_scope: comment.line.terraform
- match: $\n?
scope: punctuation.definition.comment.terraform
pop: true
# Block comments: start and end delimiters for multi-line comments.
#
# https://www.terraform.io/docs/configuration/syntax.html#comments
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#comments-and-whitespace
block_comments:
- match: /\*
comment: Block comments
scope: punctuation.definition.comment.terraform
push:
- meta_scope: comment.block.terraform
- match: \*/
scope: punctuation.definition.comment.terraform
pop: true
# Language Constants: booleans and `null`.
#
# https://www.terraform.io/docs/configuration/expressions.html#literal-expressions
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#literal-values
language_constants:
- match: \b(true|false|null)\b
comment: Language Constants
scope: constant.language.terraform
# Numbers: Integers, fractions and exponents
#
# https://www.terraform.io/docs/configuration/expressions.html#types-and-values
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#numeric-literals
numeric_literals:
- match: \b\d+({{exponent}})\d+\b
comment: Integer, no fraction, optional exponent
scope: constant.numeric.float.terraform
captures:
1: punctuation.separator.exponent.terraform
- match: \b\d+(\.)\d+(?:({{exponent}})\d+)?\b
comment: Integer, fraction, optional exponent
scope: constant.numeric.float.terraform
captures:
1: punctuation.separator.decimal.terraform
2: punctuation.separator.exponent.terraform
- match: \b\d+\b
comment: Integers
scope: constant.numeric.integer.terraform
# Strings:
#
# https://www.terraform.io/docs/configuration/expressions.html#types-and-values
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#template-expressions
string_literals:
- match: '"'
comment: Strings
scope: punctuation.definition.string.begin.terraform
push:
- meta_scope: string.quoted.double.terraform
- match: '"'
scope: punctuation.definition.string.end.terraform
pop: true
- include: string_interpolation
- match: '{{char_escapes}}'
comment: Character Escapes
scope: constant.character.escape.terraform
# String Interpolation: ("${" | "${~") Expression ("}" | "~}"
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#templates
string_interpolation:
- match: (\$|\%)\{
comment: String interpolation
scope: keyword.other.interpolation.begin.terraform
push:
- meta_scope: meta.interpolation.terraform
- clear_scopes: 1 # Clear the string.* scope.
- match: \}
scope: keyword.other.interpolation.end.terraform
pop: true
- match: \~\s
comment: Trim left whitespace
scope: keyword.operator.template.left.trim.terraform
- match: \s\~
comment: Trim right whitespace
scope: keyword.operator.template.right.trim.terraform
- match: \b(if|else|endif|for|in|endfor)\b
comment: if/else/endif and for/in/endfor directives
scope: keyword.control.terraform
- include: expressions
# String Heredocs
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#template-expressions
heredoc:
- match: (\<\<\-?)\s*({{identifer}})\s*$
comment: String Heredoc's
captures:
1: keyword.operator.heredoc.terraform
2: keyword.control.heredoc.terraform
push:
- meta_content_scope: string.unquoted.heredoc.terraform
- match: ^\s*\2\s*$
comment: The heredoc token identifier (second capture above).
scope: keyword.control.heredoc.terraform
pop: true
- include: string_interpolation
# Operators:
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#operators-and-delimiters
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#operations
operators:
- match: \>\= # >=
scope: keyword.operator.terraform
- match: \<\= # <=
scope: keyword.operator.terraform
- match: \=\= # ==
scope: keyword.operator.terraform
- match: \!\= # !=
scope: keyword.operator.terraform
- match: \+ # +
scope: keyword.operator.arithmetic.terraform
- match: \- # -
scope: keyword.operator.arithmetic.terraform
- match: \* # *
scope: keyword.operator.arithmetic.terraform
- match: \/ # /
scope: keyword.operator.arithmetic.terraform
- match: \% # %
scope: keyword.operator.arithmetic.terraform
- match: \&\& # &&
scope: keyword.operator.logical.terraform
- match: \|\| # ||
scope: keyword.operator.logical.terraform
- match: \! # !
scope: keyword.operator.logical.terraform
- match: \> # >
scope: keyword.operator.terraform
- match: \< # <
scope: keyword.operator.terraform
- match: \? # ?
scope: keyword.operator.terraform
- match: \.\.\. # ...
scope: keyword.operator.terraform
- match: "\\:" # :
scope: keyword.operator.terraform
# Terraform "import" statements
#
# https://www.terraform.io/docs/import/usage.html
imports:
- match: \s*(terraform)\s*(import)\s*
comment: Importing resources
captures:
1: support.constant.terraform
2: keyword.control.import.terraform
push:
- match: \"
comment: String literal label
scope: punctuation.definition.string.begin.terraform
push:
- meta_scope: string.quoted.double.terraform
- match: \"
scope: punctuation.definition.string.end.terraform
pop: true
- match: "{{identifer}}"
comment: Identifer label
scope: entity.name.label.terraform
- include: numeric_literals
- include: attribute_access
- match: $\n?
comment: Pop at newline
pop: true
# Brackets: matches tuples and subscript notation
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#index-operator
brackets:
- match: \[
scope: punctuation.section.brackets.begin.terraform
push:
- match: \]
scope: punctuation.section.brackets.end.terraform
pop: true
- match: (\*)\]
comment: Full-splat operator
scope: punctuation.section.brackets.end.terraform
captures:
1: keyword.operator.splat.terraform
pop: true
- include: comma
- include: comments
- include: expressions
- include: tuple_for_expression
# Objects: collection values
#
# Allows keys as identifiers, strings, and computed values wrapped in parens.
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#collection-values
objects:
- match: \{
scope: punctuation.section.braces.begin.terraform
push:
- meta_scope: meta.braces.terraform
- match: \}
scope: punctuation.section.braces.end.terraform
pop: true
- include: object_for_expression
- include: comments
- match: '\s*({{identifer}})\s*(\=)\s*'
comment: Literal, named object key
captures:
1: meta.mapping.key.terraform string.unquoted.terraform
2: keyword.operator.terraform
push: object_key_values
- match: '((\").*(\"))\s*(\=)\s*'
comment: String object key
captures:
1: meta.mapping.key.terraform string.quoted.double.terraform
2: punctuation.definition.string.begin.terraform
3: punctuation.definition.string.end.terraform
4: keyword.operator.terraform
push: object_key_values
- match: \(
comment: Computed object key (any expression between parens)
scope: punctuation.section.parens.begin.terraform
push:
- meta_scope: meta.mapping.key.terraform
- match: '(\))\s*(\=)\s*'
captures:
1: punctuation.section.parens.end.terraform
2: keyword.operator.terraform
set: object_key_values
- include: expressions
# Object key values: pop at comma, newline, and closing-bracket
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#collection-values
object_key_values:
- include: comments
- include: expressions
- match: \,
comment: Pop scope on comma.
scope: punctuation.separator.terraform
pop: true
- match: $\n?
comment: Pop scope on EOL.
pop: true
- match: (?=\})
comment: Lookahead (don't consume) and pop scope on a bracket.
scope: punctuation.section.braces.end.terraform
pop: true
# Attribute Access: "." Identifier
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#attribute-access-operator
attribute_access:
- match: \.
scope: keyword.operator.accessor.terraform
push:
- match: "{{identifer}}"
comment: Attribute access
scope: variable.other.member.terraform
pop: true
- match: \d+
comment: Subscript
scope: constant.numeric.integer.terraform
pop: true
- match: \*
comment: Attribute-only splat
scope: keyword.operator.splat.terraform
pop: true
# Attribute Definition: Identifier "=" Expression Newline
#
# The "=" operator cannot be immediately followed by "="
# ">", as those are other operators, not attr definitions.
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#attribute-definitions
attribute_definition:
- match: (\()?({{identifer}})(\))?\s*(\=[^\=|\>])\s*
comment: Identifier "=" with optional parens
scope: variable.declaration.terraform
captures:
1: punctuation.section.parens.begin.terraform
2: variable.other.readwrite.terraform
3: punctuation.section.parens.end.terraform
4: keyword.operator.assignment.terraform
# Functions: Terraform builtins and unknown
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#functions-and-function-calls
# https://www.terraform.io/docs/configuration/expressions.html#function-calls
functions:
- match: (({{predeclared_funcs}})|\b({{identifer}})\b)(\()
comment: Built-in function calls
captures:
2: support.function.builtin.terraform
3: variable.function.terraform
4: punctuation.section.parens.begin.terraform
push:
- meta_scope: meta.function-call.terraform
- match: \)
scope: punctuation.section.parens.end.terraform
pop: true
- include: comments
- include: expressions
- include: comma
# Tuple for-Expression:
#
# "[" "for" Identifier ("," Identifier)? "in" Expression ":" Expression ("if" Expression)? "]";
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#for-expressions
# https://www.terraform.io/docs/configuration/expressions.html#for-expressions
tuple_for_expression:
- match: \bfor\b
comment: for expression (arrays)
scope: keyword.control.terraform
set:
- include: for_expression_body
- match: \]
scope: punctuation.section.brackets.end.terraform
pop: true
# Object for-Expression:
#
# "{" "for" Identifier ("," Identifier)? "in" Expression ":" Expression "=>" Expression "..."? ("if" Expression)? "}";
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#for-expressions
# https://www.terraform.io/docs/configuration/expressions.html#for-expressions
object_for_expression:
- match: \bfor\b
comment: for expression (arrays)
scope: keyword.control.terraform
set:
- match: \=\>
scope: storage.type.function.terraform
- include: for_expression_body
- match: \}
scope: punctuation.section.braces.end.terraform
pop: true
# Shared body syntax for tuple and object for-expressions.
# They require different `set` blocks because they are
# pop'd with different characters and objects allow `=>`.
for_expression_body:
- match: \bin\b
comment: in keyword
scope: keyword.operator.word.terraform
- match: \bif\b
comment: if keyword
scope: keyword.control.conditional.terraform
- match: '\:'
scope: keyword.operator.terraform
- include: expressions
- include: comments
- include: comma
- match: "{{identifer}}"
comment: Local Identifiers
scope: variable.other.readwrite.terraform
# Blocks: Identifier (StringLit|Identifier)* "{" Newline Body "}" Newline;
#
# https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#structural-elements
block:
- match: '(\b({{terraform_known_blocks}})\b|({{identifer}}))(?=[\s\"\-[:word:]]*(\{))'
captures:
2: storage.type.terraform
3: entity.name.type.terraform
push:
- meta_scope: meta.type.terraform
- match: \"
comment: String literal label
scope: punctuation.definition.string.begin.terraform
push:
- meta_scope: string.quoted.double.terraform
- match: \"
scope: punctuation.definition.string.end.terraform
pop: true
- match: "{{identifer}}"
comment: Identifer label
scope: entity.name.label.terraform
- match: \{
scope: punctuation.section.block.begin.terraform
set:
- meta_scope: meta.block.terraform
- include: main
- match: \}
scope: punctuation.section.block.end.terraform
pop: true