%YAML 1.2 --- name: Python file_extensions: - py - py3 - pyw - pyi - pyx - pyx.in - pxd - pxd.in - pxi - pxi.in - rpy - cpy - SConstruct - Sconstruct - sconstruct - SConscript - gyp - gypi - Snakefile - vpy - wscript - bazel - bzl first_line_match: ^#!\s*/.*\bpython(\d(\.\d)?)?\b scope: source.python variables: # We support unicode here because Python 3 is the future identifier_continue: '[[:alnum:]_]' identifier: '\b[[:alpha:]_]{{identifier_continue}}*\b' identifier_constant: '\b(?:[\p{Lu}_][\p{Lu}_\d]*)?[\p{Lu}]{2,}[\p{Lu}_\d]*\b' # require 2 consecutive upper-case letters digits: (?:\d+(?:_\d+)*) exponent: (?:[eE][-+]?{{digits}}) path: '({{identifier}}[ ]*\.[ ]*)*{{identifier}}' sql_indicator: \s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|REPLACE|ALTER|WITH)\b illegal_names: (?:and|as|assert|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|not|or|pass|raise|return|try|while|with|yield) format_spec: |- (?x: (?:.? [<>=^])? # fill align [ +-]? # sign \#? # alternate form # technically, octal and hexadecimal integers are also supported as 'width', but rarely used \d* # width ,? # thousands separator (?:\.\d+)? # precision [bcdeEfFgGnosxX%]? # type ) strftime_spec: '(?:%(?:[aAwdbBGmyYHIpMSfzZjuUVWcxX%]|-[dmHIMSj]))' # This can be used in look-aheads to parse simple expressions. # Can't be recursive, because sregex doesn't support that, # so we're skipping parentheses. # Can't parse multiple lines as well, for obvious reasons simple_expression: |- (?x: \s+ # whitespace | [urfb]*"(?:\\.|[^"])*" # strings | [urfb]*'(?:\\.|[^'])*' # ^ | [\d.ej]+ # numerics | [+*/%@-] | // | and | or # operators | {{path}} # a path )* contexts: main: - include: statements statements: - include: docstrings - include: line-statements - include: block-statements - include: classes - include: functions - include: modifiers - include: assignments - match: ; scope: punctuation.terminator.statement.python - include: expression-as-a-statement line-statements: - include: imports - include: decorators - match: \b(raise)\b scope: keyword.control.flow.raise.python push: - meta_scope: meta.statement.raise.python - include: line-continuation-or-pop - match: \b(from)\b scope: keyword.control.flow.raise.from.python set: - meta_scope: meta.statement.raise.python - include: line-continuation-or-pop - include: expression-in-a-statement - include: expression-in-a-statement - match: \b(assert)\b scope: keyword.control.flow.assert.python - match: \b(del)\b scope: keyword.other.del.python - match: \b(print)\b(?! *([,.\]}])) scope: keyword.other.print.python - match: \b(exec)\b(?! *($|[,.()\]}])) scope: keyword.other.exec.python - match: \b(return)\b scope: keyword.control.flow.return.python - match: \b(break)\b scope: keyword.control.flow.break.python - match: \b(continue)\b scope: keyword.control.flow.continue.python - match: \b(pass)\b scope: keyword.control.flow.pass.python imports: - match: \b(import)\b scope: keyword.control.import.python push: - imports-import-body - expect-absolute-import - match: \b(from)\b scope: keyword.control.import.from.python push: - imports-from-body - maybe-relative-import imports-import-body: - meta_scope: meta.statement.import.python - include: line-continuation-or-pop - match: ',' scope: punctuation.separator.import-list.python push: expect-absolute-import - match: (?=\bas\b) set: import-alias-list - include: qualified-name - match: (?=\S) pop: true imports-from-body: - meta_scope: meta.statement.import.python - meta_content_scope: meta.import-source.python - include: line-continuation-or-pop - match: (?=\bas\b) set: import-alias-list - match: (?=\bimport\b) set: - meta_include_prototype: false - match: import scope: keyword.control.import.python set: imports-from-import-body - match: '{{illegal_names}}\b' scope: meta.import-path.python invalid.illegal.name.python - match: '{{identifier}}' scope: meta.import-path.python meta.import-name.python - match: \s*(\.) *(?={{identifier}}|$) captures: 0: meta.import-path.python 1: punctuation.accessor.dot.python - match: \s*(\. *\S+) # matches and consumes the remainder of "abc.123" or "abc.+" captures: 0: meta.import-path.python 1: invalid.illegal.name.python - match: (?=\S) pop: true imports-from-import-body: - meta_scope: meta.statement.import.python - include: line-continuation-or-pop - match: (?=\() set: - meta_include_prototype: false - match: \( scope: punctuation.section.import-list.begin.python set: - meta_scope: meta.statement.import.python meta.import-list.python - match: \) scope: punctuation.section.import-list.end.python pop: true - include: comments - include: import-name-list - match: (?=\S) set: import-alias-list import-alias-list: - meta_content_scope: meta.statement.import.python - include: line-continuation-or-pop - include: import-name-list import-name-list: - match: ',' scope: punctuation.separator.import-list.python - match: \* scope: constant.language.import-all.python - match: \b(as)\b scope: keyword.control.import.as.python - include: name - match: '[^\s,)]+' scope: invalid.illegal.name.import.python expect-absolute-import: - include: line-continuation-or-pop - match: \.+ scope: invalid.illegal.unexpected-relative-import.python - match: (?=\S) pop: true maybe-relative-import: - include: line-continuation-or-pop - match: \.+ scope: meta.import-path.python keyword.control.import.relative.python - match: (?=\S) pop: true block-statements: # async for ... in ...: - match: \b(async +)?(for)\b captures: 1: storage.modifier.async.python 2: keyword.control.loop.for.python push: - meta_scope: meta.statement.loop.for.python - include: line-continuation-or-pop - match: \bin\b scope: keyword.control.loop.for.in.python set: - meta_content_scope: meta.statement.loop.for.python - include: line-continuation-or-pop - match: ':(?!=)' scope: meta.statement.loop.for.python punctuation.section.block.loop.for.python pop: true - include: expression-in-a-statement - match: ':(?!=)' scope: invalid.illegal.missing-in.python pop: true - include: target-list # async with ... as ...: - match: \b(async +)?(with)\b captures: 1: storage.modifier.async.python 2: keyword.control.flow.with.python push: with-body # except ... as ...: - match: \bexcept\b scope: keyword.control.exception.catch.python push: - meta_scope: meta.statement.exception.catch.python - include: line-continuation-or-pop - match: ':(?!=)' scope: punctuation.section.block.exception.catch.python pop: true - match: '\bas\b' scope: keyword.control.exception.catch.as.python set: - meta_content_scope: meta.statement.exception.catch.python - include: line-continuation-or-pop - match: ':' scope: meta.statement.exception.catch.python punctuation.section.block.exception.catch.python pop: true - include: name - include: target-list - match: \bif\b scope: keyword.control.conditional.if.python push: - meta_scope: meta.statement.conditional.if.python - include: line-continuation-or-pop - match: ':(?!=)' scope: punctuation.section.block.conditional.if.python pop: true - include: expression-in-a-statement - match: \bwhile\b scope: keyword.control.loop.while.python push: - meta_scope: meta.statement.loop.while.python - include: line-continuation-or-pop - match: ':(?!=)' scope: punctuation.section.block.loop.while.python pop: true - include: expression-in-a-statement - match: \b(else)\b(?:\s*(:))? scope: meta.statement.conditional.else.python captures: 1: keyword.control.conditional.else.python 2: punctuation.section.block.conditional.else.python - match: \b(try)\b(?:\s*(:))? scope: meta.statement.exception.try.python captures: 1: keyword.control.exception.try.python 2: punctuation.section.block.exception.try.python - match: \b(finally)\b(?:\s*(:))? scope: meta.statement.exception.finally.python captures: 1: keyword.control.exception.finally.python 2: punctuation.section.block.exception.finally.python - match: \belif\b scope: keyword.control.conditional.elseif.python push: - meta_scope: meta.statement.conditional.elseif.python - match: ':(?!=)' scope: punctuation.section.block.conditional.elseif.python pop: true - match: $\n? pop: true - include: expression-in-a-statement with-body: - meta_scope: meta.statement.with.python - include: line-continuation-or-pop - match: \b(as)\b scope: keyword.control.flow.with.as.python set: with-as - match: ':(?!=)' scope: punctuation.section.block.with.python pop: true - match: ',' scope: punctuation.separator.with-resources.python - include: expression-in-a-statement with-as: - meta_scope: meta.statement.with.python - include: line-continuation-or-pop - match: ':' scope: punctuation.section.block.with.python pop: true - match: ',' scope: punctuation.separator.with-resources.python set: with-body - include: name - include: groups - include: lists expressions-common: - include: comments - include: constants - include: numbers - include: yields - include: operators - include: lambda - match: \b(await)\b scope: keyword.other.await.python - include: inline-if - include: strings - include: function-calls - include: item-access - include: lists - include: dictionaries-and-sets - include: tuples - include: groups - match: \) scope: invalid.illegal.stray.brace.round.python - match: \] scope: invalid.illegal.stray.brace.square.python - match: \} scope: invalid.illegal.stray.brace.curly.python - include: line-continuation # Always include these last and only one at a time! expression-as-a-statement: - include: expressions-common - include: qualified-name expression-in-a-statement: # Differs from expression-as-a-statement in that: # - invalid-name matches will pop the current context # - assignment expressions - include: expressions-common - include: illegal-names-pop - include: qualified-name - include: assignment-expression expression-in-a-group: # Always include this last! # Differs from expression-in-a-statement in that: # - accessor matching continues into the next line - include: expression-in-a-statement - match: '(\.) *(?={{identifier}})' captures: 1: punctuation.accessor.dot.python push: - include: magic-function-names - include: magic-variable-names - include: illegal-names - include: generic-names - match: '' pop: true after-expression: # direct function call - match: '\s*(\()' captures: 1: punctuation.section.arguments.begin.python push: [function-call-arguments, allow-unpack-operators] # item access - match: '\s*(\[)' captures: 1: meta.item-access.python punctuation.section.brackets.begin.python push: - meta_content_scope: meta.item-access.arguments.python - match: \] scope: meta.item-access.python punctuation.section.brackets.end.python pop: true - include: illegal-assignment-expression - match: ':' scope: punctuation.separator.slice.python - include: expression-in-a-group # indirect function call following attribute access - include: function-calls # arbitrary attribute access - match: '\s*(\.)' captures: 1: punctuation.accessor.dot.python push: - include: magic-function-names - include: magic-variable-names - include: illegal-names - include: generic-names - match: '' pop: true - match: '' pop: true comments: - match: "#" scope: punctuation.definition.comment.python push: - meta_scope: comment.line.number-sign.python - match: \n pop: true constants: - match: \b(None|True|False|Ellipsis|NotImplemented|__debug__)\b scope: constant.language.python - match: \.{3}(?!\w) scope: constant.language.python numbers: # https://docs.python.org/3/reference/lexical_analysis.html#numeric-literals # hexadecimal - match: \b(0[xX])(\h*)([lL]) # py2 scope: meta.number.integer.hexadecimal.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python 3: constant.numeric.suffix.python - match: \b(0[xX])((?:_?\h)+) scope: meta.number.integer.hexadecimal.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python # octal - match: \b(0[oO]?)((?=[oO]|[0-7])[0-7]*)([lL]) # py2 scope: meta.number.integer.octal.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python 3: constant.numeric.suffix.python - match: \b(0)([0-7]+) # py2 scope: meta.number.integer.octal.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python - match: \b(0[oO])((?:_?[0-7])+) scope: meta.number.integer.octal.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python # binary - match: \b(0[bB])([01]*)([lL]) # py2 scope: meta.number.integer.binary.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python 3: constant.numeric.suffix.python - match: \b(0[bB])((?:_?[01])*) scope: meta.number.integer.binary.python captures: 1: constant.numeric.base.python 2: constant.numeric.value.python # complex - match: |- (?x) ( # 1.j, 1.1j, 1.1e1j, 1.1e-1j, 1.e1j, 1.e-1 | 1e1j, 1e-1j \b{{digits}} (\.)? {{digits}}? {{exponent}}? # .1j, .1e1j, .1e-1j | (\.) {{digits}} {{exponent}}? ) ([jJ]) scope: meta.number.imaginary.decimal.python captures: 1: constant.numeric.value.python 2: punctuation.separator.decimal.python 3: punctuation.separator.decimal.python 4: constant.numeric.suffix.python # floating point - match: |- (?x: # 1., 1.1, 1.1e1, 1.1e-1, 1.e1, 1.e-1 | 1e1, 1e-1 \b{{digits}} (?: (\.) {{digits}}? {{exponent}}? | {{exponent}} ) # .1, .1e1, .1e-1 | (\.) {{digits}} {{exponent}}? ) scope: meta.number.float.decimal.python constant.numeric.value.python captures: 1: punctuation.separator.decimal.python 2: punctuation.separator.decimal.python # integer - match: \b([1-9]\d*|0)([lL])\b # py2 scope: meta.number.integer.decimal.python captures: 1: constant.numeric.value.python 2: constant.numeric.suffix.python - match: \b([1-9][\d_]*|0)\b scope: meta.number.integer.decimal.python constant.numeric.value.python modifiers: - match: \b(?:(global)|(nonlocal))\b captures: 1: storage.modifier.global.python 2: storage.modifier.nonlocal.python push: - include: line-continuation-or-pop - match: ',' scope: punctuation.separator.storage-list.python - include: name - match: \S+ scope: invalid.illegal.name.storage.python yields: - match: \b(yield)(?:\s+(from))?\b captures: 1: keyword.control.flow.yield.python 2: keyword.control.flow.yield-from.python assignment-expression: - match: := scope: keyword.operator.assignment.inline.python illegal-assignment-expression: - match: := scope: invalid.illegal.not-allowed-here.python assignments: - include: illegal-assignment-expression - match: ':' scope: punctuation.separator.annotation.variable.python - match: \+=|-=|\*=|/=|//=|%=|@=|&=|\|=|\^=|>>=|<<=|\*\*= scope: keyword.operator.assignment.augmented.python - match: '=(?!=)' scope: keyword.operator.assignment.python operators: - match: <> scope: invalid.deprecated.operator.python - match: <\=|>\=|\=\=|<|>|\!\= scope: keyword.operator.comparison.python - match: \+|\-|\*|\*\*|/|//|%|<<|>>|&|\||\^|~ scope: keyword.operator.arithmetic.python - match: \b(and|in|is|not|or)\b comment: keyword operators that evaluate to True or False scope: keyword.operator.logical.python - match: '@' scope: keyword.operator.matrix.python - match: ',' scope: punctuation.separator.sequence.python allow-unpack-operators: # Match unpacking operators, if present - include: comments - match: \*{3,} scope: invalid.illegal.syntax.python pop: true - match: \*\* scope: keyword.operator.unpacking.mapping.python pop: true - match: \* scope: keyword.operator.unpacking.sequence.python pop: true - match: (?=\S) pop: true classes: - match: '^\s*(class)\b' captures: 1: keyword.declaration.class.python push: - meta_scope: meta.class.python - include: line-continuation-or-pop - match: ':' scope: punctuation.section.class.begin.python pop: true - match: "(?={{identifier}})" push: - meta_content_scope: entity.name.class.python - include: entity-name-class - match: '' pop: true - match: \( scope: punctuation.section.inheritance.begin.python set: - meta_scope: meta.class.inheritance.python - match: \) scope: punctuation.section.inheritance.end.python set: - include: line-continuation-or-pop - match: ':' scope: meta.class.python punctuation.section.class.begin.python pop: true - match: (?=\S) pop: true - match: ':' scope: invalid.illegal.no-closing-parens.python pop: true - match: ',' scope: punctuation.separator.inheritance.python - include: illegal-names-pop - match: ({{identifier}}) *(=) captures: 1: variable.parameter.class-inheritance.python 2: keyword.operator.assignment.python - match: (?={{path}}) push: - meta_scope: entity.other.inherited-class.python - match: '{{identifier}}(?: *(\.) *)?' captures: 1: punctuation.accessor.dot.python - match: '' pop: true - include: expression-in-a-group functions: - match: '^\s*(?:(async)\s+)?(def)\b' captures: 1: keyword.declaration.async.python 2: keyword.declaration.function.python push: - meta_scope: meta.function.python - include: line-continuation-or-pop - match: ':' scope: punctuation.section.function.begin.python pop: true - match: "(?={{identifier}})" push: - meta_content_scope: entity.name.function.python - include: entity-name-function - match: '' pop: true - match: '(?=\()' set: - match: \( scope: meta.function.parameters.python punctuation.section.parameters.begin.python set: [function-parameters, allow-unpack-operators] function-parameters: - meta_content_scope: meta.function.parameters.python - match: \) scope: punctuation.section.parameters.end.python set: function-after-parameters - include: comments - match: ',' scope: punctuation.separator.parameters.python push: allow-unpack-operators - match: / scope: storage.modifier.positional-args-only.python push: - match: (?=[,)]) pop: true - match: \S scope: invalid.illegal.expected-comma.python - match: '(?==)' set: - match: '=' scope: keyword.operator.assignment.python set: - meta_scope: meta.function.parameters.default-value.python - match: '(?=[,)])' set: [function-parameters, allow-unpack-operators] - include: illegal-assignment-expression - include: expression-in-a-group - match: '(?=:)' set: - match: ':' scope: punctuation.separator.annotation.parameter.python set: - meta_scope: meta.function.parameters.annotation.python - match: '(?=[,)=])' set: function-parameters - include: illegal-assignment-expression - include: expression-in-a-group - include: function-parameters-tuple - include: illegal-names - match: '{{identifier}}' scope: variable.parameter.python - include: line-continuation function-parameters-tuple: # python 2 style tuple arguments # removed from python 3 since PEP-3113 - match: \( scope: punctuation.section.group.begin.python push: - meta_scope: meta.group.python - match: \) scope: punctuation.section.group.end.python set: after-expression - include: comments - match: ',' scope: punctuation.separator.parameters.python push: allow-unpack-operators # default values should follow the argument - match: '=' push: - meta_scope: invalid.illegal.default-value.python - match: '(?=[,)=])' pop: true # python 2 does not support type annotations - match: '(?=:)' push: - meta_scope: invalid.illegal.annotation.python - match: '(?=[,)=])' pop: true - include: illegal-names - match: '{{identifier}}' scope: variable.parameter.python - include: line-continuation function-after-parameters: - meta_content_scope: meta.function.python - match: (?=->) set: [function-return-type, function-return-type-separator] - include: function-terminator function-return-type: - meta_content_scope: meta.function.annotation.return.python - include: illegal-assignment-expression - include: function-terminator - include: expression-in-a-statement function-return-type-separator: - match: -> scope: punctuation.separator.annotation.return.python pop: true function-terminator: - match: ':' scope: meta.function.python punctuation.section.function.begin.python pop: true - include: line-continuation-or-pop decorators: - match: ^\s*(?=@) push: # Due to line continuations, we don't know whether this is a "function call" yet - meta_content_scope: meta.annotation.python - match: '@' scope: punctuation.definition.annotation.python - match: $ pop: true - include: line-continuation-or-pop - match: (?=\.?\s*{{path}}\s*\() # now we do set: [after-expression, decorator-function-call-wrapper, qualified-name-until-leaf] - match: (?=\.?\s*{{path}}) push: [decorator-wrapper, qualified-name-until-leaf] - match: \S scope: invalid.illegal.character.python pop: true decorator-wrapper: - match: (\.)\s* captures: 1: punctuation.accessor.dot.python set: - meta_scope: meta.qualified-name.python - meta_content_scope: variable.annotation.python - include: dotted-name-specials - include: generic-names - match: '' pop: true - match: '' set: - meta_scope: meta.qualified-name.python variable.annotation.python - include: name-specials - include: generic-names - match: '' pop: true decorator-function-call-wrapper: - meta_scope: meta.annotation.function.python - match: \) scope: punctuation.section.arguments.end.python pop: true - match: \( scope: meta.annotation.function.python punctuation.section.arguments.begin.python push: [decorator-function-call-arguments, allow-unpack-operators] - match: (\.)\s* captures: 1: punctuation.accessor.dot.python push: - meta_scope: meta.qualified-name.python - meta_content_scope: variable.annotation.function.python - include: dotted-name-specials - include: generic-names - match: '' pop: true - match: '' push: - meta_scope: meta.qualified-name.python variable.annotation.function.python - include: name-specials - include: generic-names - match: '' pop: true decorator-function-call-arguments: - clear_scopes: 1 - meta_content_scope: meta.annotation.arguments.python - match: (?=\)) pop: true - include: arguments item-access: - match: '(?={{path}}\s*\[)' push: - match: \] scope: meta.item-access.python punctuation.section.brackets.end.python set: after-expression - match: '(?={{path}}\s*\[)' push: - meta_content_scope: meta.item-access.python - match: '(?=\s*\[)' pop: true - include: qualified-name - match: \[ scope: meta.item-access.python punctuation.section.brackets.begin.python push: - meta_content_scope: meta.item-access.arguments.python - match: '(?=\])' pop: true - match: ':' scope: punctuation.separator.slice.python - include: expression-in-a-group function-calls: - match: '(?=(\.\s*)?{{path}}\s*\()' push: [function-call-wrapper, qualified-name-until-leaf] function-call-wrapper: - meta_scope: meta.function-call.python - match: (?=\() # need to remove meta.function-call.python from opening parens set: - match: \( scope: punctuation.section.arguments.begin.python set: [after-expression, function-call-arguments, allow-unpack-operators] - match: (\.)\s*(?={{identifier}}) captures: 1: punctuation.accessor.dot.python push: - meta_scope: meta.qualified-name.python - meta_content_scope: variable.function.python - include: dotted-name-specials - include: generic-names - match: '' pop: true - match: (?={{identifier}}) push: - meta_scope: meta.qualified-name.python variable.function.python - include: name-specials - include: generic-names - match: '' pop: true function-call-arguments: - meta_scope: meta.function-call.arguments.python - match: \) scope: punctuation.section.arguments.end.python pop: true - include: arguments arguments: - include: keyword-arguments - match: ',' scope: punctuation.separator.arguments.python push: allow-unpack-operators - include: inline-for - include: expression-in-a-group keyword-arguments: - match: '(?={{identifier}}\s*=(?!=))' push: - include: line-continuation-or-pop - match: '=' scope: keyword.operator.assignment.python set: - include: illegal-assignment-expression - match: (?=[,):]) pop: true - include: expression-in-a-group - include: illegal-names - match: '{{identifier}}' scope: variable.parameter.python lambda: - match: \b(lambda)(?=\s|:|$) scope: meta.function.inline.python storage.type.function.inline.python keyword.declaration.function.inline.python push: [lambda-parameters, allow-unpack-operators] lambda-parameters: - meta_content_scope: meta.function.inline.parameters.python - include: line-continuation-or-pop - match: '\:' scope: punctuation.section.function.begin.python set: # clear meta_scope - match: '' set: - meta_scope: meta.function.inline.body.python - include: illegal-assignment-expression # We don't know whether we are within a grouped # or line-statement context at this point. # If we're in a group, the underlying context will take over # at the end of the line. - match: (?=[,:)}\]])|$ pop: true - include: expression-in-a-statement - match: ',' scope: punctuation.separator.parameters.python push: allow-unpack-operators - include: keyword-arguments - include: function-parameters-tuple - include: illegal-names - match: '{{identifier}}' scope: variable.parameter.python - match: '\S' scope: invalid.illegal.expected-parameter.python groups: - match: \( scope: punctuation.section.group.begin.python push: - meta_scope: meta.group.python - match: \) scope: punctuation.section.group.end.python set: after-expression - match: ',' scope: punctuation.separator.tuple.python - include: inline-for - include: expression-in-a-group tuples: # We don't know for certain, whether a parenthesized expression is a tuple, # so try looking ahead. - match: (\()\s*(\)) scope: meta.sequence.tuple.empty.python captures: 1: punctuation.section.sequence.begin.python 2: punctuation.section.sequence.end.python push: after-expression - match: \((?={{simple_expression}},|\s*\*{{path}}) scope: punctuation.section.sequence.begin.python push: inside-tuple # TODO generator # - match: \((?:{{simple_expression}}for) inside-tuple: - meta_scope: meta.sequence.tuple.python - match: \) scope: punctuation.section.sequence.end.python set: after-expression - match: ',' scope: punctuation.separator.sequence.python push: allow-unpack-operators - include: inline-for - include: expression-in-a-group lists: - match: (\[)\s*(\]) scope: meta.sequence.list.empty.python captures: 1: punctuation.section.sequence.begin.python 2: punctuation.section.sequence.end.python push: after-expression - match: \[ scope: punctuation.section.sequence.begin.python push: [inside-list, allow-unpack-operators] inside-list: - meta_scope: meta.sequence.list.python - match: \] scope: punctuation.section.sequence.end.python set: after-expression - match: ',' scope: punctuation.separator.sequence.python push: allow-unpack-operators - include: inline-for - include: expression-in-a-group dictionaries-and-sets: # Dictionaries and set literals use the same punctuation, # so we try looking ahead to determine whether we have a dict or a set. - match: '(\{)\s*(\})' scope: meta.mapping.empty.python captures: 1: punctuation.section.mapping.begin.python 2: punctuation.section.mapping.end.python push: after-expression - match: \{(?={{simple_expression}}:|\s*\*\*) scope: punctuation.section.mapping.begin.python push: inside-dictionary - match: \{(?={{simple_expression}}[,}]|\s*\*) scope: punctuation.section.set.begin.python push: inside-set # If the expression is "more complex" or on the next line, # fall back to default and determine later. - match: \{ scope: punctuation.section.mapping-or-set.begin.python push: - meta_scope: meta.mapping-or-set.python - match: \} scope: punctuation.section.mapping-or-set.end.python set: after-expression - match: (?={{simple_expression}}:|\s*\*\*) set: inside-dictionary - match: (?={{simple_expression}}[,}]|\s*\*) set: inside-set - match: ',' scope: punctuation.separator.set.python set: inside-set - include: illegal-assignment-expression - match: ':' scope: punctuation.separator.mapping.key-value.python set: inside-directory-value - include: inline-for - include: expression-in-a-group inside-dictionary: - meta_scope: meta.mapping.python - match: \} scope: punctuation.section.mapping.end.python set: after-expression - include: illegal-assignment-expression - match: ':' scope: punctuation.separator.mapping.key-value.python set: inside-directory-value - match: ',' scope: invalid.illegal.expected-colon.python - match: \*\* scope: keyword.operator.unpacking.mapping.python push: - match: (?=\}) pop: true - match: ',' scope: punctuation.separator.mapping.python pop: true - include: expression-in-a-group - include: comments - match: (?=\S) push: - clear_scopes: 1 - meta_scope: meta.mapping.key.python - match: \s*(?=\}|,|:) pop: true - include: expression-in-a-group inside-directory-value: - meta_content_scope: meta.mapping.python - match: \} scope: punctuation.section.mapping.end.python set: after-expression - match: (?=,) set: # clear meta scope from this match, because 'inside-directory' has it in meta_scope - match: ',' scope: punctuation.separator.mapping.python set: inside-dictionary - match: (?=(?:async|for)\b) push: - match: (?=\}) pop: true - match: ',' scope: invalid.illegal.unexpected-comma.python - include: inline-for - include: expression-in-a-group - include: comments - match: (?=\S) push: - clear_scopes: 1 - meta_content_scope: meta.mapping.value.python - match: (?=\s*(\}|,|(?:async|for)\b)) pop: true - include: expression-in-a-group inside-set: - meta_scope: meta.set.python - match: \} scope: punctuation.section.set.end.python set: after-expression - include: illegal-assignment-expression - match: ':' scope: invalid.illegal.colon-inside-set.python - match: ',' scope: punctuation.separator.set.python - match: \* scope: keyword.operator.unpacking.sequence.python push: - match: (?=\}) pop: true - match: ',' scope: punctuation.separator.set.python pop: true - include: expression-in-a-group - include: inline-for - include: expression-in-a-group builtin-exceptions: - match: |- (?x)\b( (?: Arithmetic|Assertion|Attribute|BlockingIO|BrokenPipe|Buffer|ChildProcess| Connection(?:Aborted|Refused|Reset)?|EOF|Environment|FileExists| FileNotFound|FloatingPoint|Interrupted|IO|IsADirectoryError| Import|Indentation|Index|Key|Lookup|Memory|Name|NotADirectory| NotImplemented|OS|Overflow|Permission|ProcessLookup|Reference| Runtime|Standard|Syntax|System|Tab|Timeout|Type|UnboundLocal| Unicode(?:Encode|Decode|Translate)?|Value|VMS|Windows|ZeroDivision )Error| (?:(?:Pending)?Deprecation|Resource|Runtime|Syntax|User|Future|Import|Unicode|Bytes)?Warning| (?:Base)?Exception| SystemExit|StopIteration|NotImplemented|KeyboardInterrupt|GeneratorExit )\b scope: support.type.exception.python builtin-functions: - match: |- (?x)\b(?: __import__|all|abs|any|ascii|bin|callable|chr|classmethod| compile|delattr|dir|divmod|enumerate|eval|filter|format|getattr| globals|hasattr|hash|help|hex|id|input|isinstance|issubclass|iter| len|locals|map|max|min|next|oct|open|ord|pow|property|range| repr|reversed|round|setattr|sorted|staticmethod| sum|super|type|vars|zip # Python 2 functions |apply|cmp|coerce|execfile|intern|raw_input|reduce|reload|unichr|xrange # Python 3 functions |breakpoint|exec )\b scope: support.function.builtin.python builtin-types: - match: |- (?x)\b(?: bool|bytearray|bytes|complex|dict|float|frozenset|int| list|memoryview|object|set|slice|str|tuple # Python 2 types |basestring|long|unicode # Python 2 types prone to conflicts # |buffer|file )\b scope: support.type.python name: - match: '(?={{identifier}})' push: - include: name-specials - match: '{{identifier_constant}}' scope: variable.other.constant.python - include: generic-names - match: '' pop: true dotted-name: - match: '\s*(\.)\s*(?={{identifier}})' captures: 1: punctuation.accessor.dot.python push: - include: dotted-name-specials - match: '{{identifier_constant}}' scope: variable.other.constant.python - include: generic-names - match: '' pop: true qualified-name: - match: '(?={{path}})' push: - meta_scope: meta.qualified-name.python - include: name - include: dotted-name - match: '' pop: true - match: \. scope: punctuation.accessor.dot.python qualified-name-until-leaf: # Push this together with another context to match a qualified name # until the last non-special identifier (if any). # This allows the leaf to be scoped individually. - meta_scope: meta.qualified-name.python # If a line continuation follows, this may or may not be the last leaf (most likley not though) - match: (?={{identifier}}\s*(\.|\\)) push: - include: name-specials - include: generic-names - match: '' pop: true - match: (\.)\s*(?={{identifier}}\s*(\.|\\)) captures: 1: punctuation.accessor.dot.python push: - include: dotted-name-specials - include: generic-names - match: '' pop: true - match: \.(?!\s*{{identifier}}) # don't match last dot scope: punctuation.accessor.dot.python - match: (?=\S|$) pop: true name-specials: - include: builtin-functions - include: builtin-types - include: builtin-exceptions - include: illegal-names - include: magic-function-names - include: magic-variable-names - include: language-variables dotted-name-specials: - include: magic-function-names - include: magic-variable-names - include: illegal-names entity-name-class: - include: illegal-names - include: generic-names entity-name-function: - include: magic-function-names - include: illegal-names - include: generic-names generic-names: - match: '{{identifier}}' scope: meta.generic-name.python illegal-names: - match: \b{{illegal_names}}\b scope: invalid.illegal.name.python illegal-names-pop: - match: \b{{illegal_names}}\b scope: invalid.illegal.name.python pop: true language-variables: - match: \b(self|cls)\b scope: variable.language.python - match: _(?!{{identifier_continue}}) scope: variable.language.python line-continuation: - match: (\\)(.*)$\n? captures: 1: punctuation.separator.continuation.line.python 2: invalid.illegal.unexpected-text.python # make sure to resume parsing at next line push: # This prevents strings after a continuation from being a docstring - include: strings - match: (?=\S|^\s*$|\n) # '\n' for when we matched a string earlier pop: true line-continuation-or-pop: - include: line-continuation - match: (?=\s*($|;|#)) pop: true magic-function-names: # https://docs.python.org/2/reference/datamodel.html # https://docs.python.org/3/reference/datamodel.html - match: |- (?x)\b__(?: # unary operators invert|neg|pos|abs| # binary operators add|and|div|divmod|floordiv|lshift|mod|mul|or|pow|rshift|sub|truediv|xor| contains| # right-hand binary operators radd|rand|rdiv|rdivmod|rfloordiv|rlshift|rmod|rmul|ror|rpow|rrshift|rsub|rtruediv|rxor| # in-place operator assignments iadd|iand|idiv|ifloordiv|ilshift|imod|imul|ior|ipow|irshift|isub|itruediv|ixor| # comparisons eq|ge|gt|le|lt|ne| cmp|rcmp| # py2 # primary coercion bool|str| nonzero|unicode| # py2 # number coercion (converts something to a number) bytes|complex|float|index|int|round| long| # py2 # other "coercion" format|len|length_hint|hash|repr|reversed| coerce|hex|oct| # py2 fspath| # iterator (and 'await') iter|next| aiter|anext| await| # attribute and item access delattr|delitem|delslice| getattr|getattribute|getitem|getslice| setattr|setitem|setslice| dir|missing| # context manager enter|exit| aenter|aexit| # other class magic call|del|init|new|init_subclass| instancecheck|subclasscheck| # pickling getnewargs|getnewargs_ex|getstate|setstate|reduce|reduce_ex| # descriptors delete|get|set|set_name| # class-specific subclasses| # dataclasses (PEP 557) post_init| # for typing core support (PEP 560) class_getitem|mro_entries )__\b comment: these methods have magic interpretation by python and are generally called indirectly through syntactic constructs scope: support.function.magic.python magic-variable-names: # magic variables which a class/module/object may have. # https://docs.python.org/3/library/inspect.html#types-and-members # https://docs.python.org/3/reference/datamodel.html#object.__slots__ # https://docs.python.org/3/reference/datamodel.html#preparing-the-class-namespace - match: |- (?x)\b__(?: # generic object class|dict|doc|module|name| # module-specific / global all|file|package| # functions & methods annotations|closure|code|defaults|func|globals|kwdefaults|self|qualname| # classes (attributes) bases|prepare|slots|metaclass|mro| # Python 2 members|methods )__\b scope: support.variable.magic.python docstrings: - match: ^\s*(?=(?i)(ur|ru|u|r)?("""|''')) push: - match: (?i)(u)?("""|''') captures: 1: storage.type.string.python 2: punctuation.definition.comment.begin.python set: - meta_scope: comment.block.documentation.python - include: escaped-unicode-char - include: escaped-char - match: '\2' scope: punctuation.definition.comment.end.python pop: true - match: (?i)(u?ru?)("""|''') captures: 1: storage.type.string.python 2: punctuation.definition.comment.begin.python set: - meta_scope: comment.block.documentation.python - match: '\2' scope: punctuation.definition.comment.end.python pop: true escaped-char: - match: '(\\x\h{2})|(\\[0-7]{1,3})|(\\[\\"''abfnrtv])' captures: 1: constant.character.escape.hex.python 2: constant.character.escape.octal.python 3: constant.character.escape.python - match: \\. # deprecated in 3.6 and will eventually be a syntax error scope: invalid.deprecated.character.escape.python escaped-unicode-char: - match: '(\\U\h{8})|(\\u\h{4})|(\\N\{[-a-zA-Z ]+\})' captures: 1: constant.character.escape.unicode.16-bit-hex.python 2: constant.character.escape.unicode.32-bit-hex.python 3: constant.character.escape.unicode.name.python escaped-fstring-escape: # special-case the '\{{' sequence because it has higher priority than the deprecated '\{' - match: (\\)(\{\{|\}\}) scope: constant.character.escape.backslash.regexp captures: 1: invalid.deprecated.character.escape.python 2: constant.character.escape.python line-continuation-inside-string: - match: (\\)$\n? captures: 1: punctuation.separator.continuation.line.python - match: \n scope: invalid.illegal.unclosed-string.python set: after-expression line-continuation-inside-block-string: - match: \\$ scope: punctuation.separator.continuation.line.python constant-placeholder: - match: |- # printf style (?x) % ( \( ({{identifier}}) \) )? # mapping key \#? # alternate form 0? # pad with zeros \-? # left-adjust \ ? # implicit sign [+-]? # sign (\d*|\*) # width (\. (\d*|\*))? # precision [hlL]? # length modifier (but ignored) [acdeEfFgGiorsuxX%] scope: constant.other.placeholder.python captures: 2: variable.other.placeholder.python - match: '{{strftime_spec}}' scope: constant.other.placeholder.python - match: '\{\{|\}\}' scope: constant.character.escape.python - include: formatting-syntax formatting-syntax: # https://docs.python.org/3.6/library/string.html#formatstrings # Technically allows almost every character for the key, # but those are rarely used if ever. - match: |- # simple form (?x) (\{) (?: [\w.\[\]]+)? # field_name ( ! [ars])? # conversion (?: (:) ({{format_spec}}| # format_spec OR [^}%]*%.[^}]*) # any format-like string )? (\}) scope: constant.other.placeholder.python captures: 1: punctuation.definition.placeholder.begin.python 2: storage.modifier.conversion.python 3: punctuation.separator.format-spec.python 4: meta.format-spec.python constant.other.format-spec.python 5: punctuation.definition.placeholder.end.python - match: (?=\{[^{}"']+\{[^"']*\}) # complex (nested) form branch_point: formatting-syntax-branch branch: - formatting-syntax-complex - formatting-syntax-fallback formatting-syntax-fallback: - match: \{ scope: meta.debug.formatting-syntax-fallback.python pop: true formatting-syntax-complex: - match: \{ scope: punctuation.definition.placeholder.begin.python set: - meta_scope: constant.other.placeholder.python - match: \} scope: punctuation.definition.placeholder.end.python pop: true # TODO could match numeric indices or everything else as a key # and also [] indexing - match: '![ars]' scope: storage.modifier.conversion.python - match: ':' scope: punctuation.separator.format-spec.python push: - meta_content_scope: meta.format-spec.python constant.other.format-spec.python - match: (?=\}) pop: true - match: (?=\{) push: formatting-syntax-complex - match: '[{"''\n]' fail: formatting-syntax-branch f-string-content: # https://www.python.org/dev/peps/pep-0498/ # https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings - match: \{\{|\}\} scope: constant.character.escape.python - match: \{\s*\} scope: invalid.illegal.empty-expression.python - match: (?=\{) push: f-string-replacement - match: \} scope: invalid.illegal.stray-brace.python f-string-content-with-regex: # Same as f-string-content, but will reset the entire scope stack # and has an additional match. - match: \\(\{\{|\}\}) scope: constant.character.escape.backslash.regexp captures: 1: constant.character.escape.python - match: \{\{|\}\} scope: constant.character.escape.python - match: \{\s*\} scope: invalid.illegal.empty-expression.python - match: (?=\{) push: f-string-replacement-reset - match: \} scope: invalid.illegal.stray-brace.python f-string-replacement: - clear_scopes: 1 - match: \} scope: meta.interpolation.python punctuation.section.interpolation.end.python pop: true - match: \{ scope: punctuation.section.interpolation.begin.python push: - meta_scope: meta.interpolation.python - match: (?=\}) pop: true - match: '![ars]' scope: storage.modifier.conversion.python - match: = scope: storage.modifier.debug.python - match: ':' push: - meta_scope: meta.format-spec.python constant.other.format-spec.python # Because replacements can also be used *within* the format-spec, # basically any character is valid and matching {{format_spec}} is useless. # - match: '{{format_spec}}' - match: (?=\}) pop: true - include: f-string-content - match: '' push: - meta_content_scope: source.python.embedded - match: (?==?(![^=]|:|\})) pop: true - match: \\ scope: invalid.illegal.backslash-in-fstring.python - include: inline-for - include: expression-in-a-group f-string-replacement-reset: # Same as f-string-replacement, but with clear_scopes: true - clear_scopes: true - meta_scope: source.python meta.string.interpolated.python - match: \} scope: meta.interpolation.python punctuation.section.interpolation.end.python pop: true - match: \{ scope: punctuation.section.interpolation.begin.python push: - meta_scope: meta.interpolation.python - match: (?=\}) pop: true - match: '![ars]' scope: storage.modifier.conversion.python - match: ':' push: - meta_scope: meta.format-spec.python constant.other.format-spec.python - match: (?=\}) pop: true - include: f-string-content - match: '' push: - meta_content_scope: source.python.embedded - match: (?=![^=]|:|\}) pop: true - match: \\ scope: invalid.illegal.backslash-in-fstring.python - include: inline-for - include: expression-in-a-group string-quoted-double-block: # Triple-quoted capital R raw string, unicode or not, no syntax embedding - match: '([uU]?R)(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - include: escaped-unicode-char # Triple-quoted capital R raw string, bytes, no syntax embedding - match: '([bB]R|R[bB])(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression # Triple-quoted raw string, unicode or not, will detect SQL, otherwise regex - match: '([uU]?r)(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '(?={{sql_indicator}})' set: - meta_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.sql with_prototype: - match: '(?=""")' pop: true - include: escaped-unicode-char - include: constant-placeholder - match: '(?=\S)' set: - meta_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.regexp.python with_prototype: - match: '(?=""")' pop: true - include: escaped-unicode-char # Triple-quoted raw string, bytes, will use regex - match: '([bB]r|r[bB])(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - match: '' embed: scope:source.regexp.python escape: (?=""") # Triple-quoted raw f-string - match: ([fF]R|R[fF])(""") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - include: f-string-content # Triple-quoted raw f-string, treated as regex - match: ([fF]r|r[fF])(""") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.regexp.python with_prototype: - match: '(?=""")' pop: true - include: f-string-content-with-regex # Triple-quoted f-string - match: ([fF])(""") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-fstring-escape - include: escaped-unicode-char - include: escaped-char - include: f-string-content # Triple-quoted string, unicode or not, will detect SQL - match: '([uU]?)(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '(?={{sql_indicator}})' set: - meta_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.sql with_prototype: - match: '(?=""")' pop: true - include: line-continuation-inside-block-string - include: escaped-unicode-char - include: escaped-char - include: constant-placeholder - match: '(?=\S)' set: - meta_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-unicode-char - include: escaped-char - include: constant-placeholder # Triple-quoted string, bytes, no syntax embedding - match: '([bB])(""")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.block.python - match: '"""' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-char - include: constant-placeholder string-quoted-double: # Single-line capital R raw string, unicode or not, no syntax embedding - match: '([uU]?R)(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string # Single-line capital R raw string, bytes, no syntax embedding - match: '([bB]R|R[bB])(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string # Single-line raw string, unicode or not, starting with a SQL keyword - match: '([uU]?r)(")(?={{sql_indicator}})' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.sql with_prototype: - match: '(?="|\n)' pop: true - include: constant-placeholder - include: line-continuation-inside-string # Single-line raw string, unicode or not, treated as regex - match: '([uU]?r)(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.regexp.python with_prototype: - match: '(?="|\n)' pop: true - include: line-continuation-inside-string # Single-line raw string, bytes, treated as regex - match: '([bB]r|r[bB])(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' embed: scope:source.regexp.python escape: (?="|\n) # Single-line raw f-string - match: (R[fF]|[fF]R)(") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - include: f-string-content # Single-line raw f-string, treated as regex - match: (r[fF]|[fF]r)(") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.regexp.python with_prototype: - match: '(?="|\n)' pop: true - include: line-continuation-inside-string - include: f-string-content-with-regex # Single-line f-string - match: ([fF])(") captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: escaped-fstring-escape - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: f-string-content # Single-line string, unicode or not, starting with a SQL keyword - match: '([uU]?)(")(?={{sql_indicator}})' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.sql with_prototype: - match: '(?="|\n)' pop: true - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder # Single-line string, unicode or not - match: '([uU]?)(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder # Single-line string, bytes - match: '([bB])(")' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.double.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.double.python - match: '"' scope: punctuation.definition.string.end.python set: after-expression - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder string-quoted-single-block: # Triple-quoted capital R raw string, unicode or not, no syntax embedding - match: ([uU]?R)(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression # Triple-quoted capital R raw string, bytes, no syntax embedding - match: ([bB]R|R[bB])(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression # Triple-quoted raw string, unicode or not, will detect SQL, otherwise regex - match: ([uU]?r)(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: '(?={{sql_indicator}})' set: - meta_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.sql with_prototype: - match: (?=''') pop: true - include: escaped-unicode-char - include: escaped-char - include: constant-placeholder - match: '(?=\S)' set: - meta_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.regexp.python with_prototype: - match: (?=''') pop: true - include: escaped-unicode-char # Triple-quoted raw string, bytes, will use regex - match: ([bB]r|r[bB])(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - match: '' embed: scope:source.regexp.python escape: (?=''') # Triple-quoted raw f-string - match: ([fF]R|R[fF])(''') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - include: f-string-content # Triple-quoted raw f-string, treated as regex - match: ([fF]r|r[fF])(''') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.regexp.python with_prototype: - match: (?=''') pop: true - include: f-string-content-with-regex # Triple-quoted f-string - match: ([fF])(''') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-fstring-escape - include: escaped-unicode-char - include: escaped-char - include: f-string-content # Triple-quoted string, unicode or not, will detect SQL - match: ([uU]?)(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: '(?={{sql_indicator}})' set: - meta_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - match: '' push: scope:source.sql with_prototype: - match: (?=''') pop: true - include: line-continuation-inside-block-string - include: escaped-unicode-char - include: escaped-char - include: constant-placeholder - match: '(?=\S)' set: - meta_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-unicode-char - include: escaped-char - include: constant-placeholder # Triple-quoted string, bytes, no syntax embedding - match: ([bB])(''') captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.block.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.block.python - match: "'''" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-block-string - include: escaped-char - include: constant-placeholder string-quoted-single: # Single-line capital R raw string, unicode or not, no syntax embedding - match: '([uU]?R)('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string # Single-line capital R raw string, bytes, no syntax embedding - match: '([bB]R|R[bB])('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string # Single-line raw string, unicode or not, starting with a SQL keyword - match: '([uU]?r)('')(?={{sql_indicator}})' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.sql with_prototype: - match: '(?=''|\n)' pop: true - include: line-continuation-inside-string - include: constant-placeholder # Single-line raw string, unicode or not, treated as regex - match: '([uU]?r)('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.regexp.python with_prototype: - match: '(?=''|\n)' pop: true - include: line-continuation-inside-string # Single-line raw string, bytes, treated as regex - match: '([bB]r|r[bB])('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.regexp.python with_prototype: - match: '(?=''|\n)' pop: true - include: line-continuation-inside-string # Single-line raw f-string - match: ([fF]R|R[fF])(') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - include: f-string-content # Single-line raw f-string, treated as regex - match: ([fF]r|r[fF])(') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.regexp.python with_prototype: - match: (?='|\n) pop: true - include: line-continuation-inside-string - include: f-string-content-with-regex # Single-line f-string - match: ([fF])(') captures: 1: storage.type.string.python 2: meta.string.interpolated.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.interpolated.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: escaped-fstring-escape - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: f-string-content # Single-line string, unicode or not, starting with a SQL keyword - match: '([uU]?)('')(?={{sql_indicator}})' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: line-continuation-inside-string - match: '' push: scope:source.sql with_prototype: - match: '(?=''|\n)' pop: true - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder # Single-line string, unicode or not - match: '([uU]?)('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: escaped-unicode-char - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder # Single-line string, bytes - match: '([bB])('')' captures: 1: storage.type.string.python 2: meta.string.python string.quoted.single.python punctuation.definition.string.begin.python push: - meta_content_scope: meta.string.python string.quoted.single.python - match: "'" scope: punctuation.definition.string.end.python set: after-expression - include: escaped-char - include: line-continuation-inside-string - include: constant-placeholder strings: # block versions must be matched first - include: string-quoted-double-block - include: string-quoted-double - include: string-quoted-single-block - include: string-quoted-single inline-for: - match: \b(?:(async)\s+)?(for)\b captures: 1: storage.modifier.async.python 2: keyword.control.loop.for.generator.python push: - include: comments - meta_scope: meta.expression.generator.python - match: \bin\b scope: keyword.control.loop.for.in.python pop: true - match: '(?=[)\]}])' scope: invalid.illegal.missing-in.python pop: true - include: illegal-names-pop - include: target-list inline-if: - match: \bif\b scope: keyword.control.conditional.if.python - match: \belse\b scope: keyword.control.conditional.else.python target-list: - match: ',' scope: punctuation.separator.target-list.python - match: \( scope: punctuation.section.target-list.begin.python push: - include: comments - match: ',' scope: punctuation.separator.target-list.python - match: \) scope: punctuation.section.target-list.end.python pop: true - include: target-list - include: name - include: name