Sublime Forum

Current state of Terraform HCL Support

#1

Hi all

Whats the current state of play with terraform HCL support, autocomplete etc? I see the last update to the HCL plugin was some time ago. Is there any active development on this at present? Find myself using vscode as not too familiar with Sublime but really like how fast it is and would love to use it for my terraform development.

Apologies if this is a repeat message - I did search but very little results were shown.

Kind regards
Andrew

0 Likes

#2

I would suggest you just leave your issue on the plugin repository.

The plugin only provides snippets and syntax highlight, which also drives some other features like autocompletion in ST.

0 Likes

#3

@andrewglass3 I am using my own extended sublime-syntax file based on the one mentioned above. I was planning on cleaning it up a little bit and make it official eventually but never got around doing it. But even in its current state it makes my vscode peers jealous … I mean it covers the latest HCL syntax and it also highlights cloud provider resources referenced in your code, you know that one starting with aws_ and so on, so I can share that file with you if you want to take that route. In that case you have to create the Terraform folder manually in your User config folder instead of installing it through the package installer, so that you can update it.

0 Likes

#4

Morning @simov - that sounds awesome - yes please if you could share that with simple instructions that would be wonderful thank you :slight_smile:

0 Likes

#5

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.

2 Likes

#6

Don’t forget about installing LSP and LSP-terraform

0 Likes

#7

This is awesome thank you both. @simov I created the Terraform folder inside /Users/andrewglass/Library/Application Support/Sublime Text/Packages/User as I believe that is the correct place on a mac? I then created the file Terraform.sublime-syntax and installed LSP and LSP-terraform.

Have I missed anything?

Thank you very much for your help - I really appreciate it :slight_smile:

0 Likes

#8

Not sure what is the correct path for the User folder on a Mac, but if you can see your Terraform configuration nicely syntax highlighted then that was the correct path, otherwise not. As for the LSP plugins I’m yet to try those out myself.

0 Likes

#9

That is the correct path

1 Like

#10

Good morning all and Happy New Year 2024! :slight_smile:

How’s the Terraform plugin development progressing @simov any updates since you helped me out last year?

Look forward to hearing from you.

Kind regards
Andrew

0 Likes