Sublime Forum

[Info] Set meta_scopes in syntax definitions

#1

While working on a syntax definition, I noticed some behavior that isn’t clearly defined by the documentation, so I thought I would make a note about it here, in case it helps someone else.

The documentation says:

meta_scope. This assigns the given scope to all text within this context, including the patterns that push the context onto the stack and pop it off.

But actually, we can see that it also applies to the patterns that set the context, not just those that push it.

Take the following sublime-syntax:

%YAML 1.2
---
# See http://www.sublimetext.com/docs/3/syntax.html
scope: source.example
contexts:
  main:
    - match: \(
      push: inside_parens_start
  
  inside_parens_start:
    - meta_scope: meta.start
    - match: 'hello'
      scope: meta.start.content
      set: inside_parens_body # we don't want to set this scope again if `hello` appears multiple times, so we switch to the body context
    - match: \)
      pop: true
    - match: ''
      set: inside_parens_body

  inside_parens_body:
    - meta_scope: meta.body
    - match: 'foobar'
      scope: meta.body.content
    - match: \)
      pop: true

Given the following test document:

(hello foobar) 

One might expect:

  • ( to have scope source.example meta.start :thumbsup:
  • hello to have scope source.example meta.start meta.start.content :thumbsdown: instead, it has source.example meta.start meta.body meta.start.content
  • _ (space) to have scope source.example meta.body :thumbsup:
  • foobar to have scope source.example meta.body meta.body.content :thumbsup:
  • ) to have scope source.example meta.body :thumbsup:
  • to have scope source.example :thumbsup:

The fix is to change it to:

%YAML 1.2
---
# See http://www.sublimetext.com/docs/3/syntax.html
scope: source.example
contexts:
  main:
    - match: \(
      push: inside_parens_start
  
  inside_parens_start:
    - meta_scope: meta.start
    - match: 'hello'
      scope: meta.start.content
      set: inside_parens_body
    - match: \)
      pop: true
    - match: ''
      set: inside_parens_body

  inside_parens_body:
    - meta_content_scope: meta.body
    - match: 'foobar'
      scope: meta.body.content
    - match: \)
      scope: meta.body
      pop: true

Notice that inside_parens_body now uses meta_content_scope, and all patterns that declare pop pattern scopes within it also set the same scope.

hopefully that will help other people struggling with what can seem to be quite confusing. :slightly_smiling:

2 Likes