From 1718a963e6321c0d8b663ca3f2224be366d59905 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sat, 7 Jul 2018 12:36:32 -0700 Subject: [PATCH] extras: initial TextMate-style grammar for HCL This is for the core HCL syntax, so it doesn't include any application-specific keyword highlighting, etc. The structural, expression, and template languages are separated into different grammar definitions so that they can be used independently, but they embed each other as needed to complete the language. This is just a first pass, really. There are probably some bugs here, and also some missing features. --- extras/grammar/HCL.json-tmLanguage | 97 ++++++ extras/grammar/HCL.tmLanguage | 157 +++++++++ extras/grammar/HCL.yaml-tmLanguage | 53 +++ extras/grammar/HCLExpression.json-tmLanguage | 212 ++++++++++++ extras/grammar/HCLExpression.tmLanguage | 336 +++++++++++++++++++ extras/grammar/HCLExpression.yaml-tmLanguage | 111 ++++++ extras/grammar/HCLTemplate.json-tmLanguage | 107 ++++++ extras/grammar/HCLTemplate.tmLanguage | 172 ++++++++++ extras/grammar/HCLTemplate.yaml-tmLanguage | 58 ++++ extras/grammar/build.go | 119 +++++++ 10 files changed, 1422 insertions(+) create mode 100755 extras/grammar/HCL.json-tmLanguage create mode 100755 extras/grammar/HCL.tmLanguage create mode 100644 extras/grammar/HCL.yaml-tmLanguage create mode 100755 extras/grammar/HCLExpression.json-tmLanguage create mode 100755 extras/grammar/HCLExpression.tmLanguage create mode 100644 extras/grammar/HCLExpression.yaml-tmLanguage create mode 100755 extras/grammar/HCLTemplate.json-tmLanguage create mode 100755 extras/grammar/HCLTemplate.tmLanguage create mode 100644 extras/grammar/HCLTemplate.yaml-tmLanguage create mode 100644 extras/grammar/build.go diff --git a/extras/grammar/HCL.json-tmLanguage b/extras/grammar/HCL.json-tmLanguage new file mode 100755 index 0000000..1025965 --- /dev/null +++ b/extras/grammar/HCL.json-tmLanguage @@ -0,0 +1,97 @@ +{ + "fileTypes": [ + "hcl", + "hcldec" + ], + "name": "HCL", + "patterns": [ + { + "begin": "#|//", + "captures": { + "0": { + "name": "punctuation.definition.comment.hcl" + } + }, + "comment": "Comments", + "end": "$\\n?", + "name": "comment.line.hcl" + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.hcl" + } + }, + "comment": "Block comments", + "end": "\\*/", + "name": "comment.block.hcl" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.hcl" + } + }, + "comment": "Nested Blocks", + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.hcl" + } + }, + "name": "meta.block.hcl", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "captures": { + "1": { + "name": "string.hcl punctuation.definition.string.begin.hcl" + }, + "2": { + "name": "string.value.hcl" + }, + "3": { + "name": "string.hcl punctuation.definition.string.end.hcl" + } + }, + "comment": "Quoted Block Labels", + "match": "(\")([^\"]+)(\")" + }, + { + "begin": "(\\w+)\\s*(=)\\s*", + "beginCaptures": { + "1": { + "name": "variable.other.assignment.hcl" + }, + "2": { + "name": "keyword.operator.hcl" + } + }, + "comment": "Attribute Definitions", + "end": "$", + "name": "meta.attr.hcl", + "patterns": [ + { + "include": "source.hclexpr" + } + ] + }, + { + "captures": { + "0": { + "name": "keyword.other.hcl" + } + }, + "comment": "Keywords", + "match": "[-\\w]+" + } + ], + "scopeName": "source.hcl", + "uuid": "55e8075d-e2e3-4e44-8446-744a9860e476" +} \ No newline at end of file diff --git a/extras/grammar/HCL.tmLanguage b/extras/grammar/HCL.tmLanguage new file mode 100755 index 0000000..d65d37f --- /dev/null +++ b/extras/grammar/HCL.tmLanguage @@ -0,0 +1,157 @@ + + + + + fileTypes + + hcl + hcldec + + name + HCL + patterns + + + begin + #|// + captures + + 0 + + name + punctuation.definition.comment.hcl + + + comment + Comments + end + $\n? + name + comment.line.hcl + + + begin + /\* + captures + + 0 + + name + punctuation.definition.comment.hcl + + + comment + Block comments + end + \*/ + name + comment.block.hcl + + + begin + { + beginCaptures + + 0 + + name + punctuation.definition.block.hcl + + + comment + Nested Blocks + end + } + endCaptures + + 0 + + name + punctuation.definition.block.hcl + + + name + meta.block.hcl + patterns + + + include + $self + + + + + captures + + 1 + + name + string.hcl punctuation.definition.string.begin.hcl + + 2 + + name + string.value.hcl + + 3 + + name + string.hcl punctuation.definition.string.end.hcl + + + comment + Quoted Block Labels + match + (")([^"]+)(") + + + begin + (\w+)\s*(=)\s* + beginCaptures + + 1 + + name + variable.other.assignment.hcl + + 2 + + name + keyword.operator.hcl + + + comment + Attribute Definitions + end + $ + name + meta.attr.hcl + patterns + + + include + source.hclexpr + + + + + captures + + 0 + + name + keyword.other.hcl + + + comment + Keywords + match + [-\w]+ + + + scopeName + source.hcl + uuid + 55e8075d-e2e3-4e44-8446-744a9860e476 + + \ No newline at end of file diff --git a/extras/grammar/HCL.yaml-tmLanguage b/extras/grammar/HCL.yaml-tmLanguage new file mode 100644 index 0000000..0a23cfa --- /dev/null +++ b/extras/grammar/HCL.yaml-tmLanguage @@ -0,0 +1,53 @@ +name: HCL +scopeName: source.hcl +fileTypes: [hcl, hcldec] +uuid: 55e8075d-e2e3-4e44-8446-744a9860e476 + +patterns: + +- comment: Comments + name: comment.line.hcl + begin: '#|//' + end: $\n? + captures: + '0': {name: punctuation.definition.comment.hcl} + +- comment: Block comments + name: comment.block.hcl + begin: /\* + end: \*/ + captures: + '0': {name: punctuation.definition.comment.hcl} + +- comment: Nested Blocks + name: meta.block.hcl + begin: "{" + beginCaptures: + '0': {name: punctuation.definition.block.hcl} + end: "}" + endCaptures: + '0': {name: punctuation.definition.block.hcl} + patterns: + - include: "$self" + +- comment: Quoted Block Labels + match: '(")([^"]+)(")' + captures: + '1': {name: string.hcl punctuation.definition.string.begin.hcl} + '2': {name: string.value.hcl} + '3': {name: string.hcl punctuation.definition.string.end.hcl} + +- comment: Attribute Definitions + name: meta.attr.hcl + begin: '(\w+)\s*(=)\s*' + beginCaptures: + '1': {name: variable.other.assignment.hcl} + '2': {name: keyword.operator.hcl} + end: '$' + patterns: + - include: "source.hclexpr" + +- comment: Keywords + match: '[-\w]+' + captures: + '0': {name: keyword.other.hcl} diff --git a/extras/grammar/HCLExpression.json-tmLanguage b/extras/grammar/HCLExpression.json-tmLanguage new file mode 100755 index 0000000..91886c8 --- /dev/null +++ b/extras/grammar/HCLExpression.json-tmLanguage @@ -0,0 +1,212 @@ +{ + "fileTypes": [], + "name": "HCL Expression", + "patterns": [ + { + "begin": "#|//", + "captures": { + "0": { + "name": "punctuation.definition.comment.hcl" + } + }, + "comment": "Comments", + "end": "$\\n?", + "name": "comment.line.hcl" + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.hcl" + } + }, + "comment": "Block comments", + "end": "\\*/", + "name": "comment.block.hcl" + }, + { + "comment": "Language constants (true, false, null)", + "match": "\\b(true|false|null)\\b", + "name": "constant.language.hcl" + }, + { + "comment": "Numbers", + "match": "\\b([0-9]+)(.[0-9]+)?([eE][0-9]+)?\\b", + "name": "constant.numeric.hcl" + }, + { + "begin": "([-\\w]+)(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.function.inline.hcl" + }, + "2": { + "name": "keyword.other.section.begin.hcl" + } + }, + "comment": "Function Calls", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "keyword.other.section.end.hcl" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "captures": { + "0": { + "name": "variable.other.hcl" + } + }, + "comment": "Variables and Attribute Names", + "match": "[-\\w]+" + }, + { + "begin": "(?\u003e\\s*\u003c\u003c(\\w+))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.hcl" + }, + "1": { + "name": "keyword.operator.heredoc.hcl" + } + }, + "comment": "Heredoc Templates", + "end": "^\\s*\\1$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.hcl keyword.operator.heredoc.hcl" + } + }, + "patterns": [ + { + "include": "source.hcltemplate" + } + ] + }, + { + "begin": "\\\"", + "beginCaptures": { + "0": { + "name": "string.hcl punctuation.definition.string.begin.hcl" + } + }, + "comment": "String Templates", + "end": "\\\"", + "endCaptures": { + "0": { + "name": "string.hcl punctuation.definition.string.end.hcl" + } + }, + "patterns": [ + { + "include": "source.hcltemplate" + }, + { + "match": "(^\"|$\\{|%\\{)+", + "name": "string.quoted.double.hcl" + } + ] + }, + { + "captures": { + "0": { + "name": "keyword.operator.hcl" + } + }, + "comment": "Operators", + "match": "(!=|==|\u003e=|\u003c=|\u0026\u0026|\\|\\||[-+*/%\u003c\u003e!?:])" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.hcl" + } + }, + "comment": "Parentheses", + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.hcl" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "meta.brace.square.hcl" + } + }, + "comment": "Tuple Constructor", + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.hcl" + } + }, + "patterns": [ + { + "captures": { + "0": { + "name": "keyword.control.hcl" + } + }, + "match": "(for|in)" + }, + { + "include": "$self" + } + ] + }, + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "meta.brace.curly.hcl" + } + }, + "comment": "Object Constructor", + "end": "\\}", + "endCaptures": { + "0": { + "name": "meta.brace.curly.hcl" + } + }, + "patterns": [ + { + "captures": { + "0": { + "name": "keyword.control.hcl" + } + }, + "match": "(for|in)" + }, + { + "captures": { + "0": { + "name": "keyword.operator.hcl" + } + }, + "match": "(=\u003e|\\.\\.\\.)" + }, + { + "include": "$self" + } + ] + } + ], + "scopeName": "source.hclexpr", + "uuid": "6c358551-0381-4128-9ea3-277b21943b5c" +} \ No newline at end of file diff --git a/extras/grammar/HCLExpression.tmLanguage b/extras/grammar/HCLExpression.tmLanguage new file mode 100755 index 0000000..3a5bb83 --- /dev/null +++ b/extras/grammar/HCLExpression.tmLanguage @@ -0,0 +1,336 @@ + + + + + fileTypes + + + name + HCL Expression + patterns + + + begin + #|// + captures + + 0 + + name + punctuation.definition.comment.hcl + + + comment + Comments + end + $\n? + name + comment.line.hcl + + + begin + /\* + captures + + 0 + + name + punctuation.definition.comment.hcl + + + comment + Block comments + end + \*/ + name + comment.block.hcl + + + comment + Language constants (true, false, null) + match + \b(true|false|null)\b + name + constant.language.hcl + + + comment + Numbers + match + \b([0-9]+)(.[0-9]+)?([eE][0-9]+)?\b + name + constant.numeric.hcl + + + begin + ([-\w]+)(\() + beginCaptures + + 1 + + name + keyword.other.function.inline.hcl + + 2 + + name + keyword.other.section.begin.hcl + + + comment + Function Calls + end + (\)) + endCaptures + + 1 + + name + keyword.other.section.end.hcl + + + patterns + + + include + $self + + + + + captures + + 0 + + name + variable.other.hcl + + + comment + Variables and Attribute Names + match + [-\w]+ + + + begin + (?>\s*<<(\w+)) + beginCaptures + + 0 + + name + punctuation.definition.string.begin.hcl + + 1 + + name + keyword.operator.heredoc.hcl + + + comment + Heredoc Templates + end + ^\s*\1$ + endCaptures + + 0 + + name + punctuation.definition.string.end.hcl keyword.operator.heredoc.hcl + + + patterns + + + include + source.hcltemplate + + + + + begin + \" + beginCaptures + + 0 + + name + string.hcl punctuation.definition.string.begin.hcl + + + comment + String Templates + end + \" + endCaptures + + 0 + + name + string.hcl punctuation.definition.string.end.hcl + + + patterns + + + include + source.hcltemplate + + + match + (^"|$\{|%\{)+ + name + string.quoted.double.hcl + + + + + captures + + 0 + + name + keyword.operator.hcl + + + comment + Operators + match + (!=|==|>=|<=|&&|\|\||[-+*/%<>!?:]) + + + begin + \( + beginCaptures + + 0 + + name + meta.brace.round.hcl + + + comment + Parentheses + end + \) + endCaptures + + 0 + + name + meta.brace.round.hcl + + + patterns + + + include + $self + + + + + begin + \[ + beginCaptures + + 0 + + name + meta.brace.square.hcl + + + comment + Tuple Constructor + end + \] + endCaptures + + 0 + + name + meta.brace.square.hcl + + + patterns + + + captures + + 0 + + name + keyword.control.hcl + + + match + (for|in) + + + include + $self + + + + + begin + \{ + beginCaptures + + 0 + + name + meta.brace.curly.hcl + + + comment + Object Constructor + end + \} + endCaptures + + 0 + + name + meta.brace.curly.hcl + + + patterns + + + captures + + 0 + + name + keyword.control.hcl + + + match + (for|in) + + + captures + + 0 + + name + keyword.operator.hcl + + + match + (=>|\.\.\.) + + + include + $self + + + + + scopeName + source.hclexpr + uuid + 6c358551-0381-4128-9ea3-277b21943b5c + + \ No newline at end of file diff --git a/extras/grammar/HCLExpression.yaml-tmLanguage b/extras/grammar/HCLExpression.yaml-tmLanguage new file mode 100644 index 0000000..c8ba5c1 --- /dev/null +++ b/extras/grammar/HCLExpression.yaml-tmLanguage @@ -0,0 +1,111 @@ +name: HCL Expression +scopeName: source.hclexpr +fileTypes: [] +uuid: 6c358551-0381-4128-9ea3-277b21943b5c + +patterns: + +- comment: Comments + name: comment.line.hcl + begin: '#|//' + end: $\n? + captures: + '0': {name: punctuation.definition.comment.hcl} + +- comment: Block comments + name: comment.block.hcl + begin: /\* + end: \*/ + captures: + '0': {name: punctuation.definition.comment.hcl} + +- comment: Language constants (true, false, null) + name: constant.language.hcl + match: \b(true|false|null)\b + +- comment: Numbers + name: constant.numeric.hcl + match: \b([0-9]+)(.[0-9]+)?([eE][0-9]+)?\b + +- comment: Function Calls + begin: ([-\w]+)(\() + beginCaptures: + '1': {name: keyword.other.function.inline.hcl} + '2': {name: keyword.other.section.begin.hcl} + end: (\)) + endCaptures: + '1': {name: keyword.other.section.end.hcl} + patterns: + - include: '$self' + +- comment: Variables and Attribute Names + match: '[-\w]+' + captures: + '0': {name: variable.other.hcl} + +- comment: Heredoc Templates + begin: (?>\s*<<(\w+)) + beginCaptures: + '0': {name: punctuation.definition.string.begin.hcl} + '1': {name: keyword.operator.heredoc.hcl} + end: ^\s*\1$ + endCaptures: + '0': {name: punctuation.definition.string.end.hcl keyword.operator.heredoc.hcl} + patterns: + - include: 'source.hcltemplate' + +- comment: String Templates + begin: \" + beginCaptures: + '0': {name: string.hcl punctuation.definition.string.begin.hcl} + end: \" + endCaptures: + '0': {name: string.hcl punctuation.definition.string.end.hcl} + patterns: + - include: 'source.hcltemplate' + - match: '(^"|$\{|%\{)+' + name: "string.quoted.double.hcl" + +- comment: Operators + match: '(!=|==|>=|<=|&&|\|\||[-+*/%<>!?:])' + captures: + '0': {name: keyword.operator.hcl} + +- comment: Parentheses + begin: '\(' + beginCaptures: + '0': {name: meta.brace.round.hcl} + end: '\)' + endCaptures: + '0': {name: meta.brace.round.hcl} + patterns: + - include: '$self' + +- comment: Tuple Constructor + begin: '\[' + beginCaptures: + '0': {name: meta.brace.square.hcl} + end: '\]' + endCaptures: + '0': {name: meta.brace.square.hcl} + patterns: + - match: '(for|in)' + captures: + '0': {name: keyword.control.hcl} + - include: '$self' + +- comment: Object Constructor + begin: '\{' + beginCaptures: + '0': {name: meta.brace.curly.hcl} + end: '\}' + endCaptures: + '0': {name: meta.brace.curly.hcl} + patterns: + - match: '(for|in)' + captures: + '0': {name: keyword.control.hcl} + - match: '(=>|\.\.\.)' + captures: + '0': {name: keyword.operator.hcl} + - include: '$self' diff --git a/extras/grammar/HCLTemplate.json-tmLanguage b/extras/grammar/HCLTemplate.json-tmLanguage new file mode 100755 index 0000000..6d002c1 --- /dev/null +++ b/extras/grammar/HCLTemplate.json-tmLanguage @@ -0,0 +1,107 @@ +{ + "fileTypes": [ + "tmpl" + ], + "name": "HCL Template", + "patterns": [ + { + "begin": "[^\\$]?(\\$\\{~?)", + "beginCaptures": { + "1": { + "name": "entity.tag.embedded.start.hcltemplate" + } + }, + "comment": "Interpolation Sequences", + "end": "~?}", + "endCaptures": { + "0": { + "name": "entity.tag.embedded.end.hcltemplate" + } + }, + "name": "meta.interp.hcltemplate", + "patterns": [ + { + "include": "source.hclexpr" + } + ] + }, + { + "begin": "[^\\%]?(\\%\\{~?)", + "beginCaptures": { + "1": { + "name": "entity.tag.embedded.start.hcltemplate" + } + }, + "comment": "Control Sequences", + "end": "~?}", + "endCaptures": { + "0": { + "name": "entity.tag.embedded.end.hcltemplate" + } + }, + "name": "meta.control.hcltemplate", + "patterns": [ + { + "include": "#templateif" + }, + { + "include": "#templatefor" + }, + { + "include": "#templatesimplekw" + } + ] + } + ], + "repository": { + "templatefor": { + "begin": "(for)\\s*(\\w+)\\s*(,\\s*(\\w+)\\s*)?(in)", + "beginCaptures": { + "1": { + "name": "keyword.control.hcltemplate" + }, + "2": { + "name": "variable.other.hcl" + }, + "4": { + "name": "variable.other.hcl" + }, + "5": { + "name": "keyword.control.hcltemplate" + } + }, + "end": "(?=~?\\})", + "name": "meta.templatefor.hcltemplate", + "patterns": [ + { + "include": "source.hclexpr" + } + ] + }, + "templateif": { + "begin": "(if)\\s*", + "beginCaptures": { + "1": { + "name": "keyword.control.hcltemplate" + } + }, + "end": "(?=~?\\})", + "name": "meta.templateif.hcltemplate", + "patterns": [ + { + "include": "source.hclexpr" + } + ] + }, + "templatesimplekw": { + "captures": { + "0": { + "name": "keyword.control.hcl" + } + }, + "match": "(else|endif|endfor)" + } + }, + "scopeName": "source.hcltemplate", + "uuid": "ac6be18e-d44f-4a73-bd8f-b973fd26df05" +} \ No newline at end of file diff --git a/extras/grammar/HCLTemplate.tmLanguage b/extras/grammar/HCLTemplate.tmLanguage new file mode 100755 index 0000000..6c05359 --- /dev/null +++ b/extras/grammar/HCLTemplate.tmLanguage @@ -0,0 +1,172 @@ + + + + + fileTypes + + tmpl + + name + HCL Template + patterns + + + begin + [^\$]?(\$\{~?) + beginCaptures + + 1 + + name + entity.tag.embedded.start.hcltemplate + + + comment + Interpolation Sequences + end + ~?} + endCaptures + + 0 + + name + entity.tag.embedded.end.hcltemplate + + + name + meta.interp.hcltemplate + patterns + + + include + source.hclexpr + + + + + begin + [^\%]?(\%\{~?) + beginCaptures + + 1 + + name + entity.tag.embedded.start.hcltemplate + + + comment + Control Sequences + end + ~?} + endCaptures + + 0 + + name + entity.tag.embedded.end.hcltemplate + + + name + meta.control.hcltemplate + patterns + + + include + #templateif + + + include + #templatefor + + + include + #templatesimplekw + + + + + repository + + templatefor + + begin + (for)\s*(\w+)\s*(,\s*(\w+)\s*)?(in) + beginCaptures + + 1 + + name + keyword.control.hcltemplate + + 2 + + name + variable.other.hcl + + 4 + + name + variable.other.hcl + + 5 + + name + keyword.control.hcltemplate + + + end + (?=~?\}) + name + meta.templatefor.hcltemplate + patterns + + + include + source.hclexpr + + + + templateif + + begin + (if)\s* + beginCaptures + + 1 + + name + keyword.control.hcltemplate + + + end + (?=~?\}) + name + meta.templateif.hcltemplate + patterns + + + include + source.hclexpr + + + + templatesimplekw + + captures + + 0 + + name + keyword.control.hcl + + + match + (else|endif|endfor) + + + scopeName + source.hcltemplate + uuid + ac6be18e-d44f-4a73-bd8f-b973fd26df05 + + \ No newline at end of file diff --git a/extras/grammar/HCLTemplate.yaml-tmLanguage b/extras/grammar/HCLTemplate.yaml-tmLanguage new file mode 100644 index 0000000..bd4f99f --- /dev/null +++ b/extras/grammar/HCLTemplate.yaml-tmLanguage @@ -0,0 +1,58 @@ +name: HCL Template +scopeName: source.hcltemplate +fileTypes: [tmpl] +uuid: ac6be18e-d44f-4a73-bd8f-b973fd26df05 + +patterns: + +- comment: Interpolation Sequences + name: meta.interp.hcltemplate + begin: '[^\$]?(\$\{~?)' + beginCaptures: + '1': {name: entity.tag.embedded.start.hcltemplate} + end: '~?}' + endCaptures: + '0': {name: entity.tag.embedded.end.hcltemplate} + patterns: + - include: "source.hclexpr" + +- comment: Control Sequences + name: meta.control.hcltemplate + begin: '[^\%]?(\%\{~?)' + beginCaptures: + '1': {name: entity.tag.embedded.start.hcltemplate} + end: '~?}' + endCaptures: + '0': {name: entity.tag.embedded.end.hcltemplate} + patterns: + - include: "#templateif" + - include: "#templatefor" + - include: "#templatesimplekw" + +repository: + + templateif: + name: meta.templateif.hcltemplate + begin: '(if)\s*' + beginCaptures: + '1': {name: keyword.control.hcltemplate} + end: '(?=~?\})' + patterns: + - include: "source.hclexpr" + + templatefor: + name: meta.templatefor.hcltemplate + begin: '(for)\s*(\w+)\s*(,\s*(\w+)\s*)?(in)' + beginCaptures: + '1': {name: keyword.control.hcltemplate} + '2': {name: variable.other.hcl} + '4': {name: variable.other.hcl} + '5': {name: keyword.control.hcltemplate} + end: '(?=~?\})' + patterns: + - include: "source.hclexpr" + + templatesimplekw: + match: (else|endif|endfor) + captures: + '0': {name: keyword.control.hcl} diff --git a/extras/grammar/build.go b/extras/grammar/build.go new file mode 100644 index 0000000..224550d --- /dev/null +++ b/extras/grammar/build.go @@ -0,0 +1,119 @@ +// This is a helper to transform the HCL.yaml-tmLanguage file (the source of +// record) into both HCL.json-tmLanguage and HCL.tmLanguage (in plist XML +// format). +// +// Run this after making updates to HCL.yaml-tmLanguage to generate the other +// formats. +// +// This file is intended to be run with "go run": +// +// go run ./build.go +// +// This file is also set up to run itself under "go generate": +// +// go generate . + +package main + +//go:generate go run ./build.go + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + + plist "github.com/DHowett/go-plist" + yaml "gopkg.in/yaml.v2" + + multierror "github.com/hashicorp/go-multierror" +) + +func main() { + err := realMain() + if err != nil { + log.Fatal(err) + } + os.Exit(0) +} + +func realMain() error { + var err error + buildErr := build("HCL") + if buildErr != nil { + err = multierror.Append(err, fmt.Errorf("in HCL: %s", buildErr)) + } + buildErr = build("HCLTemplate") + if buildErr != nil { + err = multierror.Append(err, fmt.Errorf("in HCLTemplate: %s", buildErr)) + } + buildErr = build("HCLExpression") + if buildErr != nil { + err = multierror.Append(err, fmt.Errorf("in HCLExpression: %s", buildErr)) + } + return err +} + +func build(basename string) error { + yamlSrc, err := ioutil.ReadFile(basename + ".yaml-tmLanguage") + if err != nil { + return err + } + + var content interface{} + err = yaml.Unmarshal(yamlSrc, &content) + if err != nil { + return err + } + + // Normalize the value so it's both JSON- and plist-friendly. + content = prepare(content) + + jsonSrc, err := json.MarshalIndent(content, "", " ") + if err != nil { + return err + } + + plistSrc, err := plist.MarshalIndent(content, plist.XMLFormat, " ") + if err != nil { + return err + } + + err = ioutil.WriteFile(basename+".json-tmLanguage", jsonSrc, os.ModePerm) + if err != nil { + return err + } + + err = ioutil.WriteFile(basename+".tmLanguage", plistSrc, os.ModePerm) + if err != nil { + return err + } + + return nil +} + +func prepare(v interface{}) interface{} { + switch tv := v.(type) { + + case map[interface{}]interface{}: + var ret map[string]interface{} + if len(tv) == 0 { + return ret + } + ret = make(map[string]interface{}, len(tv)) + for k, v := range tv { + ret[k.(string)] = prepare(v) + } + return ret + + case []interface{}: + for i := range tv { + tv[i] = prepare(tv[i]) + } + return tv + + default: + return v + } +}