From 6100423ec6f9dc9e7fd28908e3bac666c840e00b Mon Sep 17 00:00:00 2001 From: Ken Chung Date: Tue, 21 Dec 2021 16:08:43 +0800 Subject: [PATCH] support for terrafrom --- configurations/terraform.json | 75 +++ grammars/terraform.tmGrammar.json | 809 ++++++++++++++++++++++++++++++ src/app.ts | 4 + src/languages.ts | 22 + 4 files changed, 910 insertions(+) create mode 100644 configurations/terraform.json create mode 100644 grammars/terraform.tmGrammar.json diff --git a/configurations/terraform.json b/configurations/terraform.json new file mode 100644 index 0000000..8a287a7 --- /dev/null +++ b/configurations/terraform.json @@ -0,0 +1,75 @@ +{ + "comments": { + "lineComment": "#", + "blockComment": [ + "/*", + "*/" + ] + }, + "brackets": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ] + ], + "autoClosingPairs": [ + { + "open": "{", + "close": "}" + }, + { + "open": "[", + "close": "]" + }, + { + "open": "(", + "close": ")" + }, + { + "open": "\"", + "close": "\"", + "notIn": [ + "string" + ] + }, + { + "open": "'", + "close": "'", + "notIn": [ + "string", + "comment" + ] + } + ], + "autoCloseBefore": ";:.,=}])> \n\t\"", + "surroundingPairs": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ], + [ + "\"", + "\"" + ], + [ + "'", + "'" + ] + ] +} \ No newline at end of file diff --git a/grammars/terraform.tmGrammar.json b/grammars/terraform.tmGrammar.json new file mode 100644 index 0000000..6c4dcee --- /dev/null +++ b/grammars/terraform.tmGrammar.json @@ -0,0 +1,809 @@ +{ + "scopeName": "scope.terraform", + "fileTypes": [ + "tf", + "tfvars", + "hcl" + ], + "name": "Terraform", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#attribute_definition" + }, + { + "include": "#block" + }, + { + "include": "#expressions" + } + ], + "repository": { + "char_escapes": { + "match": "\\\\[nrt\"\\\\]|\\\\u(\\h{8}|\\h{4})", + "comment": "Character Escapes", + "name": "constant.character.escape.terraform" + }, + "comma": { + "match": "\\,", + "comment": "Commas - used in certain expressions", + "name": "punctuation.separator.terraform" + }, + "language_constants": { + "match": "\\b(true|false|null)\\b", + "comment": "Language Constants", + "name": "constant.language.terraform" + }, + "named_value_references": { + "match": "\\b(var|local|module|data|path|terraform)\\b", + "comment": "Constant values available only to Terraform.", + "name": "support.constant.terraform" + }, + "local_identifiers": { + "match": "\\b(?!null|false|true)[[:alpha:]][[:alnum:]_-]*\\b", + "comment": "Local Identifiers", + "name": "variable.other.readwrite.terraform" + }, + "terraform_type_keywords": { + "match": "\\b(any|string|number|bool)\\b", + "comment": "Type keywords known to Terraform.", + "name": "storage.type.terraform" + }, + "comments": { + "patterns": [ + { + "include": "#inline_comments" + }, + { + "include": "#block_comments" + } + ] + }, + "inline_comments": { + "begin": "#|//", + "comment": "Inline Comments", + "name": "comment.line.terraform", + "captures": { + "0": { + "name": "punctuation.definition.comment.terraform" + } + }, + "end": "$\\n?" + }, + "block_comments": { + "begin": "/\\*", + "comment": "Block comments", + "name": "comment.block.terraform", + "captures": { + "0": { + "name": "punctuation.definition.comment.terraform" + } + }, + "end": "\\*/" + }, + "attribute_definition": { + "match": "(\\()?((?!null|false|true)[[:alpha:]][[:alnum:]_-]*)(\\))?\\s*(\\=(?!\\=|\\>))\\s*", + "comment": "Identifier \"=\" with optional parens", + "name": "variable.declaration.terraform", + "captures": { + "1": { + "name": "punctuation.section.parens.begin.terraform" + }, + "2": { + "name": "variable.other.readwrite.terraform" + }, + "3": { + "name": "punctuation.section.parens.end.terraform" + }, + "4": { + "name": "keyword.operator.assignment.terraform" + } + } + }, + "block": { + "name": "meta.block.terraform", + "begin": "(\\w+)(?:([\\s\\\"\\-[:word:]]*)(\\{))", + "beginCaptures": { + "1": { + "patterns": [ + { + "match": "\\b(?:resource|provider|variable|output|locals|module|data|terraform)\\b", + "name": "entity.name.type.terraform" + }, + { + "match": "\\b(?!null|false|true)[[:alpha:]][[:alnum:]_-]*\\b", + "comment": "Identifer label", + "name": "entity.name.label.terraform" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#string_literals" + } + ] + }, + "3": { + "name": "punctuation.section.block.begin.terraform" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.terraform" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#attribute_definition" + }, + { + "include": "#block" + }, + { + "include": "#expressions" + } + ] + }, + "expressions": { + "patterns": [ + { + "include": "#literal_values" + }, + { + "include": "#operators" + }, + { + "include": "#tuple_for_expression" + }, + { + "include": "#object_for_expression" + }, + { + "include": "#brackets" + }, + { + "include": "#objects" + }, + { + "include": "#attribute_access" + }, + { + "include": "#structural_types" + }, + { + "include": "#functions" + }, + { + "include": "#parens" + } + ] + }, + "literal_values": { + "patterns": [ + { + "include": "#numeric_literals" + }, + { + "include": "#language_constants" + }, + { + "include": "#string_literals" + }, + { + "include": "#heredoc" + }, + { + "include": "#terraform_type_keywords" + }, + { + "include": "#named_value_references" + } + ] + }, + "numeric_literals": { + "patterns": [ + { + "match": "\\b\\d+([Ee][+-]?)\\d+\\b", + "comment": "Integer, no fraction, optional exponent", + "name": "constant.numeric.float.terraform", + "captures": { + "1": { + "name": "punctuation.separator.exponent.terraform" + } + } + }, + { + "match": "\\b\\d+(\\.)\\d+(?:([Ee][+-]?)\\d+)?\\b", + "comment": "Integer, fraction, optional exponent", + "name": "constant.numeric.float.terraform", + "captures": { + "1": { + "name": "punctuation.separator.decimal.terraform" + }, + "2": { + "name": "punctuation.separator.exponent.terraform" + } + } + }, + { + "match": "\\b\\d+\\b", + "comment": "Integers", + "name": "constant.numeric.integer.terraform" + } + ] + }, + "string_literals": { + "begin": "\"", + "comment": "Strings", + "name": "string.quoted.double.terraform", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.terraform" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.terraform" + } + }, + "patterns": [ + { + "include": "#string_interpolation" + }, + { + "include": "#char_escapes" + } + ] + }, + "string_interpolation": { + "begin": "(\\G|[^%$])([%$]{)", + "comment": "String interpolation", + "name": "meta.interpolation.terraform", + "beginCaptures": { + "2": { + "name": "keyword.other.interpolation.begin.terraform" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "keyword.other.interpolation.end.terraform" + } + }, + "patterns": [ + { + "match": "\\~\\s", + "comment": "Trim left whitespace", + "name": "keyword.operator.template.left.trim.terraform" + }, + { + "match": "\\s\\~", + "comment": "Trim right whitespace", + "name": "keyword.operator.template.right.trim.terraform" + }, + { + "match": "\\b(if|else|endif|for|in|endfor)\\b", + "comment": "if/else/endif and for/in/endfor directives", + "name": "keyword.control.terraform" + }, + { + "include": "#expressions" + }, + { + "include": "#local_identifiers" + } + ] + }, + "heredoc": { + "begin": "(\\<\\<\\-?)\\s*(\\w+)\\s*$", + "comment": "String Heredoc", + "name": "string.unquoted.heredoc.terraform", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.terraform" + }, + "2": { + "name": "keyword.control.heredoc.terraform" + } + }, + "end": "^\\s*\\2\\s*$", + "endCaptures": { + "0": { + "comment": "The heredoc token identifier (second capture above).", + "name": "keyword.control.heredoc.terraform" + } + }, + "patterns": [ + { + "include": "#string_interpolation" + } + ] + }, + "operators": { + "patterns": [ + { + "match": "\\>\\=", + "name": "keyword.operator.terraform" + }, + { + "match": "\\<\\=", + "name": "keyword.operator.terraform" + }, + { + "match": "\\=\\=", + "name": "keyword.operator.terraform" + }, + { + "match": "\\!\\=", + "name": "keyword.operator.terraform" + }, + { + "match": "\\+", + "name": "keyword.operator.arithmetic.terraform" + }, + { + "match": "\\-", + "name": "keyword.operator.arithmetic.terraform" + }, + { + "match": "\\*", + "name": "keyword.operator.arithmetic.terraform" + }, + { + "match": "\\/", + "name": "keyword.operator.arithmetic.terraform" + }, + { + "match": "\\%", + "name": "keyword.operator.arithmetic.terraform" + }, + { + "match": "\\&\\&", + "name": "keyword.operator.logical.terraform" + }, + { + "match": "\\|\\|", + "name": "keyword.operator.logical.terraform" + }, + { + "match": "\\!", + "name": "keyword.operator.logical.terraform" + }, + { + "match": "\\>", + "name": "keyword.operator.terraform" + }, + { + "match": "\\<", + "name": "keyword.operator.terraform" + }, + { + "match": "\\?", + "name": "keyword.operator.terraform" + }, + { + "match": "\\.\\.\\.", + "name": "keyword.operator.terraform" + }, + { + "match": "\\:", + "scope": "keyword.operator.terraform" + } + ] + }, + "brackets": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.begin.terraform" + } + }, + "end": "(\\*?)\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.terraform" + }, + "1": { + "name": "keyword.operator.splat.terraform" + } + }, + "patterns": [ + { + "include": "#comma" + }, + { + "include": "#comments" + }, + { + "include": "#expressions" + }, + { + "include": "#local_identifiers" + } + ] + }, + "objects": { + "name": "meta.braces.terraform", + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.braces.begin.terraform" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.braces.end.terraform" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "match": "\\b((?!null|false|true)[[:alpha:]][[:alnum:]_-]*)\\s*(\\=)\\s*", + "comment": "Literal, named object key", + "captures": { + "1": { + "name": "meta.mapping.key.terraform string.unquoted.terraform" + }, + "2": { + "name": "keyword.operator.terraform" + } + } + }, + { + "match": "\\b((\").*(\"))\\s*(\\=)\\s*", + "comment": "String object key", + "captures": { + "0": { + "patterns": [ + { + "include": "#named_value_references" + } + ] + }, + "1": { + "name": "meta.mapping.key.terraform string.quoted.double.terraform" + }, + "2": { + "name": "punctuation.definition.string.begin.terraform" + }, + "3": { + "name": "punctuation.definition.string.end.terraform" + }, + "4": { + "name": "keyword.operator.terraform" + } + } + }, + { + "begin": "^\\s*\\(", + "comment": "Computed object key (any expression between parens)", + "name": "meta.mapping.key.terraform", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.terraform" + } + }, + "end": "(\\))\\s*(\\=)\\s*", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.terraform" + }, + "2": { + "name": "keyword.operator.terraform" + } + }, + "patterns": [ + { + "include": "#named_value_references" + }, + { + "include": "#attribute_access" + } + ] + }, + { + "include": "#object_key_values" + } + ] + }, + "object_key_values": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#literal_values" + }, + { + "include": "#operators" + }, + { + "include": "#tuple_for_expression" + }, + { + "include": "#object_for_expression" + }, + { + "include": "#heredoc" + }, + { + "include": "#functions" + } + ] + }, + "tuple_for_expression": { + "begin": "(\\[)\\s?(for)\\b", + "beginCaptures": { + "1": { + "name": "punctuation.section.brackets.begin.terraform" + }, + "2": { + "comment": "for expression (tuple)", + "name": "keyword.control.terraform" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.terraform" + } + }, + "patterns": [ + { + "include": "#for_expression_body" + } + ] + }, + "object_for_expression": { + "begin": "(\\{)\\s?(for)\\b", + "beginCaptures": { + "1": { + "name": "punctuation.section.braces.begin.terraform" + }, + "2": { + "comment": "for expression (object)", + "name": "keyword.control.terraform" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.braces.end.terraform" + } + }, + "patterns": [ + { + "match": "\\=\\>", + "name": "storage.type.function.terraform" + }, + { + "include": "#for_expression_body" + } + ] + }, + "for_expression_body": { + "patterns": [ + { + "match": "\\bin\\b", + "comment": "in keyword", + "name": "keyword.operator.word.terraform" + }, + { + "match": "\\bif\\b", + "comment": "if keyword", + "name": "keyword.control.conditional.terraform" + }, + { + "match": "\\:", + "name": "keyword.operator.terraform" + }, + { + "include": "#expressions" + }, + { + "include": "#comments" + }, + { + "include": "#comma" + }, + { + "include": "#local_identifiers" + } + ] + }, + "attribute_access": { + "begin": "\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.accessor.terraform" + } + }, + "end": "\\w+(\\[[0-9\\*]+\\])?", + "endCaptures": { + "0": { + "patterns": [ + { + "match": "\\b(?!null|false|true)[[:alpha:]][[:alnum:]_-]*\\b", + "comment": "Attribute access", + "name": "variable.other.member.terraform" + } + ] + }, + "1": { + "patterns": [ + { + "match": "\\d+", + "comment": "Subscript", + "name": "constant.numeric.integer.terraform" + }, + { + "match": "\\*", + "comment": "Attribute-only splat", + "name": "keyword.operator.splat.terraform" + } + ] + } + } + }, + "structural_types": { + "patterns": [ + { + "begin": "(object)(\\()(\\{)\\s*", + "name": "meta.function-call.terraform", + "comment": "Object structural type", + "beginCaptures": { + "1": { + "name": "support.function.builtin.terraform" + }, + "2": { + "name": "punctuation.section.parens.begin.terraform" + }, + "3": { + "name": "punctuation.section.braces.begin.terraform" + } + }, + "end": "(\\})(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.braces.end.terraform" + }, + "2": { + "name": "punctuation.section.parens.end.terraform" + } + }, + "patterns": [ + { + "include": "#comma" + }, + { + "match": "((?!null|false|true)[[:alpha:]][[:alnum:]_-]*)\\s*(\\=(?!\\=|\\>))\\s*", + "comment": "Identifier \"=\"", + "name": "variable.declaration.terraform", + "captures": { + "1": { + "name": "variable.other.readwrite.terraform" + }, + "2": { + "name": "keyword.operator.assignment.terraform" + } + } + }, + { + "include": "#terraform_type_keywords" + } + ] + }, + { + "begin": "(tuple)(\\()(\\[)\\s*", + "name": "meta.function-call.terraform", + "comment": "Tuple structural type", + "beginCaptures": { + "1": { + "name": "support.function.builtin.terraform" + }, + "2": { + "name": "punctuation.section.parens.begin.terraform" + }, + "3": { + "name": "punctuation.section.brackets.begin.terraform" + } + }, + "end": "(\\])(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.brackets.end.terraform" + }, + "2": { + "name": "punctuation.section.parens.end.terraform" + } + }, + "patterns": [ + { + "include": "#comma" + }, + { + "include": "#terraform_type_keywords" + } + ] + } + ] + }, + "functions": { + "begin": "(\\w+)(\\()", + "name": "meta.function-call.terraform", + "comment": "Built-in function calls", + "beginCaptures": { + "1": { + "patterns": [ + { + "match": "abspath|abs|ceil|floor|log|max|min|pow|signum|chomp|formatlist|indent|join|lower|regexall|regex|replace|split|strrev|substr|title|trimspace|upper|chunklist|coalescelist|coalesce|compact|concat|contains|distinct|element|flatten|index|keys|length|lookup|matchkeys|merge|range|reverse|setintersection|setproduct|setunion|slice|sort|transpose|values|zipmap|base64decode|base64encode|base64gzip|csvdecode|jsondecode|jsonencode|urlencode|yamldecode|yamlencode|dirname|pathexpand|basename|fileexists|fileset|filebase64|templatefile|formatdate|timeadd|timestamp|base64sha256|base64sha512|bcrypt|filebase64sha256|filebase64sha512|filemd5|filemd1|filesha256|filesha512|md5|rsadecrypt|sha1|sha256|sha512|uuidv5|uuid|cidrhost|cidrnetmask|cidrsubnet|tobool|tolist|tomap|tonumber|toset|tostring|file|format", + "name": "support.function.builtin.terraform" + }, + { + "match": "list|map", + "name": "invalid.deprecated.terraform" + }, + { + "match": "\\b(?!null|false|true)[[:alpha:]][[:alnum:]_-]*\\b", + "name": "variable.function.terraform" + } + ] + }, + "2": { + "name": "punctuation.section.parens.begin.terraform" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.terraform" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#expressions" + }, + { + "include": "#comma" + } + ] + }, + "parens": { + "begin": "\\(", + "comment": "Parens - matched *after* function syntax", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.terraform" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.terraform" + } + }, + "patterns": [ + { + "include": "#expressions" + }, + { + "include": "#local_identifiers" + } + ] + } + } +} \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index f6e022c..281e9ce 100644 --- a/src/app.ts +++ b/src/app.ts @@ -115,6 +115,10 @@ async function main(language: LanguageId, theme: string) { // change the call to main() above to pass your LanguageId. const languages: monaco.languages.ILanguageExtensionPoint[] = languagesDefinitions; const grammars: {[scopeName: string]: DemoScopeNameInfo} = { + 'scope.terraform': { + language: 'terraform', + path: 'terraform.tmGrammar.json', + }, 'source.vue': { language: 'vue', path: 'vue-generated.json', diff --git a/src/languages.ts b/src/languages.ts index 67abf19..4de7f1f 100644 --- a/src/languages.ts +++ b/src/languages.ts @@ -639,5 +639,27 @@ export const languagesDefinitions: monaco.languages.ILanguageExtensionPoint[] = extensions: [ ".vue" ] + }, + { + id: "terraform", + aliases: [ + "Terraform", + "terraform" + ], + extensions: [ + ".tf" + ] + }, + { + id: "terraform-vars", + extensions: [ + ".tfvars" + ] + }, + { + id: "json", + extensions: [ + ".tfstate" + ] } ]; \ No newline at end of file