You have to create a folder called Terraform
inside your ~/.config/sublime-text/Packages/User
folder. It’s a good idea to have a backup of that folder whenever you switch machines, re-install Sublime and so on. For this plugin in particular I have copy/pasted only the following files from the original repo:
- Comments.tmPreferences
- Symbols.tmPreferences
- Terraform.sublime-settings
And then my modified Teffarom.sublime-syntax
is this:
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Terraform
file_extensions:
- tf
- tfvars
- .terragrunt
- hcl
scope: source.terraform
contexts:
main:
- match: "#"
comment: Comments
captures:
0: punctuation.definition.comment.terraform
push:
- meta_scope: comment.line.number-sign.terraform
- match: $\n?
captures:
0: punctuation.definition.comment.terraform
pop: true
- match: /\*
comment: Block comments
captures:
0: punctuation.definition.comment.terraform
push:
- meta_scope: comment.block.terraform
- match: \*/
captures:
0: punctuation.definition.comment.terraform
pop: true
- match: //
comment: Line comment
scope: punctuation.definition.comment.terraform
push:
- meta_scope: comment.line.double-slash.terraform
- match: $\n?
captures:
0: punctuation.definition.comment.terraform
pop: true
- match: \b(true|false|yes|no|on|off)\b
comment: Language constants (true, false, yes, no, on, off)
scope: constant.language.terraform
- match: '\b([0-9]+)([kKmMgG]b?)?\b'
comment: Numbers
scope: constant.numeric.terraform
- match: '\b(0x[0-9A-Fa-f]+)([kKmMgG]b?)?\b'
comment: Hex numbers
scope: constant.numeric.terraform
- match: '(resource)\s+((")(\w+)?("))\s+((")([\w-]+)?("))\s*\{'
scope: meta.resource.terraform entity.name.resource.terraform
captures:
1: storage.type.function.terraform
2: string.quoted.double.terraform
3: punctuation.definition.string.begin.terraform
4: meta.resource.type.terraform
5: punctuation.definition.string.end.terraform
6: string.quoted.double.terraform
7: punctuation.definition.string.begin.terraform
8: meta.resource.name.terraform
9: punctuation.definition.string.end.terraform
- match: '(data)\s+((")(\w+)?("))\s+((")([\w-]+)?("))\s*\{'
scope: meta.data-source.terraform entity.name.resource.terraform
captures:
1: storage.type.function.terraform
2: string.quoted.double.terraform
3: punctuation.definition.string.begin.terraform
4: meta.data-source.type.terraform
5: punctuation.definition.string.end.terraform
6: string.quoted.double.terraform
7: punctuation.definition.string.begin.terraform
8: meta.data-source.name.terraform
9: punctuation.definition.string.end.terraform
- match: '(provider|provisioner|variable|module|atlas)\s+(")([\w-]+)?(")\s*{'
scope: entity.name.resource.terraform
captures:
1: storage.type.function.terraform
2: string.terraform punctuation.definition.string.begin.terraform
3: string.quoted.double.terraform
4: string.terraform punctuation.definition.string.end.terraform
- match: '(output)\s+(")([-\w\.]+)(")\s*{'
scope: entity.name.resource.terraform
captures:
1: storage.type.function.terraform
2: string.terraform punctuation.definition.string.begin.terraform
3: string.quoted.double.terraform
4: string.terraform punctuation.definition.string.end.terraform
- match: ^\s*(locals|terraform)\s*{
captures:
1: storage.type.function.terraform
push:
- meta_content_scope: meta.block.terraform
- match: '^\s*}'
pop: true
- include: main
- match: '([\w_-]+)\s*(=)\s*'
comment: Value assignments (left hand side not in double quotes)
captures:
1: variable.assignment.terraform
2: keyword.operator.terraform
- match: '(")([\w_-]+)(")\s*(=)\s*'
comment: Value assignments (left hand side in double quotes)
captures:
1: punctuation.quote.double.terraform
2: variable.assignment.terraform
3: punctuation.quote.double.terraform
4: keyword.operator.terraform
- match: '([\w\-_]+)\s+({)'
comment: Maps
captures:
1: entity.name.section.terraform
2: punctuation.definition.tag.terraform
- include: strings
- include: variable_reference
- include: dot
- include: function
- include: for
- include: operators
- include: aws
- include: dynamic
- include: content
- include: blocks
- include: resource_meta
- include: provider_meta
strings:
- 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: interpolation
- include: string_placeholder
- include: string_escaped_char
- match: '<<(\w+)'
scope: punctuation.definition.string.begin.terraform
comment: Heredoc
push:
- meta_scope: string.heredoc.terraform
- match: '^\1'
scope: punctuation.definition.string.end.terraform
pop: true
- include: interpolation
# - match: '<<-SFN'
# comment: JSON
# push:
# - meta_content_scope: source.json
# - match: '^SFN'
# pop: true
# - include: scope:source.json
# - include: interpolation
interpolation:
- match: '\$\{'
scope: punctuation.section.embed.begin.terraform
push:
- meta_scope: meta.embed.terraform
- match: '\}'
scope: punctuation.section.embed.end.terraform
pop: true
- include: interpolated_terraform
interpolated_terraform:
- include: variable_reference
- include: function
- include: operators
- include: interpolation
- include: strings
- include: dot
- include: aws
function:
- match: '(\w+)\('
comment: functions in interpolations
captures:
1: support.function.terraform
push:
- include: variable_reference
- include: function
- include: main
- match: '\)'
pop: true
operators:
- match: '\?|:'
scope: keyword.operator.conditional.terraform
- match: '=|!=|>|<|>=|<=|&&|\|\||!'
scope: keyword.operator.comparison.terraform
- match: (%|&|\*|\+|\-|/)
scope: keyword.operator.arithmetic.terraform
variable_reference:
- match: '(\b(self|count|each|path|var|local|module|data)\b(\.?))'
captures:
1: variable.language.terraform # capture the whole thing - orange
3: keyword.control.terraform # capture only the dot - red
aws:
- match: '(\b((?:aws_|auth0_|azurerm_|azuread_|google_|vault_).*?)\b(\.?))'
captures:
1: storage.type.function.terraform # outermost capture - italic + blue
# 2: variable.function.terraform # inner capture - green
2: variable.language.terraform # orange
3: keyword.control.terraform # capture only the dot - red
dot:
- match: '(\.)'
captures:
# 1: variable.language.terraform # orange
# 1: variable.annotation.terraform # blue
1: keyword.control.terraform # red
# 1: support.function.terraform # green
for:
- match: '\b(for|in|if)\b'
captures:
1: keyword.control.terraform
dynamic:
- match: '(dynamic)\s+("\w+")\s*{'
scope: meta.resource.terraform entity.name.resource.terraform
captures:
1: storage.type.function.terraform # capture the whole thing - blue
2: string.quoted.double.terraform # capture the name - yellow
content:
- match: '^\s*(content)\s*{'
scope: meta.resource.terraform entity.name.resource.terraform
captures:
1: storage.type.function.terraform # capture the whole thing - blue
resource_meta:
- match: '^\s*(count|for_each|iterator|provider|depends_on|lifecycle|sensitive|timeouts)\s*(?:{|(=))\s*'
comment: Resource Meta Arguments
captures:
1: keyword.control.terraform # red
2: keyword.control.terraform # red
provider_meta:
- match: '^\s*(alias)\s*(=)\s*'
comment: Resource Meta Arguments
captures:
1: keyword.control.terraform # red
2: keyword.control.terraform # red
blocks:
- match: '^\s*(source|version|count|for_each|iterator)\s*(=)\s*'
comment: Value assignments for special ..
captures:
1: keyword.control.terraform # red
2: keyword.control.terraform # red
string_placeholder:
- match: |-
(?x)%
[#0\- +']* # flags
(\[\d+\])? # field (argument #)
[,;:_]? # separator character (AltiVec)
((-?\d+)|(\[\d+\])?\*)? # minimum field width
(\.((-?\d+)|(\[\d+\])?\*)?)? # precision
[diouxXDOUeEfFgGaAcCsSpqnvtTbyYhHmMzZ%] # conversion type
scope: constant.other.placeholder.terraform
- match: "%"
scope: invalid.illegal.placeholder.terraform
string_escaped_char:
- match: '\\(\\|[abfnrutv''"]|x\h{2}|u\h{4}|U\h{8}|[0-7]{3})'
scope: constant.character.escape.terraform
- match: \\.
scope: invalid.illegal.unknown-escape.terraform
It’s a work in progress, but it should be relatively easy to find where I am defining the specific cloud provider or service prefixes so that you can add your own. Also I’m definitely not an expert in writing sublime-syntax
files, but what I have so far was done on top of the original file from that repo.