Grammar injections


I’ve been playing around with grammars and I’m trying to understand how grammar injections work. I think I understand the basics, for instance in the language-php grammar it has a section

'scopeName': 'text.html.jsp'
  'text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:source.js.embedded.html':
    'patterns': [

where it is embedding the rules in patterns into the given scopes. What I don’t understand is the structure of the scopes statement

'text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:source.js.embedded.html'

The first part, text.html.php, is obviously the scope of the new grammars, and I’m guessing (meta.embedded | meta.tag) means to inject into either the meta.embedded scope or the meta.tag scope, but what is the significance of the L: in L:text.html.php and L:source.js.embedded.html, and why is meta.tag included twice? I’ve searched through as much of the posts and literature on grammar injections for Textmate but I haven’t been able to find anything that really clarifies this. Can anyone provide some insight into this or point me to a resource that explains it?

1 Like

Is there a way to escape from another language grammar?
How to inject an additional pattern into a Atom or TextMate editor grammar
How to prioritize grammar injections?
ERB and mixed, scoped syntax highlighting

After playing with the injection scope statement some more this is what I’ve been able to figure out so far:

  1. A set of patterns can be injected into multiple scopes by separating those scopes with commas. So
  'text.html.php, source.js.embedded.html':

will inject into the scopes ["text.html.php"] and ["source.js.embedded.html"].

  1. Scopes can be excluded from an encompassing scope by “subtracting them” as shown below. So
  'text.html.php - meta.tag':

will inject into the scope ["text.html.php"] but not the scope ["text.html.php", "meta.tag"].

  1. Scopes separated by a space are injected into only when both scopes are present (think of your standard “and” operator). So
  'text.html.php meta.tag':

will inject into the scope ["text.html.php", "meta.tag"] but not the scope ["text.html.php"] or the scope ["meta.tag"]. These also appear to be order dependent. From my testing the previous injection rule would not work for the scope ["meta.tag", "text.html.php"].

  1. Multiple scopes can be subtracted from an encompassing scope by grouping them in parentheses and separating them with | (think of them as standard “or” operators). So
  'text.html.php - ( meta.embedded | meta.tag )':

will inject into the scope ["text.html.php"] but not the scopes ["text.html.php", "meta.embedded"] or ["text.html.php", "meta.tag"]. Note: From what I tried this only works for subtracting scopes. I was not able to apply it to any “and” combined scopes. From what I could tell those have to be written out explicitly for each combination.

Given all of this I think the L: notation in the example in my original post has to do with what precedence the injected rules are given but I’ll have to play with it more to know for sure.

1 Like

How does atom text editor parse / tokenise code? (syntax-highlighting)

I was able to find some discussion of the L: notation in the textmate/markdown.tmbundle github repository. I guess L: is suppose to stand for inject “left” of the existing rules for the given scope, i.e., the injected rules should take precedence over the existing rules. However, upon trying this I was unable to get such an effect. So either this understanding is incorrect or there is an error in how rules are injected in Atom at the moment.