%YAML 1.2 --- # http://www.sublimetext.com/docs/3/syntax.html # The structure and terminology of this syntax reflects the spec: # https://golang.org/ref/spec # The following is a simplified model of Sublime Text's syntax engine, reverse- # engineered through experience. This model uses assertive language for brevity, # but does not reflect the real implementation and should not be taken # literally. Still, it helps a LOT, and is necessary for understanding this # syntax. # # The engine has a stack of rulesets. The topmost frame is the current ruleset: # # rulesets: # # current # - [ # {match: '...', scope: '...'}, # {match: '...', scope: '...'}, # {match: '...', scope: '...'}, # ], # # other # - [...] # # The engine appears to use three nested loops: (1) lines, (2) character # positions, and (3) rules. # # First, the engine loops through lines. On each line, it loops through char # positions. On each char position, it loops through rules. It also loops # through rules on at least two special "positions" that don't correspond to a # character: start of line and end of line. # # For each rule, the engine runs its regex against the remainder of the line, # which may also start with ^ or consist entirely of $. Note that older syntax # engine(s) supported multiline regexes, but this has been deprecated for # performance reasons. # # Each rule may "consume" 0 to N characters, optionally assigning scopes. In # addition, the rule may modify the rule stack with `push / pop / set`. # Consuming characters advances the character loop. Consuming characters OR # modifying the rule stack also resets the RULE loop; the engine will continue # from the next character and the FIRST rule in the then-current ruleset. # # Rules that consume ZERO characters and DON'T modify the stack also DON'T reset # the rule loop. We must be mindful of this behavior. Regexes for such rules # typically look like this: (?=\S) or $. If they did reset the rule loop, it # would cause an infinite loop in the engine. # # Another potential gotcha: the engine will loop through the rules at the end of # each line, where there aren't any characters to match. The only matches are $ # or its derivatives such as (?=$). Rules intended to work across multiple # lines, for example to trim whitespace and comments, may be unexpectedly # interrupted by sibling rules with $. file_extensions: - go scope: source.go variables: # https://golang.org/ref/spec#Keywords # These are the only words that can't be used as identifiers. keyword: \b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b # https://golang.org/ref/spec#Predeclared_identifiers predeclared_type: \b(?:bool|byte|complex64|complex128|error|float32|float64|int|int8|int16|int32|int64|rune|string|uint|uint8|uint16|uint32|uint64|uintptr)\b # https://golang.org/ref/spec#Predeclared_identifiers predeclared_func: \b(?:append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)\b # Note: this matches ALL valid identifiers, including predeclared constants, # functions and types. ident: \b(?!{{keyword}})[[:alpha:]_][[:alnum:]_]*\b # Single line only inline_comment: /[*](?:[^*]|[*](?!/))*[*]/ # Whitespace and general comments on a single line. # This should only be used for lookahead, not for capturing / scoping. noise: (?:\s|{{inline_comment}})* char_escape: \\x\h{2}|\\u\h{4}|\\U\h{8}|\\[0-7]{3}|\\. dec_exponent: (?:[eE][-+]??{{dec_digits}}) hex_exponent: (?:[pP][-+]??{{dec_digits}}) # Matches a digit with any number of numeric separators, while # not allowing a numeric separator as the last or first character. dec_digits: (?:\d+(?:_\d+)*) # Hexadecimal counterpart to dec_digits. hex_digits: (?:_?\h+(?:_\h+)*) # Octal counterpart to dec_digits. oct_digits: (?:_?[0-7]+(?:_[0-7]+)*) # Binary counterpart to dec_digits. bin_digits: (?:_?[01]+(?:_[01]+)*) # Matches a digit with any number of numeric separators, while # not allowing a numeric separator as the last or first character. ddigits: (?:\d+(?:_\d+)*) # Hexadecimal counterpart to ddigits. hdigits: _?(?:\h+(?:_\h+)*) # Same as hdigits, except the leading hex character # coefficient is optional in this case. ohdigits: _?(?:\h*(?:_\h+)*) # Octal counterpart to ddigits. odigits: _?(?:[0-7]+(?:_[0-7]+)*) # Binary counterpart to ddigits. bdigits: _?(?:[01]+(?:_[01]+)*) contexts: main: - include: match-any match-any: - include: match-comments - include: match-tokens # https://golang.org/ref/spec#Comments match-comments: # Go has magic comments in the form of: # # //go:some_directive arg0 arg1 ... # # They're not part of the language spec, may not be recognized by some Go # compilers, and may stop working in future releases. Therefore, # highlighting them as compiler pragmas could be misleading. We scope them # as plain comments by default, and add some detailed meta scopes for # enterprising users wishing to add more color. - match: (//)(go)(:)({{ident}})? captures: 1: punctuation.definition.comment.go 2: meta.keyword.annotation.go 3: meta.punctuation.accessor.colon.go 4: meta.variable.function.go push: - meta_scope: comment.line.go meta.annotation.go - match: \S+ scope: meta.variable.parameter.go # End the annotation scope at EOL, but stretch the comment scope # indefinitely to the right. - match: $ set: pop-line-comment # Line comment - match: // scope: punctuation.definition.comment.go push: pop-line-comment # General comment - match: /\* scope: punctuation.definition.comment.begin.go push: - meta_scope: comment.block.go - match: \*/ scope: punctuation.definition.comment.end.go pop: true - match: ^\s*(\*)(?!/) captures: 1: punctuation.definition.comment.go pop-line-comment: - meta_scope: comment.line.go # Including the newline allows the scope to visually stretch to the right, # and ensures that functionality that relies on comment scoping, such as # contextual hotkeys, works properly at EOL while typing a comment. This # should also match \r\n due to Sublime's internal normalization. - match: $\n? pop: true # https://golang.org/ref/spec#Tokens match-tokens: - include: match-keywords - include: match-identifiers - include: match-literals - include: match-operators - include: match-punctuation # https://golang.org/ref/spec#Keywords match-keywords: - include: match-keyword-break - include: match-keyword-case - include: match-keyword-chan - include: match-keyword-const - include: match-keyword-continue - include: match-keyword-default - include: match-keyword-defer - include: match-keyword-else - include: match-keyword-fallthrough - include: match-keyword-for - include: match-keyword-func - include: match-keyword-go - include: match-keyword-goto - include: match-keyword-if - include: match-keyword-import - include: match-keyword-interface - include: match-keyword-map - include: match-keyword-package - include: match-keyword-range - include: match-keyword-return - include: match-keyword-select - include: match-keyword-struct - include: match-keyword-switch - include: match-keyword-type - include: match-keyword-var # See `match-selector` for field scoping. match-identifiers: - include: match-predeclared-constants - include: match-call-or-cast - include: match-short-variable-declarations - match: \b_\b scope: variable.language.blank.go - match: '{{ident}}' scope: variable.other.go # https://golang.org/ref/spec#Predeclared_identifiers # # In Go, the predeclared constants are not keywords, and can be redefined. In # many places such as variable declarations, types, function names, etc, we # allow them to be scoped the same way as other identifiers. This "constant" # rule should be used in places that are "left over". Detecting redefinition # would be ideal, but is beyond the scope of this syntax engine; we simply # expect it to be very rare. match-predeclared-constants: - match: \b(?:true|false|nil)\b scope: constant.language.go # Note: in Go, calls and casts are syntactically identical. Detecting casts # and scoping them as types is beyond the capabilities of this syntax engine. # # https://golang.org/ref/spec#Predeclared_identifiers # # Notes on built-in functions # # Most built-in functions don't need special syntactic support. We scope them # for the benefit of the users who prefer to distinguish them from # user-defined identifiers. Two exceptions are `make` and `new`, where the # first argument is scoped as a type, matching the special-case support in # the compiler. When built-ins are redefined, this leads to incorrect # scoping; like with constants, we expect such redefinition to be very rare. # # Note that we limit this detection to plain function calls, ignoring method # calls and other identifier occurrences. The language currently allows # built-in functions ONLY in a function call position. This helps minimize # false positives. # # Notes on built-in types # # Unlike casts involving a user-defined type, casts involving a built-in # types could be scoped purely as types rather than function calls. However, # we stick to `variable.function.go` to make the treatment of built-ins # purely additive, allowing the user to opt out. match-call-or-cast: - match: \b(?:make|new)\b(?=(?:{{noise}}\))*{{noise}}\() scope: variable.function.go support.function.builtin.go push: pop-arguments-starting-with-type - match: '{{predeclared_type}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go support.type.builtin.go - match: '{{predeclared_func}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go support.function.builtin.go - match: '{{ident}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go # See notes on `match-call-or-cast`. pop-call-or-cast: - match: \b(?:make|new)\b(?=(?:{{noise}}\))*{{noise}}\() scope: variable.function.go support.function.builtin.go set: pop-arguments-starting-with-type - match: '{{predeclared_type}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go support.type.builtin.go pop: true - match: '{{predeclared_func}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go support.function.builtin.go pop: true - match: '{{ident}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go pop: true # Note: this currently doesn't work across multiple lines. match-short-variable-declarations: - match: (?={{ident}}(?:{{noise}},{{noise}}{{ident}})*{{noise}}:=) push: - include: match-comments - match: \b_\b scope: variable.language.blank.go - match: '{{ident}}' scope: variable.declaration.go - include: match-comma - include: pop-before-nonblank # https://golang.org/ref/spec#Operators_and_punctuation match-operators: [ {match: \!= , scope: keyword.operator.go}, {match: \! , scope: keyword.operator.go}, {match: \%= , scope: keyword.operator.assignment.go}, {match: \% , scope: keyword.operator.go}, {match: \&& , scope: keyword.operator.go}, {match: \&= , scope: keyword.operator.assignment.go}, {match: \&^= , scope: keyword.operator.assignment.go}, {match: \&^ , scope: keyword.operator.go}, {match: \& , scope: keyword.operator.go}, {match: \*= , scope: keyword.operator.assignment.go}, {match: \* , scope: keyword.operator.go}, {match: \+\+ , scope: keyword.operator.go}, {match: \+= , scope: keyword.operator.assignment.go}, {match: \+ , scope: keyword.operator.go}, {match: -- , scope: keyword.operator.assignment.go}, {match: -= , scope: keyword.operator.assignment.go}, {match: \- , scope: keyword.operator.go}, {match: /= , scope: keyword.operator.assignment.go}, {match: / , scope: keyword.operator.go}, {match: := , scope: keyword.operator.assignment.go}, {match: <- , scope: keyword.operator.go}, {match: < , scope: keyword.operator.go}, {match: <<= , scope: keyword.operator.assignment.go}, {match: \<< , scope: keyword.operator.go}, {match: <= , scope: keyword.operator.go}, {match: == , scope: keyword.operator.go}, {match: \= , scope: keyword.operator.assignment.go}, {match: \>= , scope: keyword.operator.assignment.go}, {match: \>>= , scope: keyword.operator.assignment.go}, {match: \>> , scope: keyword.operator.go}, {match: \> , scope: keyword.operator.go}, {match: \^= , scope: keyword.operator.assignment.go}, {match: \^ , scope: keyword.operator.go}, {match: \|= , scope: keyword.operator.assignment.go}, {match: \|\| , scope: keyword.operator.go}, {match: \| , scope: keyword.operator.go}, ] match-star: - match: \* scope: keyword.operator.go # https://golang.org/ref/spec#Operators_and_punctuation match-punctuation: - include: match-comma - include: match-ellipsis - include: match-colon - include: match-semicolon - include: match-selector - include: match-parens - include: match-brackets - include: match-braces match-comma: - match: \, scope: punctuation.separator.go match-ellipsis: - match: \.\.\. scope: keyword.operator.variadic.go match-colon: - match: ':' scope: punctuation.separator.go match-semicolon: - match: ; scope: punctuation.terminator.go match-selector: - match: \. scope: punctuation.accessor.dot.go push: - include: match-comments - include: pop-type-assertion # Note: calls and casts are syntactically identical. - match: '{{ident}}(?=(?:{{noise}}\))*{{noise}}\()' scope: variable.function.go pop: true - include: pop-member # Note: newlines between dot and assertion/field are ok - include: pop-before-nonblank match-parens: - match: \( scope: punctuation.section.parens.begin.go push: - match: \) scope: punctuation.section.parens.end.go pop: true - include: pop-call-or-cast - include: match-any - match: \) scope: punctuation.section.parens.end.go match-brackets: - match: \[ scope: punctuation.section.brackets.begin.go - match: \] scope: punctuation.section.brackets.end.go push: - include: pop-on-terminator - include: match-comments - include: match-star - match: '{{ident}}(?={{noise}}\.)' scope: variable.other.go - match: \b_\b scope: variable.language.blank.go pop: true - include: pop-type-identifier - include: pop-before-nonblank match-braces: - match: \{ scope: punctuation.section.braces.begin.go push: - meta_scope: meta.block.go - match: \} scope: punctuation.section.braces.end.go pop: true - include: match-any - match: \} scope: punctuation.section.braces.end.go match-literals: - include: match-imaginary - include: match-floats - include: match-integers - include: match-runes - include: match-strings match-imaginary: # Decimal imaginary numbers - match: '{{dec_digits}}(?:(\.){{dec_digits}}?)?{{dec_exponent}}?(i)' scope: constant.numeric.imaginary.decimal.go captures: 1: punctuation.separator.decimal.go 2: storage.type.numeric.go # Hexadecimal imaginary numbers - match: (0[xX]){{hex_digits}}?(?:(\.){{hex_digits}}?)?{{hex_exponent}}?(i) scope: constant.numeric.imaginary.hexadecimal.go captures: 1: punctuation.definition.numeric.base.go 2: punctuation.separator.decimal.go 3: storage.type.numeric.go # Octal imaginary numbers - match: (0[oO]){{oct_digits}}(i) scope: constant.numeric.imaginary.octal.go captures: 1: punctuation.definition.numeric.base.go 2: storage.type.numeric.go # Binary imaginary numbers - match: (0[bB]){{bin_digits}}(i) scope: constant.numeric.imaginary.binary.go captures: 1: punctuation.definition.numeric.base.go 2: storage.type.numeric.go match-floats: # Decimal float literal - match: |- (?x: {{dec_digits}}(?:(\.){{dec_digits}}?{{dec_exponent}}?|{{dec_exponent}}) | (\.){{dec_digits}}{{dec_exponent}}? ) scope: constant.numeric.float.decimal.go captures: 1: punctuation.separator.decimal.go 2: punctuation.separator.decimal.go # Hexadecimal float literal - match: (0[xX]){{hex_digits}}?(?:(\.){{hex_digits}}?)?{{hex_exponent}} scope: constant.numeric.float.hexadecimal.go captures: 1: punctuation.definition.numeric.base.go 2: punctuation.separator.decimal.go match-integers: - include: match-octal-integer - include: match-hex-integer - include: match-binary-integer - include: match-decimal-integer match-octal-integer: - match: (0){{oct_digits}}(?=\D) scope: constant.numeric.integer.octal.go captures: 1: punctuation.definition.numeric.base.go - match: 0[0-7]*[8-9]+ scope: invalid.illegal.go - match: (0[oO]){{oct_digits}} scope: constant.numeric.integer.octal.go captures: 1: punctuation.definition.numeric.base.go match-hex-integer: - match: (0[xX]){{hex_digits}} scope: constant.numeric.integer.hexadecimal.go captures: 1: punctuation.definition.numeric.base.go match-binary-integer: - match: (0[bB]){{bin_digits}} scope: constant.numeric.integer.binary.go captures: 1: punctuation.definition.numeric.base.go match-decimal-integer: - match: '{{dec_digits}}' scope: constant.numeric.integer.decimal.go # https://golang.org/ref/spec#Rune_literals match-runes: - match: \'({{char_escape}})' scope: constant.character.go captures: 1: constant.character.escape.go - match: \'[^']*' scope: constant.character.go match-strings: - include: match-raw-string - include: match-interpreted-string match-raw-string: - match: '`' scope: punctuation.definition.string.begin.go push: - meta_scope: string.quoted.other.go - match: '`' scope: punctuation.definition.string.end.go pop: true - include: match-template-string - match: \%% scope: constant.character.escape.go - include: match-fmt match-interpreted-string: - match: '"' scope: punctuation.definition.string.begin.go push: - meta_scope: string.quoted.double.go - match: '"' scope: punctuation.definition.string.end.go pop: true - include: match-template-string - match: '{{char_escape}}' scope: constant.character.escape.go - match: \%% scope: constant.character.escape.go - include: match-fmt match-template-string: - match: '{{(?=.*}})' scope: punctuation.section.interpolation.begin.go push: - meta_scope: meta.interpolation.go - clear_scopes: 1 - match: "}}" scope: punctuation.section.interpolation.end.go pop: true - match: "\\s-" scope: keyword.operator.template.right.trim.go - match: "-\\s" scope: keyword.operator.template.left.trim.go - match: ":=|=" scope: keyword.operator.assignment.go - match: \| scope: keyword.operator.template.pipe.go - match: '(\.)([\w]+)' captures: 1: punctuation.accessor.dot.go 2: variable.other.member.go - match: '(\$)[\w]+' scope: variable.other.template.go captures: 1: punctuation.definition.variable.go - match: '[.$]' scope: variable.other.template.go - match: \b(if|else|range|template|with|end|nil|define|block)\b scope: keyword.control.go - match: \b(and|call|html|index|slice|js|len|not|or|print|printf|println|urlquery|eq|ne|lt|le|gt|ge)\b scope: variable.function.go support.function.builtin.go - include: match-comments - include: match-strings # https://godoc.org/fmt # # Tries to match known patterns without being too specific. We want to avoid # false positives in non-fmt strings that just happen to contain %, but don't # want too much coupling with the current version of fmt. match-fmt: - match: '\%(?:\[\d+\])?[ .\d#+-]*[A-Za-z]' scope: constant.other.placeholder.go match-keyword-break: - match: \bbreak\b scope: keyword.control.go match-keyword-case: - match: \bcase\b scope: keyword.control.go match-keyword-chan: - match: (?=\bchan\b) push: pop-chan match-keyword-const: - match: \bconst\b scope: storage.type.keyword.const.go push: - match: \( scope: punctuation.section.parens.begin.go set: - match: \) scope: punctuation.section.parens.end.go pop: true - match: \b_\b(?={{noise}},) scope: variable.language.blank.go - match: '{{ident}}(?={{noise}},)' scope: variable.other.constant.declaration.go - match: \b_\b scope: variable.language.blank.go push: pop-const-type-and-or-assignment - match: '{{ident}}' scope: variable.other.constant.declaration.go push: pop-const-type-and-or-assignment - include: match-any - include: match-comments - include: match-comma - match: \b_\b(?={{noise}},) scope: variable.language.blank.go - match: '{{ident}}(?={{noise}},)' scope: variable.other.constant.declaration.go - match: \b_\b scope: variable.language.blank.go set: pop-const-type-and-or-assignment - match: '{{ident}}' scope: variable.other.constant.declaration.go set: pop-const-type-and-or-assignment - include: pop-before-nonblank match-keyword-continue: - match: \bcontinue\b scope: keyword.control.go match-keyword-default: - match: \bdefault\b scope: keyword.control.go match-keyword-defer: - match: \bdefer\b scope: keyword.control.go match-keyword-else: - match: \belse\b scope: keyword.control.go match-keyword-fallthrough: - match: \bfallthrough\b scope: keyword.control.go match-keyword-for: - match: \bfor\b scope: keyword.control.go match-keyword-func: - match: \bfunc\b scope: storage.type.keyword.function.go push: - include: match-comments # Method - match: (?=\({{noise}}[^)]+{{noise}}\){{noise}}{{ident}}{{noise}}\() set: - meta_scope: meta.function.declaration.go - match: (?=[^(]) set: - meta_scope: meta.function.declaration.go - include: pop-func-signature # Receiver list - match: (?=\() push: pop-func-parameter-list # Named function - match: (?={{ident}}{{noise}}\() set: pop-func-signature # Anonymous function - include: pop-func-parameter-and-return-lists match-keyword-go: - match: \bgo\b scope: keyword.control.go match-keyword-goto: - match: \bgoto\b scope: keyword.control.go match-keyword-if: - match: \bif\b scope: keyword.control.go match-keyword-import: - match: \bimport\b scope: keyword.other.import.go match-keyword-interface: - match: (?=\binterface\b) scope: storage.type.keyword.interface.go push: pop-interface match-keyword-map: - match: (?=\bmap\b) push: pop-map match-keyword-package: - match: \bpackage\b scope: keyword.other.package.go match-keyword-range: - match: \brange\b scope: keyword.other.go match-keyword-return: - match: \breturn\b scope: keyword.control.go match-keyword-select: - match: \bselect\b scope: keyword.control.go match-keyword-struct: - match: (?=\bstruct\b) push: pop-struct match-keyword-switch: - match: \bswitch\b scope: keyword.control.go match-keyword-type: - match: \btype\b scope: storage.type.keyword.type.go push: - include: match-comments - match: \( scope: punctuation.section.parens.begin.go set: - match: \) scope: punctuation.section.parens.end.go pop: true - match: \b_\b scope: variable.language.blank.go push: - match: (?=\)) pop: true - include: pop-type-alias-or-typedef - match: '{{ident}}' scope: entity.name.type.go push: - match: (?=\)) pop: true - include: pop-type-alias-or-typedef - include: match-any - match: \b_\b scope: variable.language.blank.go set: pop-type-alias-or-typedef - match: '{{ident}}' scope: entity.name.type.go set: pop-type-alias-or-typedef - include: pop-before-nonblank match-keyword-var: - match: \bvar\b scope: storage.type.keyword.var.go push: - match: \( scope: punctuation.section.parens.begin.go set: - match: \) scope: punctuation.section.parens.end.go pop: true - match: \b_\b(?={{noise}},) scope: variable.language.blank.go - match: '{{ident}}(?={{noise}},)' scope: variable.declaration.go - match: \b_\b scope: variable.language.blank.go push: pop-var-type-and-or-assignment - match: '{{ident}}' scope: variable.declaration.go push: pop-var-type-and-or-assignment - include: match-any - include: match-comments - include: match-comma - match: \b_\b(?={{noise}},) scope: variable.language.blank.go - match: '{{ident}}(?={{noise}},)' scope: variable.declaration.go - match: \b_\b scope: variable.language.blank.go set: pop-var-type-and-or-assignment - match: '{{ident}}' scope: variable.declaration.go set: pop-var-type-and-or-assignment - include: pop-before-nonblank pop-func-signature: - include: match-comments - match: \b_\b scope: variable.language.blank.go set: pop-func-parameter-and-return-lists - match: '{{ident}}' scope: entity.name.function.go set: pop-func-parameter-and-return-lists - include: pop-before-nonblank # https://golang.org/ref/spec#Function_types # # Go has two parameter syntaxes: unnamed and named. # # Unnamed: # # (int) # (int, int) # (int, int, ...int) # # Named: # # (a int) # (a, b int) # (a, b ...int) # (a int, b int) # (a, b int, c ...int) # # The modes are distinct: either all named, or all unnamed. # # Gotchas: # # parameters can span multiple lines # a type can span multiple lines (anonymous struct, interface, etc.) # parameter groups AND parameter names are comma-separated # `chan type` is a type that looks like an identifier followed by a type # # I have an impression that with the current syntax engine, it's impossible to # perfectly parse some parameter lists, particularly ones that are named, # multiline, and have name groups. We're still trying to cover as many edge # cases as possible. pop-func-parameter-and-return-lists: - include: match-comments - match: (?=\() set: [pop-func-return-signature, pop-func-parameter-list] - include: pop-before-nonblank pop-func-return-signature: - include: pop-on-terminator - include: match-comments - match: (?=\() set: pop-func-parameter-list - match: (?=\S) set: pop-type pop-func-parameter-list: - include: match-comments - match: \( scope: punctuation.section.parens.begin.go set: - include: match-comments - match: | (?x) (?= (?:{{noise}}{{ident}}{{noise}},{{noise}})* {{ident}}{{noise}}(?:\.\.\.|[^\s/,).]) ) set: pop-parameter-list-named - match: (?=\S) set: pop-parameter-list-unnamed - include: pop-before-nonblank pop-parameter-list-named: - match: \) scope: punctuation.section.parens.end.go pop: true - include: match-comments - include: match-keywords - include: match-comma - include: match-ellipsis - match: \b_\b scope: variable.language.blank.go push: pop-parameter-type - match: '{{ident}}' scope: variable.parameter.go push: pop-parameter-type pop-parameter-type: - match: (?=\)|,) pop: true - include: match-ellipsis - include: pop-type pop-parameter-list-unnamed: - match: \) scope: punctuation.section.parens.end.go pop: true - include: match-comments - include: match-keywords - include: match-comma - include: match-ellipsis - match: (?=\S) push: pop-type pop-before-nonblank: - match: (?=\S) pop: true pop-on-semicolon: - match: ; scope: punctuation.terminator.go pop: true pop-on-terminator: - include: pop-on-semicolon - match: $ pop: true pop-type: - include: pop-on-semicolon - include: match-comments # Note: Go allows wrapping types in an arbitrary number of parens. - match: \( scope: punctuation.section.parens.begin.go push: [pop-type-nested-in-parens, pop-type] - match: \[ scope: punctuation.section.brackets.begin.go set: - match: \] scope: punctuation.section.brackets.end.go # BUG: # _ = blah[0] * blah # This currently parses as an array type of `[0]*blah`. # Can we fix this false positive? set: pop-type - include: match-any - include: match-operators - match: (?=\bchan\b) set: pop-chan - match: (?=\binterface\b) set: pop-interface - match: (?=\bmap\b) set: pop-map - match: (?=\bstruct\b) set: pop-struct - match: \bfunc\b scope: storage.type.keyword.function.go set: pop-func-parameter-and-return-lists - match: (?={{ident}}) set: pop-named-type - include: pop-before-nonblank pop-type-nested-in-parens: - match: \) scope: punctuation.section.parens.end.go pop: true - include: pop-type pop-struct: - match: \bstruct\b scope: storage.type.keyword.struct.go set: - include: match-comments - match: \{ scope: punctuation.section.braces.begin.go set: - meta_scope: meta.type.go - match: \} scope: punctuation.section.braces.end.go pop: true - include: match-keywords - include: match-star - match: '{{ident}}(?={{noise}}\.)' scope: variable.other.go - match: \. scope: punctuation.accessor.dot.go - match: '{{predeclared_type}}(?={{noise}}(?:"|`|//|;|\}|$))' scope: entity.other.inherited-class.go support.type.builtin.go - match: '{{ident}}(?={{noise}}(?:"|`|//|;|\}|$))' scope: entity.other.inherited-class.go - match: \b_\b scope: variable.language.blank.go - match: '{{ident}}' scope: variable.other.member.declaration.go push: - match: (?=\}) pop: true - include: pop-on-terminator - include: match-comments - include: pop-type - include: match-any - include: match-any - include: pop-before-nonblank pop-interface: - match: \binterface\b scope: storage.type.keyword.interface.go set: - include: match-comments - match: \{ scope: punctuation.section.braces.begin.go set: - meta_scope: meta.type.go - match: \} scope: punctuation.section.braces.end.go pop: true - include: match-keywords - include: match-star - match: '{{ident}}(?={{noise}}\.)' scope: variable.other.go - match: \. scope: punctuation.accessor.dot.go - match: '{{predeclared_type}}(?={{noise}}(?://|;|\}|$))' scope: entity.other.inherited-class.go support.type.builtin.go - match: '{{ident}}(?={{noise}}(?://|;|\}|$))' scope: entity.other.inherited-class.go - match: '{{ident}}(?={{noise}}\()' scope: entity.name.function.go push: - match: (?=\}) pop: true - include: pop-func-parameter-and-return-lists - include: match-any - include: pop-before-nonblank pop-map: # Note: newlines between `map` and `[` are ok, but newlines after `]` # terminate the type. - match: \bmap\b scope: storage.type.keyword.map.go set: - include: match-comments - include: pop-on-semicolon - match: \[ scope: punctuation.section.brackets.begin.go set: - match: \] scope: punctuation.section.brackets.end.go set: - include: pop-on-terminator - include: pop-type - include: match-comments - match: (?=\S) push: - match: (?=\]) pop: true - include: pop-type - include: pop-type # Note: newlines between `chan`, subsequent arrow, and subsequent type, are # perfectly ok. pop-chan: - match: \bchan\b scope: storage.type.keyword.chan.go set: pop-type pop-named-type: - include: match-comments - match: \b_\b scope: variable.language.blank.go pop: true - match: '{{ident}}(?={{noise}}\.)' scope: variable.other.go - match: \. scope: punctuation.accessor.dot.go - match: \b_\b scope: variable.language.blank.go pop: true - include: pop-type-identifier - include: pop-before-nonblank pop-type-identifier: - match: '{{predeclared_type}}' scope: storage.type.go support.type.builtin.go pop: true - match: '{{ident}}' scope: storage.type.go pop: true pop-type-alias-or-typedef: - include: pop-on-terminator - include: match-comments # Newlines after `=` are ok. - match: = scope: keyword.operator.assignment.go set: pop-type - match: (?=\S) set: pop-type pop-const-type-and-or-assignment: - include: pop-on-terminator - include: match-comments - match: = scope: keyword.operator.assignment.go set: pop-const-expressions - match: (?=\S) set: [pop-const-assignment-or-terminate, pop-type] pop-const-assignment-or-terminate: - include: pop-on-terminator - include: match-comments - match: = scope: keyword.operator.assignment.go set: pop-const-expressions - include: pop-before-nonblank # Note: this doesn't support multiline expressions. # # Note on `iota`. See https://golang.org/ref/spec#Iota. `iota` is a regular # identifier that happens to be predeclared in constant initialization # expressions, but not anywhere else. Just like `true|false|nil`, you can # redefine it. Doing so in the root scope makes the magic constant unavailable # for the entire package. pop-const-expressions: - include: pop-on-semicolon - include: match-comments - match: (?=\S) set: - include: pop-on-terminator - match: \biota\b scope: constant.numeric.integer.decimal.go - include: match-any pop-var-type-and-or-assignment: - include: pop-on-terminator - include: match-comments - match: = scope: keyword.operator.assignment.go set: pop-var-expressions - match: (?=\S) set: [pop-var-assignment-or-terminate, pop-type] pop-var-assignment-or-terminate: - include: pop-on-terminator - include: match-comments - match: = scope: keyword.operator.assignment.go set: pop-var-expressions - include: pop-before-nonblank # Note: this doesn't support multiline expressions. pop-var-expressions: - include: pop-on-semicolon - include: match-comments - match: (?=\S) set: - include: pop-on-terminator - include: match-any pop-type-assertion: - match: \( scope: punctuation.section.parens.begin.go set: - match: \) scope: punctuation.section.parens.end.go pop: true - include: pop-type pop-member: - match: \b_\b scope: variable.language.blank.go pop: true - match: '{{ident}}' scope: variable.other.member.go pop: true pop-arguments-starting-with-type: - include: match-comments - match: \) scope: punctuation.section.parens.end.go - match: \( scope: punctuation.section.parens.begin.go set: - match: \) scope: punctuation.section.parens.end.go pop: true - include: match-comments - match: (?=\S) set: pop-type - include: pop-on-terminator - include: pop-before-nonblank