3

In a simple to-do list language grammar that I made, some scopes overlap in their regex rules, so certain scopes are not being recognized at all. I'd like to give these scopes precedence so that they're recognized within another scope.

Currently it looks like this:

enter image description here

The scopes are:

  • urgent (red; lines starting with XXam/pm or *)
  • waiting (yellow; lines starting with `)
  • url (purple; words starting with http)
  • tag (blue; words starting with @)

I'd like tags and URLs to be colored even within urgent or waiting lines, but currently the Scope and Token Inspector shows that the entirety of lines 2 and 3 are the urgent scope, and all of line 4 is the waiting scope, even though those lines should have tags and URLs in them.

I've tried reversing the order of the definitions in the .tmLanguage file, but that didn't make any difference. Here are those definitions:

<dict>
  <key>match</key>
  <string>\B\@\w+</string>
  <key>name</key>
  <string>constant.language.tag.todotxt</string>
</dict>
<dict>
  <key>match</key>
  <string>http.*?( |$)</string>
  <key>name</key>
  <string>constant.language.url.todotxt</string>
</dict>
<dict>
  <key>match</key>
  <string>^`.*$</string>
  <key>name</key>
  <string>constant.language.waiting.todotxt</string>
</dict>
<dict>
  <key>match</key>
  <string>^\*.*$|^\d.{0,5}[ap]m.*$</string>
  <key>name</key>
  <string>constant.language.urgent.todotxt</string>
</dict>

So, what needs to change for the tag and url scopes to be recognized even when they're within the urgent and waiting scopes?

Update: an imperfect workaround

I can prevent the scopes from overlapping by making the urgent and waiting scopes (red and yellow) end as soon as a tag or url is encountered on the line, using these regular expressions:

<key>match</key>
<string>^`.*?(?= @| http|$)</string>
<key>name</key>
<string>constant.language.waiting.todotxt</string>
...
<key>match</key>
<string>(^\*.*?|^\d.{0,5}[ap]m.*?)(?= @| http|$)</string>
<key>name</key>
<string>constant.language.urgent.todotxt</string>

The limitation of this workaround is that tags and URLs must be at the end the line, otherwise normal text appears where it shouldn't:

enter image description here

Ideally I would still prefer that tags and URLs be recognized WITHIN the urgent and waiting scopes, so that an urgent or waiting scope can continue even after tags and/or URLs in the middle of the line.

fpsvogel
  • 264
  • 4
  • 11
  • Is it like css where the order matters, the last selector that matches wins? – Graham P Heath Jun 04 '20 at 15:53
  • 1
    @GrahamPHeath That's what I thought too, but reversing the order (with url and tag definitions at the bottom) doesn't make any difference. I kept the order as above because this answer to a related question suggests that definitions closer to the top get precedence: https://stackoverflow.com/a/47491994/4158773 – fpsvogel Jun 04 '20 at 16:21
  • 1
    Not related to your problem, but the convention in naming scopes is to have the overall scope name (`todotxt` in your case) come last. So, it should be `constant.language.url.todotxt`, `constant.language.waiting.todotxt`, etc. – MattDMo Jun 04 '20 at 18:07
  • @MattDMo Thanks! I've updated the scope names to follow that convention. This is all new to me, as you can probably tell :) – fpsvogel Jun 04 '20 at 18:46

0 Answers0