%YAML 1.2 --- name: Ruby # TODO: unresolved issues # # text: # "p << end # print me! # end" # symptoms: # not recognized as a heredoc # solution: # there is no way to distinguish perfectly between the << operator and the start # of a heredoc. Currently, we require assignment to recognize a heredoc. More # refinement is possible. # • Heredocs with indented terminators (<<-) are always distinguishable, however. # • Nested heredocs are not really supportable at present # # text: # val?(a):p(b) # val?'a':'b' # symptoms: # ':p' is recognized as a symbol.. its 2 things ':' and 'p'. # :'b' has same problem. # solution: # ternary operator rule, precedence stuff, symbol rule. # but also consider 'a.b?(:c)' ?? file_extensions: - rb - Appfile - Appraisals - Berksfile - Brewfile - capfile - cgi - Cheffile - config.ru - Deliverfile - Fastfile - fcgi - Gemfile - gemspec - Guardfile - irbrc - jbuilder - Podfile - podspec - prawn - rabl - rake - Rakefile - Rantfile - rbx - rjs - ruby.rail - Scanfile - simplecov - Snapfile - thor - Thorfile - Vagrantfile first_line_match: |- (?xi: ^\#! .* \bj?ruby\b | # shebang ^\# \s* -\*- [^*]* ruby [^*]* -\*- # editorconfig ) scope: source.ruby variables: bdigits: (?:[01]+(?:_[01]+)*) ddigits: (?:\d+(?:_\d+)*) hdigits: (?:\h+(?:_\h+)*) odigits: (?:[0-7]+(?:_[0-7]+)*) exponent: (?:[Ee][-+]?{{ddigits}}) heredoc_type_css: (?:[[:upper:]_]_)?CSS heredoc_type_html: (?:[[:upper:]_]_)?HTML heredoc_type_js: (?:[[:upper:]_]_)?(?:JS|JAVASCRIPT) heredoc_type_ruby: (?:[[:upper:]_]_)?RUBY heredoc_type_shell: (?:[[:upper:]_]_)?(?:SH|SHELL) heredoc_type_sql: (?:[[:upper:]_]_)?SQL identifier: '\b[[:alpha:]_][[:alnum:]_]*\b' method_punctuation: '(?:[?!]|=(?![>=]))?' method_name: '{{identifier}}{{method_punctuation}}' path_lookahead: '(::)?({{identifier}}(\.|::))*{{identifier}}' contexts: main: - include: expressions expressions: - include: constants - include: class - include: module - include: invalid - include: blocks - include: keywords - include: well-known-methods - include: variables - include: method - include: strings - include: comments - include: data-section - include: heredocs - include: punctuation - include: operators - include: identifiers-accessors comments: # multiline comments - match: ^=begin scope: punctuation.definition.comment.begin.ruby push: - meta_scope: comment.block.documentation.ruby - match: ^=end scope: punctuation.definition.comment.end.ruby pop: true - match: \#+ scope: punctuation.definition.comment.ruby push: - meta_scope: comment.line.number-sign.ruby - match: \n pop: true class: # Defining a class method - match: \bclass\b(?=\s*<) scope: storage.type.class.ruby keyword.declaration.class.ruby - match: \bclass\b scope: storage.type.class.ruby keyword.declaration.class.ruby push: class-declaration class-declaration: - meta_scope: meta.class.ruby - match: '(?={{path_lookahead}})' set: class-name # Escape if no valid match - match: (?=\S) pop: true class-name: - meta_content_scope: meta.class.ruby entity.name.class.ruby - include: name-parts - match: '' set: class-inheritance class-inheritance: - meta_content_scope: meta.class.ruby - match: '<' scope: punctuation.separator.inheritance.ruby set: - meta_content_scope: meta.class.ruby - match: '(?={{path_lookahead}})' set: - meta_content_scope: meta.class.ruby entity.other.inherited-class.ruby - include: name-parts - match: '' pop: true # Escape if no valid match - match: '(?=\S)' pop: true # Escape if no valid match - match: '(?=\S)' pop: true module: - match: \bmodule\b scope: storage.type.namespace.ruby keyword.declaration.namespace.ruby push: module-declaration module-declaration: - meta_scope: meta.namespace.ruby - match: '(?=(::)?({{identifier}}::)*{{identifier}})' set: - meta_content_scope: meta.namespace.ruby entity.name.namespace.ruby - include: name-parts - match: '' pop: true # Escape if no valid match - match: (?=\S) pop: true name-parts: - match: ({{identifier}})?(?:(::)|(\.)) captures: 1: support.other.namespace.ruby 2: punctuation.accessor.double-colon.ruby 3: punctuation.accessor.dot.ruby - match: '{{identifier}}' invalid: # else if is a common mistake carried over from other languages. it works if you put in a second end, but it’s never what you want. - match: \belse\s+if\b scope: invalid.deprecated.ruby constants: # constant definition, handles multiple definitions on a single line 'APPLE, ORANGE= 1, 2' - match: '\b([[:upper:]]\w*)(?=(\s*,\s*[[:upper:]]\w*)*\s*=(?![=\>]))' scope: meta.constant.ruby entity.name.constant.ruby # Ruby 1.9 symbols - match: '{{identifier}}[?!]?(:)(?!:)' scope: constant.other.symbol.ruby captures: 1: punctuation.definition.constant.ruby push: try-regex - match: '\b(nil|true|false)\b(?![?!])' scope: constant.language.ruby - match: '\b(__(FILE|LINE|ENCODING)__|self)\b(?![?!])' scope: variable.language.ruby # hexadecimal imaginary numbers: 0xAi, 0xAri - match: '\b(0[xX]){{hdigits}}(r?i)(r)?\b' scope: constant.numeric.imaginary.hexadecimal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby 3: invalid.illegal.numeric.ruby # octal imaginary numbers: 0o1i, 0o1ri, 01i, 01ri - match: '\b(0[oO]?){{odigits}}(r?i)(r)?\b' scope: constant.numeric.imaginary.octal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby 3: invalid.illegal.numeric.ruby # binary imaginary numbers: 0b1i, 0b1ri - match: '\b(0[bB]){{bdigits}}(r?i)(r)?\b' scope: constant.numeric.imaginary.binary.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby 3: invalid.illegal.numeric.ruby # decimal imaginary numbers: 0d1i, 0d1ri, 1i, 1ri, 1.1i, 1.1ri, 1e1i, 1.1e1i - match: |- \b(?x: (?: # 0d1i, 0d1ri, 1i, 1ri | 1.1i, 1.1ri (?: (0[dD])? {{ddigits}} | {{ddigits}} (\.) {{ddigits}} ) (r?i) # 1e1i, 1.1e1i | {{ddigits}} (?: (\.) {{ddigits}} )? {{exponent}} (r)? (i) ) (r)? )\b scope: constant.numeric.imaginary.decimal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: punctuation.separator.decimal.ruby 3: storage.type.numeric.ruby 4: punctuation.separator.decimal.ruby 5: invalid.illegal.numeric.ruby 6: storage.type.numeric.ruby 7: invalid.illegal.numeric.ruby # hexadecimal rational numbers: 0xAr - match: '\b(0[xX]){{hdigits}}(r)\b' scope: constant.numeric.rational.hexadecimal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby # octal rational numbers: 0o1r, 01r - match: '\b(0[oO]?){{odigits}}(r)\b' scope: constant.numeric.rational.octal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby # binary rational numbers: 0b1r - match: '\b(0[bB]){{bdigits}}(r)\b' scope: constant.numeric.rational.binary.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: storage.type.numeric.ruby # decimal rational numbers: 0d1r, 1r, 1.1r - match: '\b(?:(0[dD])?{{ddigits}}|{{ddigits}}(\.){{ddigits}})(r)\b' scope: constant.numeric.rational.decimal.ruby captures: 1: punctuation.definition.numeric.base.ruby 2: punctuation.separator.decimal.ruby 3: storage.type.numeric.ruby # decimal floating point numbers: 1.1, 1e1, 1.1e1 - match: '\b{{ddigits}}(?:(\.){{ddigits}}|(?:(\.){{ddigits}})?{{exponent}}(r)?)\b' scope: constant.numeric.float.decimal.ruby captures: 1: punctuation.separator.decimal.ruby 2: punctuation.separator.decimal.ruby 3: invalid.illegal.numeric.rational.ruby # hexadecimal integer numbers: 0xA - match: '\b(0[xX]){{hdigits}}\b' scope: constant.numeric.integer.hexadecimal.ruby captures: 1: punctuation.definition.numeric.base.ruby # octal integer numbers: 0o1, 01 - match: '\b(0[oO]?){{odigits}}\b' scope: constant.numeric.integer.octal.ruby captures: 1: punctuation.definition.numeric.base.ruby # binary integer numbers: 0b1 - match: '\b(0[bB]){{bdigits}}\b' scope: constant.numeric.integer.binary.ruby captures: 1: punctuation.definition.numeric.base.ruby # decimal integer numbers: 0d1, 1 - match: '\b(0[dD])?{{ddigits}}\b' scope: constant.numeric.integer.decimal.ruby captures: 1: punctuation.definition.numeric.base.ruby # Quoted symbols - match: ":'" scope: punctuation.definition.constant.ruby push: - meta_scope: meta.constant.ruby constant.other.symbol.single-quoted.ruby - match: "'" scope: punctuation.definition.constant.ruby pop: true - match: '\\[''\\]' scope: constant.character.escape.ruby - match: ':"' scope: punctuation.definition.constant.ruby push: - meta_scope: meta.constant.ruby constant.other.symbol.double-quoted.ruby - match: '"' scope: punctuation.definition.constant.ruby pop: true - include: interpolated-ruby - include: escaped-char # Unquoted symbols - match: |- (?x: (:) ( {{identifier}}{{method_punctuation}}| ===?| >[>=]?| <[<=]?| <=>| [%&`/\|]| \*\*?| =?~| [-+]@?| \[\]=?| @@?{{identifier}} ) ) scope: constant.other.symbol.ruby captures: 1: punctuation.definition.constant.ruby # questionmark literals - match: ((\?)\\u)(\{) captures: 1: constant.character.ruby 2: punctuation.definition.constant.ruby 3: meta.braces.ruby punctuation.section.braces.begin.ruby push: - meta_scope: meta.constant.ruby - meta_content_scope: meta.braces.ruby - match: \} scope: meta.braces.ruby punctuation.section.braces.end.ruby pop: true - match: \h{0,6} scope: constant.numeric.integer.hexadecimal.ruby - match: \S scope: invalid.illegal.escape.ruby - match: |- (?x: (\?)(?: # examples (meta control sequences): # ?\C-a ?\M-a ?\M-\C-a ?\ca ?\M-ca (?:\\(?:[MC]-|c)){1,2}[[:ascii:]] | \\(?: # examples (hex): # ?\x1 ?\x61 x\h{1,2}\b | # examples (octal): # ?\0 ?\07 ?\017 0[0-7]{0,2}\b | # examples (escaped): # ?\n ?\b ?\\ .(?!\w) ) | # examples (illegal): # ?abc ?\xAG ?\\n # ?_a0 ([[:alpha:]_\\]\S+)\b(?!\s*:) | # examples (normal): # ?a ?A ?0 # ?* ?" ?( # ?. ?# ?\ [[:alnum:]_]\b(?!\s*:) | [^[:alnum:]_\s] ) ) scope: constant.character.ruby captures: 1: punctuation.definition.constant.ruby 2: invalid.illegal.character.ruby blocks: - match: \bdo\b scope: keyword.control.block.do.ruby push: maybe-block-parameters - match: \{ scope: punctuation.section.scope.ruby push: maybe-block-parameters maybe-block-parameters: - match: \| scope: meta.block.parameters.ruby punctuation.definition.parameters.begin.ruby set: block-parameters - match: (?=\s*[^\s\|]) pop: true block-parameters: - meta_content_scope: meta.block.parameters.ruby - match: \| scope: meta.block.parameters.ruby punctuation.definition.parameters.end.ruby set: try-regex - match: '{{identifier}}' scope: variable.parameter.ruby - match: ',' scope: punctuation.separator.ruby - match: \* scope: keyword.operator.splat.ruby - match: '&' scope: keyword.operator.ruby - match: '(?==)' set: - meta_content_scope: meta.block.parameters.default-value.ruby - match: '=' scope: keyword.operator.assignment.ruby set: - meta_content_scope: meta.block.parameters.default-value.ruby - match: '(?=[,\|])' set: block-parameters - include: nest-all - include: expressions keywords: # blocks - match: \bbegin\b(?![?!]) scope: keyword.control.block.begin.ruby push: after-keyword - match: \bend\b(?![?!]) scope: keyword.control.block.end.ruby # conditional - match: \bcase\b(?![?!]) scope: keyword.control.conditional.case.ruby push: after-keyword - match: \belse\b(?![?!]) scope: keyword.control.conditional.if.ruby push: after-keyword - match: \belsif\b(?![?!]) scope: keyword.control.conditional.elseif.ruby push: after-keyword - match: \bif\b(?![?!]) scope: keyword.control.conditional.if.ruby push: after-keyword - match: \bthen\b(?![?!]) scope: keyword.control.conditional.then.ruby - match: \bunless\b(?![?!]) scope: keyword.control.conditional.unless.ruby push: after-keyword - match: \bwhen\b(?![?!]) scope: keyword.control.conditional.when.ruby push: after-keyword # exception - match: \bensure\b(?![?!]) scope: keyword.control.exception.ensure.ruby push: after-keyword - match: \brescue\b(?![?!]) scope: keyword.control.exception.rescue.ruby push: after-keyword # loop - match: \bfor\b(?![?!]) scope: keyword.control.loop.for.ruby push: after-keyword - match: \buntil\b(?![?!]) scope: keyword.control.loop.until.ruby push: after-keyword - match: \bwhile\b(?![?!]) scope: keyword.control.loop.while.ruby push: after-keyword # flow - match: \bbreak\b(?![?!]) scope: keyword.control.flow.break.ruby - match: \bnext\b(?![?!]) scope: keyword.control.flow.next.ruby - match: \bredo\b(?![?!]) scope: keyword.control.flow.redo.ruby - match: \bretry\b(?![?!]) scope: keyword.control.flow.retry.ruby - match: \breturn\b(?![?!]) scope: keyword.control.flow.return.ruby - match: \byield\b(?![?!]) scope: keyword.control.flow.yield.ruby # declarations - match: \b(?:alias|alias_method)\b(?![?!]) scope: keyword.declaration.alias.ruby push: after-keyword - match: \bundef\b(?![?!]) scope: keyword.declaration.undef.ruby push: after-keyword # operators - match: \b(?:and|not|or)\b scope: keyword.operator.logical.ruby push: after-keyword - match: \bin\b(?![?!]) scope: keyword.operator.logical.ruby push: after-keyword # other functions - match: \b(?:BEGIN|END)\b(?![?!]) scope: entity.name.function.prepocessor.ruby - match: \b(?:defined|block_given)\? scope: support.function.builtin.ruby push: after-keyword - match: \bsuper\b(?![?!]) scope: support.function.builtin.ruby push: after-keyword operators: - match: '>>' scope: keyword.operator.other.ruby push: after-operator # note: `/=` is matched in the `regexes` context - match: <<=|&&=|\|\|=|\*\*=|[-+*&|^]=|<< scope: keyword.operator.assignment.augmented.ruby push: after-operator - match: <=>|===|<=|>=|==|=~|!=|!~|<|> scope: keyword.operator.comparison.ruby push: after-operator - match: \*\*|[-+*/%] scope: keyword.operator.arithmetic.ruby push: after-operator - match: = scope: keyword.operator.assignment.ruby push: after-operator - match: '!+|&&|\|\|' scope: keyword.operator.logical.ruby push: after-operator - match: '[~&|^]' scope: keyword.operator.bitwise.ruby push: after-operator - match: \? scope: keyword.operator.conditional.ruby push: # Handle hash-key-lookalike of identifier: in ternary - match: \s*{{identifier}}(:)(?!:) captures: 1: keyword.operator.conditional.ruby set: after-operator - include: after-operator - match: :(?!:) scope: keyword.operator.conditional.ruby push: after-operator - match: \.\.\.? scope: keyword.operator.range.ruby push: after-operator punctuation: - match: => scope: punctuation.separator.key-value.ruby push: after-operator - match: ',' scope: punctuation.separator.sequence.ruby push: after-operator - match: ; scope: punctuation.terminator.statement.ruby push: after-operator - match: \[ scope: punctuation.section.array.ruby push: after-operator - match: \( scope: punctuation.definition.group.begin.ruby push: after-operator # Opening { is handled by "block" context to try and detect parameters - match: \} scope: punctuation.section.scope.ruby - match: \] scope: punctuation.section.array.ruby - match: \) scope: punctuation.definition.group.end.ruby identifiers-accessors: # This consumes class/module access to prevent issues parsing : as part # of a ternary operator - match: ::(?={{identifier}}{{method_punctuation}}) scope: punctuation.accessor.double-colon.ruby push: - include: well-known-methods - match: '{{identifier}}{{method_punctuation}}' - match: '' set: after-identifier # This consumes attribute access so we don't need a lookbehind for . - match: \.(?={{identifier}}{{method_punctuation}}) scope: punctuation.accessor.dot.ruby push: - include: well-known-methods - match: '{{identifier}}{{method_punctuation}}' - match: '' set: after-identifier # This consumes method names ending in punctuation so we don't need a lookbehind for ?, ! or = - match: '{{identifier}}{{method_punctuation}}' # This consumes module/class accessor so we don't need a lookbehind for :: push: after-identifier - match: \. scope: punctuation.accessor.dot.ruby - match: '::' scope: punctuation.accessor.double-colon.ruby after-identifier: # Handles a : right after an identifier. In this case it can't be the # beginning of a symbol, so it must be part of a ternary operator - match: ':(?!:)' scope: keyword.operator.conditional.ruby pop: true - match: '' pop: true variables: - match: '(@)[a-zA-Z_]\w*' scope: variable.other.readwrite.instance.ruby captures: 1: punctuation.definition.variable.ruby - match: '(@@)[a-zA-Z_]\w*' scope: variable.other.readwrite.class.ruby captures: 1: punctuation.definition.variable.ruby - match: '(\$)[a-zA-Z_]\w*' scope: variable.other.readwrite.global.ruby captures: 1: punctuation.definition.variable.ruby - match: '(\$)(!|@|&|`|''|\+|\d+|~|=|/|\\|,|;|\.|<|>|_|\*|\$|\?|:|"|-[0adFiIlpv])' scope: variable.other.readwrite.global.pre-defined.ruby captures: 1: punctuation.definition.variable.ruby - match: '\b(ENV)\[' captures: 1: variable.other.constant.ruby push: - meta_scope: meta.environment-variable.ruby - match: '\]' pop: true - include: expressions - match: '(::)?(\b[[:upper:]]\w*)(?=((\.|::)[[:alpha:]_]|\[))' captures: 1: punctuation.accessor.double-colon.ruby 2: support.class.ruby - match: '\b[[:upper:]]\w*\b' scope: variable.other.constant.ruby well-known-methods: # exceptions - match: \bcatch\b(?![?!]) scope: keyword.control.exception.catch.ruby push: function-call-arguments # flow - match: \b(?:fail|raise|throw)\b(?![?!]) scope: keyword.control.flow.throw.ruby push: function-call-arguments # loop - match: \bloop\b(?![?!]) scope: keyword.control.loop.loop.ruby push: function-call-arguments # other - match: \b(initialize|new|include|extend|prepend|attr_reader|attr_writer|attr_accessor|attr|module_function|public|protected|private)\b(?![?!]) scope: keyword.other.special-method.ruby push: function-call-arguments - match: \b(require|require_relative|gem)\b scope: keyword.control.import.ruby push: - meta_scope: meta.require.ruby - match: $|(?=[#}]) pop: true - include: expressions # Conversion methods - match: |- (?x: \b( to_ary| to_a| to_c| to_enum| to_f| to_hash| to_h| to_int| to_io| to_i| to_proc| to_r| to_str| to_sym| to_s )\b (?![!?=]) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods that may be followed by a regex - match: |- (?x: \b( gsub| sub )(!|\b) | \b( match )(\?|\b) | \b( assert_match| assert_no_match| index| rindex| scan )\b(?![!?=]) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Object class not handled elsewhere, ending in punctuation - match: |- (?x: \b( eql\?| instance_of\?| instance_variable_defined\?| is_a\?| kind_of\?| nil\?| respond_to\?| respond_to_missing\?| tainted\?| untrusted\? ) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Object class not handled elsewhere - match: |- (?x: \b( class| clone| define_singleton_method| display| dup| enum_for| extend| freeze| frozen?| hash| inspect| instance_variable_get| instance_variable_set| instance_variables| itself| method| methods| object_id| private_methods| protected_methods| public_method| public_methods| public_send| remove_instance_variable| send| singleton_class| singleton_method| singleton_methods| taint| tap| trust| untaint| untrust )\b (?![!?=]) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Kernel class not handled elsewhere, ending in punctuation - match: |- (?x: \b( autoload\?| iterator\?| exit! ) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Kernel class not handled elsewhere - match: |- (?x: \b( Array| Complex| Float| Hash| Integer| Rational| String| __callee__| __dir__| __method__| abort| at_exit| autoload| binding| callcc| caller| caller_locations| chomp| chop| eval| exec| exit| fork| format| gets| global_variables| gsub| lambda| load| local_variables| open| p| print| printf| proc| putc| puts| rand| readline| readlines| require| require_relative| select| set_trace_func| sleep| spawn| sprintf| srand| sub| syscall| system| test| trace_var| trap| untrace_var| warn )\b (?![!?=]) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Kernel class not handled elsewhere, ending in punctuation - match: |- (?x: \b( class_variable_defined\?| const_defined\?| include\?| instance_methods\?| method_defined\?| private_method_defined\?| protected_method_defined\?| public_method_defined\?| singleton_class\? ) ) scope: support.function.builtin.ruby push: function-call-arguments # Methods from the Module class not handled elsewhere - match: |- (?x: \b( ancestors| append_features| class_eval| class_exec| class_variable_get| class_variable_set| class_variables| const_get| const_missing| const_set| constants| define_method| extend_object| extended| freeze| included| included_modules| inspect| method_added| method_removed| method_undefined| module_eval| module_exec| name| prepend_features| prepended| private_class_method| private_constant| private_instance_methods| protected_instance_methods| public_class_method| public_constant| public_instance_method| public_instance_methods| refine| remove_class_variable| remove_const| remove_method| undef_method| using )\b (?![!?=]) ) scope: support.function.builtin.ruby push: function-call-arguments function-call-arguments: - include: try-regex method: - match: \bdef\b scope: meta.function.ruby storage.type.function.ruby keyword.declaration.function.ruby push: - meta_content_scope: meta.function.ruby - match: '(self)(\.)({{identifier}}{{method_punctuation}}|===?|>[>=]?|<=>|<[<=]?|[%&`/\|]|\*\*?|=?~|[-+]@?|\[\]=?)' captures: 1: variable.language.ruby 2: punctuation.accessor.dot.ruby 3: entity.name.function.ruby set: method-parameters-start - match: '===?|>[>=]?|<=>|<[<=]?|[%&`/\|]|\*\*?|=?~|[-+]@?|\[\]=?' scope: entity.name.function.ruby set: method-parameters-start - match: '(?:({{identifier}})(?:(::)|(\.)))?{{identifier}}{{method_punctuation}}' scope: entity.name.function.ruby captures: 1: support.other.namespace.ruby 2: punctuation.accessor.double-colon.ruby 3: punctuation.accessor.dot.ruby set: method-parameters-start - match: '$' pop: true - match: '(?=\S)' pop: true method-parameters-start: - meta_content_scope: meta.function.ruby - match: '(?=\()' set: - meta_content_scope: meta.function.parameters.ruby - match: '\(' scope: punctuation.definition.group.begin.ruby set: method-parameters # No parameters - match: '(?=$|;|#)' pop: true # No parentheses around parameters - match: '(?=[[:alpha:]_*])' set: method-bare-parameters method-parameters: - meta_content_scope: meta.function.parameters.ruby - match: '\)' scope: meta.function.parameters.ruby punctuation.definition.group.end.ruby pop: true - match: '{{identifier}}' scope: variable.parameter.ruby - include: comments - match: ',' scope: punctuation.separator.ruby - match: '\*' scope: keyword.operator.splat.ruby - match: '&' scope: keyword.operator.ruby # De-structuring - match: \( scope: punctuation.definition.group.begin.ruby push: - match: \) scope: punctuation.definition.group.end.ruby pop: true - match: '{{identifier}}' scope: variable.parameter.ruby - match: ',' scope: punctuation.separator.ruby - match: '\*' scope: keyword.operator.splat.ruby # Default values - match: (?==) set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '=' scope: keyword.operator.assignment.ruby set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '(?=[,\)])' set: method-parameters - include: nest-all - include: expressions # Keyword parameter (with default value support) - match: (?=:) set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: ':' scope: punctuation.separator.ruby set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '(?=[,\)])' set: method-parameters - include: nest-all - include: expressions # When no parentheses are placed around the parameters method-bare-parameters: - meta_content_scope: meta.function.parameters.ruby - match: '(?=$|;|#)' pop: true - match: '{{identifier}}' scope: variable.parameter.ruby - match: ',' scope: punctuation.separator.ruby - match: '\*' scope: keyword.operator.splat.ruby - match: '&' scope: keyword.operator.ruby # Default values - match: (?==) set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '=' scope: punctuation.operator.assignment.ruby set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '(?=$|[,;])' set: method-bare-parameters - include: nest-all - include: expressions # Keyword parameter (with default value support) - match: (?=:) set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: ':' scope: punctuation.separator.ruby set: - meta_content_scope: meta.function.parameters.default-value.ruby - match: '(?=$|[,;])' set: method-bare-parameters - include: nest-all - include: expressions strings: - include: early-strings - include: regexes - include: late-strings early-strings: # single quoted string (does not allow interpolation) - match: "'" scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.single.ruby - match: "'" scope: punctuation.definition.string.end.ruby pop: true - match: \\'|\\\\ scope: constant.character.escape.ruby - include: string-placeholder # double quoted string (allows for interpolation) - match: '"' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.double.ruby - match: '"' scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: string-placeholder # execute string (allows for interpolation) - match: "`" scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: "`" scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char # execute string (allow for interpolation) - match: '%x\{' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: '\}' scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-curly-i # execute string (allow for interpolation) - match: '%x\[' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: '\]' scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-brackets-i # execute string (allow for interpolation) - match: '%x\<' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: \> scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-ltgt-i # execute string (allow for interpolation) - match: '%x\(' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: \) scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-parens-i # execute string (allow for interpolation) - match: '%x([^\w])' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.interpolated.ruby - match: \1 scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char late-strings: # literal capable of interpolation () - match: '%[QWI]?\(' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.upper.ruby - match: \) scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-parens-i # "literal capable of interpolation []" - match: '%[QWI]?\[' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.upper.ruby - match: '\]' scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-brackets-i # literal capable of interpolation <> - match: '%[QWI]?\<' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.upper.ruby - match: \> scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-ltgt-i # literal capable of interpolation -- {} - match: '%[QWI]?\{' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.double.ruby.mod - match: '\}' scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-curly-i # literal capable of interpolation -- wildcard - match: '%[QWI]([^\w])' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.upper.ruby - match: \1 scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char # literal capable of interpolation -- wildcard - match: '%([^\w\s=])' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.other.ruby - match: \1 scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char # literal incapable of interpolation -- () - match: '%[qwsi]\(' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.lower.ruby - match: \) scope: punctuation.definition.string.end.ruby pop: true - match: \\\)|\\\\ scope: constant.character.escape.ruby - include: nest-parens # literal incapable of interpolation -- <> - match: '%[qwsi]\<' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.lower.ruby - match: \> scope: punctuation.definition.string.end.ruby pop: true - match: \\\>|\\\\ scope: constant.character.escape.ruby - include: nest-ltgt # literal incapable of interpolation -- [] - match: '%[qwsi]\[' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.lower.ruby - match: '\]' scope: punctuation.definition.string.end.ruby pop: true - match: '\\\]|\\\\' scope: constant.character.escape.ruby - include: nest-brackets # literal incapable of interpolation -- {} - match: '%[qwsi]\{' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.lower.ruby - match: '\}' scope: punctuation.definition.string.end.ruby pop: true - match: '\\\}|\\\\' scope: constant.character.escape.ruby - include: nest-curly # literal incapable of interpolation -- wildcard - match: '%[qwsi]([^\w])' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.quoted.other.literal.lower.ruby - match: \1 scope: punctuation.definition.string.end.ruby pop: true # Cant be named because its not necessarily an escape - match: \\. after-keyword: - include: try-regex after-operator: - include: try-regex try-regex: # Generally for multiline regexes, one of the %r forms below will be used, # so we bail out if we can't find a second / on the current line - match: \s*(/)(?=(?!=).*/) captures: 1: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.regexp.ruby string.regexp.classic.ruby - match: (/)([eimnosux]*) captures: 1: punctuation.definition.string.end.ruby 2: keyword.other.ruby pop: true - include: regex-sub - match: '' pop: true regexes: # Needs higher precedence than regular expressions. - match: /= scope: keyword.operator.assignment.augmented.ruby - match: '(?=^\s*/)' push: try-regex - match: (?=/\s*[^\w\(\s@"']) push: try-regex # regular expressions (literal) - match: '%r\{' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.regexp.mod-r.ruby - match: '\}[eimnosux]*' scope: punctuation.definition.string.end.ruby pop: true - include: regex-sub - include: nest-curly-r # regular expressions (literal) - match: '%r\[' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.regexp.mod-r.ruby - match: '\][eimnosux]*' scope: punctuation.definition.string.end.ruby pop: true - include: regex-sub - include: nest-brackets-r # regular expressions (literal) - match: '%r\(' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.regexp.mod-r.ruby - match: '\)[eimnosux]*' scope: punctuation.definition.string.end.ruby pop: true - include: regex-sub - include: nest-parens-r # regular expressions (literal) - match: '%r\<' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.regexp.mod-r.ruby - match: '\>[eimnosux]*' scope: punctuation.definition.string.end.ruby pop: true - include: regex-sub - include: nest-ltgt-r # regular expressions (literal) - match: '%r([^\w])' scope: punctuation.definition.string.begin.ruby push: - meta_scope: meta.string.ruby string.regexp.mod-r.ruby - match: '\1[eimnosux]*' scope: punctuation.definition.string.end.ruby pop: true - include: regex-sub regex-sub: - include: interpolated-ruby - include: escaped-char - match: '(\{)\d+(,\d+)?(\})' scope: meta.string.ruby string.regexp.arbitrary-repetition.ruby captures: 1: punctuation.definition.arbitrary-repetition.ruby 3: punctuation.definition.arbitrary-repetition.ruby - match: '\[(?:\^?\])?' scope: punctuation.definition.character-class.ruby push: - meta_scope: meta.string.ruby string.regexp.character-class.ruby - match: '\]' scope: punctuation.definition.character-class.ruby pop: true - include: escaped-char - match: \( scope: punctuation.definition.group.ruby push: - meta_scope: meta.string.ruby string.regexp.group.ruby - match: \) scope: punctuation.definition.group.ruby pop: true - include: regex-sub # We are restrictive in what we allow to go after the comment character to # avoid false positives, since the availability of comments depend on regexp # flags. - match: '(?:^|\s)(#)\s[[a-zA-Z0-9,. \t?!-][^\x{00}-\x{7F}]]*$' scope: comment.line.number-sign.ruby captures: 1: punctuation.definition.comment.ruby nest-brackets-r: - match: '\[' scope: punctuation.section.scope.ruby push: - match: '\]' scope: punctuation.section.scope.ruby pop: true - include: regex-sub - include: nest-brackets-r nest-curly-r: - match: '\{' scope: punctuation.section.scope.ruby push: - match: '\}' scope: punctuation.section.scope.ruby pop: true - include: regex-sub - include: nest-curly-r nest-ltgt-r: - match: \< scope: punctuation.section.scope.ruby push: - match: \> scope: punctuation.section.scope.ruby pop: true - include: regex-sub - include: nest-ltgt-r nest-parens-r: - match: \( scope: punctuation.section.scope.ruby push: - match: \) scope: punctuation.section.scope.ruby pop: true - include: regex-sub - include: nest-parens-r nest-brackets: - match: '\[' scope: punctuation.section.scope.ruby push: - match: '\]' scope: punctuation.section.scope.ruby pop: true - include: nest-brackets nest-curly: - match: '\{' scope: punctuation.section.scope.ruby push: [nest-curly-inner, maybe-block-parameters] nest-curly-inner: - match: '\}' scope: punctuation.section.scope.ruby pop: true - include: nest-curly nest-ltgt: - match: \< scope: punctuation.section.scope.ruby push: - match: \> scope: punctuation.section.scope.ruby pop: true - include: nest-ltgt nest-parens: - match: \( scope: punctuation.section.scope.ruby push: - match: \) scope: punctuation.section.scope.ruby pop: true - include: nest-parens string-placeholder: # %[flags][width][.precision]type # # A format sequence consists of a percent sign, followed by optional # flags, width, and precision indicators, then terminated with a field # type character. # # Also this is used for time format in strftime. - match: |- (?x)% ([#0\- +\*]|(\d+\$))* # flags (-?\d+)? # minimum field width (\.(\d+)?)? # precision [diouxXDOUeEfFgGaAcCsSpnvtTbByYhHmMzZ%] # conversion type scope: constant.other.placeholder.ruby escaped-char: # SEE: https://ruby-doc.org/core-2.6.3/doc/syntax/literals_rdoc.html # meta control sequence - match: (?:\\(?:[MC]-|c)){1,2}[[:ascii:]] scope: constant.character.escape.ruby # extended unicode character - match: \\u\{ push: - meta_scope: constant.character.escape.ruby - match: \} pop: true - match: \h{0,6} - match: \S scope: invalid.illegal.escape.ruby # octal, hex, unicode, normal escaped character - match: \\(?:[0-7]{1,3}|x\h{1,2}|u\h{4}|.) scope: constant.character.escape.ruby interpolated-ruby: - match: '#\{' scope: punctuation.section.interpolation.begin.ruby push: - clear_scopes: 1 # remove `string`/`constant` - meta_scope: meta.interpolation.ruby - meta_content_scope: source.ruby.embedded.ruby - include: interpolated-ruby-expressions - match: '(?=#[@$])' push: - clear_scopes: 1 # remove `string`/`constant` - meta_scope: meta.interpolation.ruby - include: interpolated-ruby-variables interpolated-heredoc-ruby: - match: '#\{' scope: punctuation.section.interpolation.begin.ruby push: - meta_scope: meta.interpolation.ruby - meta_content_scope: source.ruby.embedded.ruby - include: interpolated-ruby-expressions - match: '(?=#[@$])' push: - meta_scope: meta.interpolation.ruby - include: interpolated-ruby-variables interpolated-ruby-expressions: - match: '\}' scope: punctuation.section.interpolation.end.ruby pop: true - include: nest-curly-expressions - include: expressions interpolated-ruby-variables: - match: '(#@)[[:alpha:]_]\w*' scope: variable.other.readwrite.instance.ruby captures: 1: punctuation.definition.variable.ruby pop: true - match: '(#@@)[[:alpha:]_]\w*' scope: variable.other.readwrite.class.ruby captures: 1: punctuation.definition.variable.ruby pop: true - match: '(#\$)[[:alpha:]_]\w*' scope: variable.other.readwrite.global.ruby captures: 1: punctuation.definition.variable.ruby pop: true - match: '' pop: true nest-curly-expressions: - match: '\{' scope: punctuation.section.scope.ruby push: [nest-curly-expressions-inner, maybe-block-parameters] nest-curly-expressions-inner: - match: '\}' scope: punctuation.section.scope.ruby pop: true - include: nest-curly-expressions - include: expressions nest-all: - match: '\(' scope: punctuation.definition.group.begin.ruby push: - match: '\)' scope: punctuation.definition.group.end.ruby pop: true - include: nest-all - include: expressions - match: '\{' scope: punctuation.section.scope.ruby push: [nest-all-inner, maybe-block-parameters] - match: '\[' scope: punctuation.section.array.ruby push: - match: '\]' scope: punctuation.section.array.ruby pop: true - include: nest-all - include: expressions nest-all-inner: - match: '\}' scope: punctuation.section.scope.ruby pop: true - include: nest-all - include: expressions nest-brackets-i: - match: '\[' scope: punctuation.section.scope.ruby push: - match: '\]' scope: punctuation.section.scope.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-brackets-i nest-curly-i: - match: '\{' scope: punctuation.section.scope.ruby push: [nest-curly-i-inner, maybe-block-parameters] nest-curly-i-inner: - match: '\}' scope: punctuation.section.scope.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-curly-i nest-ltgt-i: - match: \< scope: punctuation.section.scope.ruby push: - match: \> scope: punctuation.section.scope.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-ltgt-i nest-parens-i: - match: \( scope: punctuation.section.scope.ruby push: - match: \) scope: punctuation.section.scope.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: nest-parens-i ###[ HEREDOCS ]################################################################ heredocs: # SEE: https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html - include: heredoc-css - include: heredoc-js - include: heredoc-html - include: heredoc-ruby - include: heredoc-shell - include: heredoc-sql - include: heredoc-plain heredoc-css: - match: <<[-~]["`]?({{heredoc_type_css}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-css-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_css}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-css-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_css}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-css-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_css}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-css-unindented-literal, trailing-heredoc-start] heredoc-css-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.css.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: scope:source.css - include: escaped-char heredoc-css-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.css.embedded.ruby - include: indented-heredoc-end - include: scope:source.css heredoc-css-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.css.embedded.ruby - include: unindented-heredoc-end - include: scope:source.css - include: escaped-char heredoc-css-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.css.embedded.ruby - include: unindented-heredoc-end - include: scope:source.css heredoc-js: - match: <<[-~]["`]?({{heredoc_type_js}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-js-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_js}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-js-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_js}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-js-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_js}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-js-unindented-literal, trailing-heredoc-start] heredoc-js-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.js.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: scope:source.js - include: escaped-char heredoc-js-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.js.embedded.ruby - include: indented-heredoc-end - include: scope:source.js heredoc-js-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.js.embedded.ruby - include: unindented-heredoc-end - include: scope:source.js - include: escaped-char heredoc-js-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.js.embedded.ruby - include: unindented-heredoc-end - include: scope:source.js heredoc-html: - match: <<[-~]["`]?({{heredoc_type_html}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-html-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_html}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-html-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_html}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-html-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_html}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-html-unindented-literal, trailing-heredoc-start] heredoc-html-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: text.html.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: scope:text.html.basic - include: escaped-char heredoc-html-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: text.html.embedded.ruby - include: indented-heredoc-end - include: scope:text.html.basic heredoc-html-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: text.html.embedded.ruby - include: unindented-heredoc-end - include: scope:text.html.basic - include: escaped-char heredoc-html-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: text.html.embedded.ruby - include: unindented-heredoc-end - include: scope:text.html.basic heredoc-ruby: - match: <<[-~]["`]?({{heredoc_type_ruby}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-ruby-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_ruby}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-ruby-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_ruby}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-ruby-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_ruby}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-ruby-unindented-literal, trailing-heredoc-start] heredoc-ruby-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.ruby.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: escaped-char - include: expressions heredoc-ruby-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.ruby.embedded.ruby - include: indented-heredoc-end - include: expressions heredoc-ruby-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.ruby.embedded.ruby - include: unindented-heredoc-end - include: interpolated-heredoc-ruby - include: escaped-char - include: expressions heredoc-ruby-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.ruby.embedded.ruby - include: unindented-heredoc-end - include: expressions heredoc-plain: - match: <<[-~]["`]?(\w+)["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-plain-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'(\w+)' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-plain-indented-literal, trailing-heredoc-start] - match: <<["`]?(\w+)["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-plain-unindented-interpolated, trailing-heredoc-start] - match: <<'(\w+)' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-plain-unindented-literal, trailing-heredoc-start] heredoc-plain-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: string.unquoted.heredoc.ruby - include: indented-heredoc-end - include: interpolated-ruby - include: escaped-char heredoc-plain-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: string.unquoted.heredoc.ruby - include: indented-heredoc-end heredoc-plain-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: string.unquoted.heredoc.ruby - include: unindented-heredoc-end - include: interpolated-ruby - include: escaped-char heredoc-plain-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: string.unquoted.heredoc.ruby - include: unindented-heredoc-end heredoc-shell: - match: <<[-~]["`]?({{heredoc_type_shell}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-shell-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_shell}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-shell-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_shell}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-shell-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_shell}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-shell-unindented-literal, trailing-heredoc-start] heredoc-shell-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.shell.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: scope:source.shell - include: escaped-char heredoc-shell-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.shell.embedded.ruby - include: indented-heredoc-end - include: scope:source.shell heredoc-shell-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.shell.embedded.ruby - include: unindented-heredoc-end - include: scope:source.shell - include: escaped-char heredoc-shell-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.shell.embedded.ruby - include: unindented-heredoc-end - include: scope:source.shell heredoc-sql: - match: <<[-~]["`]?({{heredoc_type_sql}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-sql-indented-interpolated, trailing-heredoc-start] - match: <<[-~]'({{heredoc_type_sql}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-sql-indented-literal, trailing-heredoc-start] - match: <<["`]?({{heredoc_type_sql}})["`]? scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-sql-unindented-interpolated, trailing-heredoc-start] - match: <<'({{heredoc_type_sql}})' scope: string.unquoted.heredoc.ruby punctuation.definition.string.begin.ruby push: [heredoc-sql-unindented-literal, trailing-heredoc-start] heredoc-sql-indented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.sql.embedded.ruby - include: indented-heredoc-end - include: interpolated-heredoc-ruby - include: scope:source.sql - include: escaped-char heredoc-sql-indented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.sql.embedded.ruby - include: indented-heredoc-end - include: scope:source.sql heredoc-sql-unindented-interpolated: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.sql.embedded.ruby - include: unindented-heredoc-end - include: scope:source.sql - include: escaped-char heredoc-sql-unindented-literal: - meta_scope: meta.string.heredoc.ruby - meta_content_scope: source.sql.embedded.ruby - include: unindented-heredoc-end - include: scope:source.sql indented-heredoc-end: - match: ^\s*(\1)$ # HEREDOC delimiter scope: string.unquoted.heredoc.ruby captures: 1: punctuation.definition.string.end.ruby pop: true unindented-heredoc-end: - match: ^\1$ # HEREDOC delimiter scope: string.unquoted.heredoc.ruby punctuation.definition.string.end.ruby pop: true trailing-heredoc-start: # This prevents clear_scopes from applying to the push token - match: '' set: trailing-heredoc trailing-heredoc: # The rest of the line right after the heredoc tag needs to be handled # as ordinary ruby source. The embedded syntax starts at the next line. - clear_scopes: 2 - match: ^ pop: true - include: expressions ###[ DATA SECTION ]############################################################ data-section: - match: ^__END__\n scope: meta.string.ruby string.unquoted.program-block.ruby push: - meta_content_scope: text.plain - match: (?=