%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: # print <<-'THERE' # This is single quoted. # The above used #{Time.now} # THERE # symtoms: # From Programming Ruby p306; should be a non-interpolated heredoc. # # text: # "a\332a" # symptoms: # '\332' is not recognized as slash3.. which should be octal 332. # solution: # plain regexp.. should be easy. # # 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 - podspec - prawn - rabl - rake - Rakefile - Rantfile - rbx - rjs - ruby.rail - Scanfile - simplecov - Snapfile - thor - Thorfile - Vagrantfile first_line_match: ^#!\s*/.*\bj?ruby\b scope: source.ruby variables: identifier: '\b[[:alpha:]_][[:alnum:]_]*\b' method_punctuation: '(?:[?!]|=(?![>=]))?' method_name: '{{identifier}}{{method_punctuation}}' path_lookahead: '(::)?({{identifier}}(\.|::))*{{identifier}}' contexts: main: - include: expressions expressions: - include: class - include: module - include: constants - include: invalid - include: blocks - include: keywords - include: well-known-methods - include: variables - include: method - include: strings - include: comments - include: data-section - include: heredocs - include: operators - include: identifiers-accessors comments: # multiline comments - match: ^=begin scope: punctuation.definition.comment.ruby push: - meta_scope: comment.block.documentation.ruby - match: ^=end scope: punctuation.definition.comment.ruby pop: true - match: '(#).*$\n?' scope: comment.line.number-sign.ruby captures: 1: punctuation.definition.comment.ruby class: # Defining a class method - match: \b(class)\b(?=\s*<) scope: keyword.control.class.ruby - match: '\b(class)\b' scope: meta.class.ruby keyword.control.class.ruby push: class-declaration class-declaration: - meta_content_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: \b(module)\b scope: meta.module.ruby keyword.control.module.ruby push: module-declaration module-declaration: - meta_content_scope: meta.module.ruby - match: '(?=(::)?({{identifier}}::)*{{identifier}})' set: - meta_content_scope: meta.module.ruby entity.name.module.ruby - include: name-parts - match: '' pop: true # Escape if no valid match - match: (?=\S) pop: true name-parts: - match: '::' scope: punctuation.accessor.ruby - match: '\.' scope: punctuation.accessor.ruby - match: '({{identifier}})(::|\.)' captures: 1: support.other.namespace.ruby 2: punctuation.accessor.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 - match: '\b(0[xX]\h(_?\h)*|\d(_?\d)*(\.(?![^[:space:][:digit:]])(_?\d)*)?([eE][-+]?\d(_?\d)*)?|0[bB][01]+)\b' scope: constant.numeric.ruby - match: ":'" scope: punctuation.definition.constant.ruby push: - meta_scope: 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: 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 # matches questionmark-letters. # # examples (1st alternation = hex): # ?\x1 ?\x61 # # examples (2nd alternation = octal): # ?\0 ?\07 ?\017 # # examples (3rd alternation = escaped): # ?\n ?\b # # examples (4th alternation = meta-ctrl): # ?\C-a ?\M-a ?\C-\M-\C-\M-a # # examples (4th alternation = normal): # ?a ?A ?0 # ?* ?" ?( # ?. ?# # # the negative lookbehind prevents against matching # p(42.tainted?) - match: '\?(\\(x\h{1,2}\b|0[0-7]{0,2}\b|[^x0MC]\b)|(\\[MC]-)+\w\b|[a-zA-Z0-9_]\b(?!\s*:)|[^a-zA-Z0-9_\s\\])' scope: constant.numeric.ruby blocks: - match: \b(do)\b\s* captures: 1: keyword.control.start-block.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) 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: - match: '\b(BEGIN|END)\b(?![?!])' scope: keyword.control.ruby - match: '\b(class|module)\b(?![?!])' scope: keyword.control.ruby - match: '\b(begin|end|ensure|rescue)\b(?![?!])' scope: keyword.control.ruby - match: '\b(case|else|ensure|for|in|then)\b(?![?!])' scope: keyword.control.ruby - match: '\b(elsif|if|unless|when|while|until)\b(?![?!])' scope: keyword.control.ruby push: after-keyword - match: \b(and|not|or)\b scope: keyword.operator.logical.ruby push: after-keyword - match: '!+|&&|\|\||\^' scope: keyword.operator.logical.ruby push: after-operator - match: '\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\b(?![?!])|\bdefined\?|\bblock_given\?' scope: keyword.control.pseudo-method.ruby operators: - match: '=>' scope: punctuation.separator.key-value.ruby push: after-operator - match: '<<=|%=|&=|\*=|\*\*=|\+=|\-=|\^=|\|{1,2}=|<<' 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.other.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 - include: after-operator - match: ':(?!:)' scope: keyword.operator.conditional.ruby push: after-operator - match: \; scope: punctuation.terminator.statement.ruby push: after-operator - match: "," scope: punctuation.separator.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 - match: '\.\.\.?' scope: keyword.operator.ruby push: after-operator identifiers-accessors: # This consumes class/module access to prevent issues parsing : as part # of a ternary operator - match: '(::)(?={{identifier}}{{method_punctuation}})' scope: punctuation.accessor.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.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.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.ruby 2: support.class.ruby - match: '\b[[:upper:]]\w*\b' scope: variable.other.constant.ruby well-known-methods: - match: '\b(initialize|new|loop|include|extend|prepend|raise|fail|attr_reader|attr_writer|attr_accessor|attr|catch|throw|module_function|public|protected|private)\b(?![?!])' scope: keyword.other.special-method.ruby - match: \b(require|require_relative|gem)\b captures: 1: keyword.other.special-method.ruby push: - meta_scope: meta.require.ruby - match: $|(?=#) captures: 1: keyword.other.special-method.ruby 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 # Methods that may be followed by a regex - match: |- (?x: \b( gsub!| sub! )(?=\s) | \b( assert_match| gsub| index| match| scan| sub )\b ) scope: support.function.builtin.ruby push: try-regex # 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 # 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 # Methods from the Kernel class not handled elsewhere, ending in punctuation - match: |- (?x: \b( autoload\?| iterator\?| exit! ) ) scope: support.function.builtin.ruby # 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 # 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 # 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 method: - match: \b(def)\b scope: meta.function.ruby keyword.control.def.ruby push: - meta_content_scope: meta.function.ruby - match: '(self)(\.)({{identifier}}{{method_punctuation}}|===?|>[>=]?|<=>|<[<=]?|[%&`/\|]|\*\*?|=?~|[-+]@?|\[\]=?)' captures: 1: variable.language.ruby 2: punctuation.accessor.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.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 - 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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*/[^/]*$)' pop: true - match: '\s*(/)(?![*+{}?])' captures: 1: string.regexp.classic.ruby punctuation.definition.string.ruby push: - meta_content_scope: string.regexp.classic.ruby - match: "(/)([eimnosux]*)" scope: string.regexp.classic.ruby captures: 1: punctuation.definition.string.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*[^[:alnum:](\s])' push: try-regex # regular expressions (literal) - match: '%r\{' scope: punctuation.definition.string.begin.ruby push: - meta_scope: 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: 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: 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: 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: 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: 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: 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: 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: - match: '\\(?:[0-7]{1,3}|x[\da-fA-F]{1,2}|.)' scope: constant.character.escape.ruby interpolated-ruby: - match: '(#\{)(\})' scope: punctuation.section.embedded.ruby captures: 1: source.ruby.embedded.source 2: source.ruby.embedded.source.empty - match: '#\{' scope: punctuation.section.embedded.ruby push: - meta_scope: source.ruby.embedded.source - match: '\}' scope: punctuation.section.embedded.ruby pop: true - include: nest-curly-expressions - include: expressions - match: '(#@)[[:alpha:]_]\w*' scope: variable.other.readwrite.instance.ruby captures: 1: punctuation.definition.variable.ruby - match: '(#@@)[[:alpha:]_]\w*' scope: variable.other.readwrite.class.ruby captures: 1: punctuation.definition.variable.ruby - match: '(#\$)[[:alpha:]_]\w*' scope: variable.other.readwrite.global.ruby captures: 1: punctuation.definition.variable.ruby 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: # heredoc with embedded HTML and indented terminator - match: '(<<[-~]"?((?:[_\w]+_|)HTML)\b"?)' scope: punctuation.definition.string.begin.ruby push: [heredoc-html, trailing-heredoc-start] # heredoc with embedded SQL and indented terminator - match: '(<<[-~]"?((?:[_\w]+_|)SQL)\b"?)' scope: punctuation.definition.string.begin.ruby push: [heredoc-sql, trailing-heredoc-start] # heredoc with embedded css and indented terminator - match: '(<<[-~]"?((?:[_\w]+_|)CSS)\b"?)' scope: punctuation.definition.string.begin.ruby push: [heredoc-css, trailing-heredoc-start] # heredoc with embedded javascript and indented terminator - match: '(<<[-~]"?((?:[_\w]+_|)(?:JS|JAVASCRIPT))\b"?)' scope: punctuation.definition.string.begin.ruby push: [heredoc-js, trailing-heredoc-start] # heredoc with embedded ruby and indented terminator - match: '(<<[-~]"?((?:[_\w]+_|)RUBY)\b"?)' scope: punctuation.definition.string.begin.ruby push: [heredoc-ruby, trailing-heredoc-start] # Escaped to prevent recursion? # heredoc with embedded shell and indented terminator # - match: '(<<[-~]("?)((?:[_\w]+_|)(?:SH|SHELL))\b\1)' # scope: punctuation.definition.string.begin.ruby # push: [heredoc-shell, trailing-heredoc-start] - match: (\=)\s*(<<(\w+)) captures: 1: keyword.operator.assignment.ruby 2: punctuation.definition.string.begin.ruby push: [heredoc-assign, trailing-heredoc-no-embedding-start] # heredoc with indented terminator - match: '(<<[-~](\w+))' scope: punctuation.definition.string.begin.ruby push: [heredoc-plain, trailing-heredoc-no-embedding-start] heredoc-html: - meta_scope: string.unquoted.embedded.html.ruby - meta_content_scope: text.html.embedded.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: scope:text.html.basic - include: interpolated-ruby - include: escaped-char heredoc-sql: - meta_scope: string.unquoted.embedded.sql.ruby - meta_content_scope: text.sql.embedded.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: scope:source.sql - include: interpolated-ruby - include: escaped-char heredoc-css: - meta_scope: string.unquoted.embedded.css.ruby - meta_content_scope: text.css.embedded.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: 'scope:source.css' - include: interpolated-ruby - include: escaped-char heredoc-js: - meta_scope: string.unquoted.embedded.js.ruby - meta_content_scope: text.js.embedded.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: 'scope:source.js' - include: interpolated-ruby - include: escaped-char heredoc-ruby: - meta_scope: string.unquoted.embedded.ruby.ruby - meta_content_scope: text.ruby.embedded.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char - include: expressions #heredoc-shell: # - meta_scope: string.unquoted.embedded.shell.ruby # - meta_content_scope: text.shell.embedded.ruby # - match: ^\s*\2$ # scope: punctuation.definition.string.end.ruby # pop: true # - include: Shell-Unix-Generic.sublime-syntax # - include: interpolated-ruby # - include: escaped-char # This prevents clear_scopes from applying to the push token trailing-heredoc-start: - match: '' set: trailing-heredoc trailing-heredoc: - clear_scopes: 2 - match: '$' pop: true - include: expressions heredoc-assign: - meta_scope: string.unquoted.heredoc.ruby - match: ^\s*\3$ scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char heredoc-plain: - meta_scope: string.unquoted.heredoc.ruby - match: ^\s*\2$ scope: punctuation.definition.string.end.ruby pop: true - include: interpolated-ruby - include: escaped-char # This prevents clear_scopes from applying to the push token trailing-heredoc-no-embedding-start: - match: '' set: trailing-heredoc-no-embedding trailing-heredoc-no-embedding: - clear_scopes: 1 - match: '$' pop: true - include: expressions data-section: - match: ^__END__\n scope: string.unquoted.program-block.ruby push: - meta_content_scope: text.plain - match: (?=