Yeah, what I generally do here is something like:
some_context_on_the_stack:
- meta_scope: meta.declaration
more_specific context:
- clear_scopes: 1
- meta_scope: meta.declaration.name
I tried to come up with a live example, but I rely heavily on my macro system for stuff like this:
contexts:
else-pop:
- match: (?=\S)
pop: true
architectures:
- match: !word architecture
scope: storage.type.architecture.vhdl
push:
- !meta meta.block.arch-decl.vhdl
- !expect [';', punctuation.terminator.vhdl]
- - match: !word begin
scope: keyword.declaration.vhdl
set:
- !meta_set meta.block.arch-decl.body.vhdl
- !expect [ !word architecture, storage.type.architecture.vhdl ]
- !expect [ !word end, keyword.declaration.vhdl ]
- - !pop_on [ !word end ]
- include: statements
- include: else-pop
- !expect ['{{identifier}}', entity.name.architecture.vhdl ]
- !expect [ !word of, 'keyword.other.vhdl' ]
- !expect ['{{identifier}}', entity.name.entity.vhdl]
The full expansion of this is not easy to read:
contexts:
else-pop:
- match: (?=\S)
pop: true
architectures:
- match: '(?i)\b(?:architecture)\b'
scope: storage.type.architecture.vhdl
push:
- - meta_scope: meta.block.arch-decl.vhdl
- include: else-pop
- - match: ';'
scope: punctuation.terminator.vhdl
pop: true
- include: else-pop
- - match: '(?i)\b(?:begin)\b'
scope: keyword.declaration.vhdl
set:
- - clear_scopes: 1
- meta_scope: meta.block.arch-decl.body.vhdl
- include: else-pop
- - match: '(?i)\b(?:architecture)\b'
scope: storage.type.architecture.vhdl
pop: true
- include: else-pop
- - match: '(?i)\b(?:end)\b'
scope: keyword.declaration.vhdl
pop: true
- include: else-pop
- - match: '(?=(?i)\b(?:end)\b)'
pop: true
- include: statements
- include: else-pop
- - match: '{{identifier}}'
scope: entity.name.architecture.vhdl
pop: true
- include: else-pop
- - match: '(?i)\b(?:of)\b'
scope: keyword.other.vhdl
pop: true
- include: else-pop
- - match: '{{identifier}}'
scope: entity.name.entity.vhdl
pop: true
- include: else-pop
If written by hand, this approach would probably call for quite a few more named contexts. This approach does have several advantages over the traditional method:
- It seems more declarative, which helps me to reason about it.
- It’s very concise (with macros).
- It handles newlines very well without extra code (e.g.“architecture¬name¬of¬name¬is…”)
- If any part is missing, the rest will be highlighted correctly.
But it does result in a lot of boilerplate if you have to write it all yourself.