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.
This commit is contained in:
Martin Atkins 2018-07-07 12:36:32 -07:00
parent 6558d83419
commit 1718a963e6
10 changed files with 1422 additions and 0 deletions

View File

@ -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"
}

157
extras/grammar/HCL.tmLanguage Executable file
View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>hcl</string>
<string>hcldec</string>
</array>
<key>name</key>
<string>HCL</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string>#|//</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Comments</string>
<key>end</key>
<string>$\n?</string>
<key>name</key>
<string>comment.line.hcl</string>
</dict>
<dict>
<key>begin</key>
<string>/\*</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Block comments</string>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.hcl</string>
</dict>
<dict>
<key>begin</key>
<string>{</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.block.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Nested Blocks</string>
<key>end</key>
<string>}</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.block.hcl</string>
</dict>
</dict>
<key>name</key>
<string>meta.block.hcl</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>$self</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>string.hcl punctuation.definition.string.begin.hcl</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>string.value.hcl</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>string.hcl punctuation.definition.string.end.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Quoted Block Labels</string>
<key>match</key>
<string>(&#34;)([^&#34;]+)(&#34;)</string>
</dict>
<dict>
<key>begin</key>
<string>(\w+)\s*(=)\s*</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.other.assignment.hcl</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>keyword.operator.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Attribute Definitions</string>
<key>end</key>
<string>$</string>
<key>name</key>
<string>meta.attr.hcl</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hclexpr</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.other.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Keywords</string>
<key>match</key>
<string>[-\w]+</string>
</dict>
</array>
<key>scopeName</key>
<string>source.hcl</string>
<key>uuid</key>
<string>55e8075d-e2e3-4e44-8446-744a9860e476</string>
</dict>
</plist>

View File

@ -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}

View File

@ -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"
}

View File

@ -0,0 +1,336 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
</array>
<key>name</key>
<string>HCL Expression</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string>#|//</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Comments</string>
<key>end</key>
<string>$\n?</string>
<key>name</key>
<string>comment.line.hcl</string>
</dict>
<dict>
<key>begin</key>
<string>/\*</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Block comments</string>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.hcl</string>
</dict>
<dict>
<key>comment</key>
<string>Language constants (true, false, null)</string>
<key>match</key>
<string>\b(true|false|null)\b</string>
<key>name</key>
<string>constant.language.hcl</string>
</dict>
<dict>
<key>comment</key>
<string>Numbers</string>
<key>match</key>
<string>\b([0-9]+)(.[0-9]+)?([eE][0-9]+)?\b</string>
<key>name</key>
<string>constant.numeric.hcl</string>
</dict>
<dict>
<key>begin</key>
<string>([-\w]+)(\()</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.other.function.inline.hcl</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>keyword.other.section.begin.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Function Calls</string>
<key>end</key>
<string>(\))</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.other.section.end.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>$self</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>variable.other.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Variables and Attribute Names</string>
<key>match</key>
<string>[-\w]+</string>
</dict>
<dict>
<key>begin</key>
<string>(?&gt;\s*&lt;&lt;(\w+))</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.hcl</string>
</dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.operator.heredoc.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Heredoc Templates</string>
<key>end</key>
<string>^\s*\1$</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.hcl keyword.operator.heredoc.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hcltemplate</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>\&#34;</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>string.hcl punctuation.definition.string.begin.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>String Templates</string>
<key>end</key>
<string>\&#34;</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>string.hcl punctuation.definition.string.end.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hcltemplate</string>
</dict>
<dict>
<key>match</key>
<string>(^&#34;|$\{|%\{)+</string>
<key>name</key>
<string>string.quoted.double.hcl</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.operator.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Operators</string>
<key>match</key>
<string>(!=|==|&gt;=|&lt;=|&amp;&amp;|\|\||[-+*/%&lt;&gt;!?:])</string>
</dict>
<dict>
<key>begin</key>
<string>\(</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.round.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Parentheses</string>
<key>end</key>
<string>\)</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.round.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>$self</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>\[</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.square.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Tuple Constructor</string>
<key>end</key>
<string>\]</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.square.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.control.hcl</string>
</dict>
</dict>
<key>match</key>
<string>(for|in)</string>
</dict>
<dict>
<key>include</key>
<string>$self</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>\{</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.curly.hcl</string>
</dict>
</dict>
<key>comment</key>
<string>Object Constructor</string>
<key>end</key>
<string>\}</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>meta.brace.curly.hcl</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.control.hcl</string>
</dict>
</dict>
<key>match</key>
<string>(for|in)</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.operator.hcl</string>
</dict>
</dict>
<key>match</key>
<string>(=&gt;|\.\.\.)</string>
</dict>
<dict>
<key>include</key>
<string>$self</string>
</dict>
</array>
</dict>
</array>
<key>scopeName</key>
<string>source.hclexpr</string>
<key>uuid</key>
<string>6c358551-0381-4128-9ea3-277b21943b5c</string>
</dict>
</plist>

View File

@ -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'

View File

@ -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"
}

View File

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>tmpl</string>
</array>
<key>name</key>
<string>HCL Template</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string>[^\$]?(\$\{~?)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.tag.embedded.start.hcltemplate</string>
</dict>
</dict>
<key>comment</key>
<string>Interpolation Sequences</string>
<key>end</key>
<string>~?}</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>entity.tag.embedded.end.hcltemplate</string>
</dict>
</dict>
<key>name</key>
<string>meta.interp.hcltemplate</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hclexpr</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>[^\%]?(\%\{~?)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.tag.embedded.start.hcltemplate</string>
</dict>
</dict>
<key>comment</key>
<string>Control Sequences</string>
<key>end</key>
<string>~?}</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>entity.tag.embedded.end.hcltemplate</string>
</dict>
</dict>
<key>name</key>
<string>meta.control.hcltemplate</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#templateif</string>
</dict>
<dict>
<key>include</key>
<string>#templatefor</string>
</dict>
<dict>
<key>include</key>
<string>#templatesimplekw</string>
</dict>
</array>
</dict>
</array>
<key>repository</key>
<dict>
<key>templatefor</key>
<dict>
<key>begin</key>
<string>(for)\s*(\w+)\s*(,\s*(\w+)\s*)?(in)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.control.hcltemplate</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>variable.other.hcl</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>variable.other.hcl</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>keyword.control.hcltemplate</string>
</dict>
</dict>
<key>end</key>
<string>(?=~?\})</string>
<key>name</key>
<string>meta.templatefor.hcltemplate</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hclexpr</string>
</dict>
</array>
</dict>
<key>templateif</key>
<dict>
<key>begin</key>
<string>(if)\s*</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.control.hcltemplate</string>
</dict>
</dict>
<key>end</key>
<string>(?=~?\})</string>
<key>name</key>
<string>meta.templateif.hcltemplate</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>source.hclexpr</string>
</dict>
</array>
</dict>
<key>templatesimplekw</key>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>keyword.control.hcl</string>
</dict>
</dict>
<key>match</key>
<string>(else|endif|endfor)</string>
</dict>
</dict>
<key>scopeName</key>
<string>source.hcltemplate</string>
<key>uuid</key>
<string>ac6be18e-d44f-4a73-bd8f-b973fd26df05</string>
</dict>
</plist>

View File

@ -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}

119
extras/grammar/build.go Normal file
View File

@ -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
}
}