Sublime Forum

How to nest two scopes with the new syntax?

#1

I like to add a heading syntax in my code files so that two or more # are treated as entities (therefore appearing in the Goto Anything panel). I would also like to detect when a word is surrounded in asterisks *. This is what I have so far (but it doesn’t work):

contexts:
  main:
    - match: ' *#{2,} .*$\n?' # headers
      scope: entity.name.function
      push:
          - match: '\*(.+)'
            captures:
                1: keyword.bold
          - match: '\*'
            pop: true
    - match: (#).*$\n? # regular comments
      scope: comment.line.number-sign.r
0 Likes

#2

What exactly does not work?

Your header match seems to work fine here. And it’s even shown in the symbol list. Although I would not abuse entity.name.function but rather entity.name.section (and add that to the smbol list manually).

Your “bold” match is simply just wrong, and having that in a context that is pushed by the header match doesn’t help either. I imagine you want to highlight everything in between asterisks, is that correct?

You would do that like so:

contexts:
  main:
    - match: ' *#{2,} .*$\n?' # headers
      scope: entity.name.function
    - match: \*
      push:
        - meta_content_scope: keyword.bold
        - match: \*
          pop: true
    - match: (#).*$\n? # regular comments
      scope: comment.line.number-sign.r

If the asteriks should get the keyword scope as well, use meta_scope instead.

For more scope name inspiration, check a few implementations of markup languages (e.g. markdown).

0 Likes

#3

Thanks, your suggestion works for things like: this should be *bold* (if I do ctrl+shift+p I see keyword.bold), but I wanted to nest the header rule with the bold rule, so that something like this would show the word bold in a different color than that of the header: ## this too should be *bold*

0 Likes

#4
contexts:
  main:
    - match: '^ *#{2,}' # headers
      push:
        - meta_scope: entity.name.function
        - include: bold
        - match: $\n?  # \n is matched to render the remainder of the line in background color
          pop: true
    - include: bold
    - match: (#).*$\n? # regular comments
      scope: comment.line.number-sign.r

  bold:
    - match: \*
      push:
        - meta_content_scope: keyword.bold
        - match: \*
          pop: true

0 Likes

#5

Awesome, thanks! It works. Is the include: bold before the regular comments needed? It seems to also work without it.

0 Likes

#6

Also, is there any way to prevent the bold taking place when there is only one * in the line?

0 Likes

#7

That’s just for also highlighting non-heading lines. You can remove it if you don’t want it.

Yes, by using a look-ahead group in the beginning \* match and only matching if there is another asterisk in the same line. This gets a bit complicated with escape sequences.

0 Likes

#8

For the record, I ended up using this syntax to “bold” things that appear between asterisks, colors or backticks, and also anything of the form: # this_gets_bolded: whatever. Let me know if there is a simpler way to do this:

bold:
  - match: '\*(?=.+\*)'
    push:
      - meta_content_scope: string.bold
      - match: '\*'
        pop: true
  - match: '`(?=.+`)'
    push:
      - meta_content_scope: string.bold
      - match: '`'
        pop: true
  - match: ':(?=.+:)'
    push:
      - meta_content_scope: string.bold
      - match: ':'
        pop: true
  - match: '(?<!\w) (?=\S+: )' # negative lookbehind (not preceded by words), a space, positive lookahead for non-whitespace colon and a space
    push:
      - meta_content_scope: string.bold
      - match: ': '
        pop: true
0 Likes

#9

Well, since this is only about single-line matching you might as well just use regular captures:

  bold:
    - match: ([*`:])(.+?)(\1)
      captures:
        2: string.bold
    - match: '\G\s*(\w+): '
      captures:
        1: string.bold

\G is used as an anchor that is a) more reliable since it seems to anchor to where the heading context was pushed, and b) does not use a look-behind, which is less performant than just not using it. Furthermore, I combined your multiple similar matches into one with a back-reference.

0 Likes

#10

Wow, that’s brilliant. I would have never gotten there by myself, thanks!

I know there is a way to include a new syntax by using push: Packages/User/my.sublime-syntax but is there a way to include a context? What I’d like is to be able to edit the Python syntax, for example, and simply add a reference to the bold context that I just created, without having to copy and paste it literally.

0 Likes

#11

push: Packages/User/my.sublime-syntax#context-name

Except you would want to “include” your bold context since would never be popped.

0 Likes