Right now, in .sublime-syntax files, if in a context A
a match pattern push
es a context B
, and in B
, a match pattern pop
s, then you can use \1 in the popping pattern to reference the contents of the first captured group of the content that push
ed.
This is perfect to manage certaing constructs, but it’s very limited in usage. If it were extended so that any match pattern could use \1 to reference the first capture group in the match that pushed the current context, that’d greatly increase the capabilities of the system, e.g. by allowing us to define a python-style grammars, where a context is pushed for each new block, and said context is popped only when the indentation decreased (currently, the python cyntax can’t e.g. put a meta.class scope to encompass a whole class definition).
The only possibility to do this now, is to have many copies of the same base context that check for different levels of indentation, so e.g. instead of three primary contexts (main, class, function) I need to have potentially infinite ones (main, class function, main_1, class_1, function_1, … main_n, class_n, function_n), where 1…n is a range of allowed indentation. This needless repetition (and it’s associated impact on the memory footprint of the grammar, as well as the associated costs in therms of maintainability) would be removed if the suggestion above were to be implemented.
Here is how a toy indent-based grammar would look if the suggestion was implemented
main_0:
- meta_content_scope: main_0
- match: '^(?!\t{0})'
pop: true
- match: '^(\t{0})(\s*)(?={{prefix}})'
scope: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_recursive, parse_block_opener]
- match: '^(\t{0})(\s*)'
scope: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '(.+)'
captures:
2: invalid.illegal.gss.main_0
main_recursive:
- meta_content_scope: main_recursive
- match: '^(?!\t\1)' #this is currently valid
pop: true
- match: '^(\t\1)(\s*)(?={{prefix}})' #this is currently invalid since the action in the pattern is not 'pop'
scope: invalid.illegal.gss.main_recursive.invalid-leading-whitespace
push: [main_recursive, parse_block_opener]
- match: '^(\t\1)(\s*)'
scope: invalid.illegal.gss.main_recursive.invalid-leading-whitespace
push: parse_normal_line
- match: '(.+)'
captures:
2: invalid.illegal.gss.main_recursive
And this is what I currently need to do to emulate it:
main_0:
- meta_content_scope: main_0
- match: '^(?!\t{0})'
pop: true
- match: '^(\t{0})(\s*)(?={{prefix}})'
scope: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_1, parse_block_opener]
- match: '^(\t{0})(\s*)'
scope: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '(.+)'
captures:
2: invalid.illegal.gss.main_0
main_1:
- meta_content_scope: main_1
- match: '^(?!\t{1})'
pop: true
- match: '^(\t{1})(\s*)(?={{opener_line}})'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_2, parse_block_opener]
- match: '^(\t{1})(\s*)'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '^(\t*)(.+)'
captures:
2: invalid.illegal.gss.main_1
main_2:
- meta_content_scope: main_2
- match: '^(?!\t{2})'
pop: true
- match: '^(\t{2})(\s*)(?={{opener_line}})'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_3, parse_block_opener]
- match: '^(\t{2})(\s*)'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '^(\t*)(.+)'
captures:
2: invalid.illegal.gss.main_2
main_3:
- meta_content_scope: main_3
- match: '^(?!\t{3})'
pop: true
- match: '^(\t{3})(\s*)(?={{opener_line}})'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_4, parse_block_opener]
- match: '^(\t{3})(\s*)'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '^(\t*)(.+)'
captures:
2: invalid.illegal.gss.main_3
main_4:
- meta_content_scope: main_4
- match: '^(?!\t{4})'
pop: true
- match: '^(\t{4})(\s*)(?={{opener_line}})'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: [main_5, parse_block_opener]
- match: '^(\t{4})(\s*)'
captures:
2: invalid.illegal.gss.main_0.invalid-leading-whitespace
push: parse_normal_line
- match: '^(\t*)(.+)'
captures:
2: invalid.illegal.gss.main_4
...