Sublime Forum

Using capture in scope

#1

I am playing with an extension to the PlainTasks plugin.
I often grab code snippets and put them into my work log / todo lists either from the web or from other sources.
I want to make a tag like:

#+BEGIN_SRC python
# PYTHON CODE HERE
#+END_SRC

And have it be recognized as python code.
I can do something like this:

sourceblock:
- match: ‘#+BEGIN_SRC[ \t]+python’
push:
- include: ‘scope:source.python’
- meta_scope: todo.sourceblock
- match: ‘#+END_SRC’
pop: true

But then I will need to make a block per language I wish to support.
I thought I could also do something with captures but I can’t figure out a good way to make that work.
What I really want is something dynamic like:

sourceblock:
- match: ‘#+BEGIN_SRC[ \t]+(python|ruby|js)’
push:
- include: ‘scope:source.{{capture.1}}’
- meta_scope: todo.sourceblock
- match: ‘#+END_SRC’
pop: true

Where the included scope is determined by the capture, better yet just [a-z]+ allowing any defined source scope to be used as a moniker.

I’ve dug through the docs but I am not seeing anything that would take me beyond what I know right now.
Are there any syntax wizards out there with better ideas of how this could be handled?

0 Likes

#2

there is no “quicker” (syntactic sugar) way to achieve this

0 Likes

#3

Fair enough.
I am also struggling using with_prototype:

I am trying to emulate what I see HTML.sublime-syntax doing with javascript.

Here is my attempt.
This will pop the context during the END_SRC block itself but it stays in source.cs context after the #+END_SRC block
and I am struggling to understand why, I thought the pop would mirror my push and bring me back to the parent scope but it does not seem to be accomplishing my goals.

- match: '#\+BEGIN_SRC[ \t]+([cC]sharp|[cC]#)'
  push:
    - meta_content_scope: todo.block
    - include: 'scope:source.cs'
  with_prototype:
    - match: '#\+END_SRC'
      pop: true
0 Likes

#4

It seems that this particular issue is specific to the csharp syntax.
The grammar above will leave things in a state where stuff after the END_SRC will match against the C# grammar still.
JavaScript on the other hand works fine.

0 Likes

#5

because you are only popping one context off the stack in your with_prototype - you should probably use a lookahead (like the HTML syntax does for </script>)

0 Likes

#6

You can do this without repetition using YAML Macros.

In a macro file, define a function like:

def begin_src(name, include):
  return {
    'match': r'#+BEGIN_SRC[ \t](?:%s)' % name,
    'push': [
      'sourceblock-end',
      [
        { 'include': include },
        { 'with_prototype': [
          'match': r'(?=#+END_SRC)',
          'pop': True,
        ] },
      ],
    ],
  }

In the syntax:

sourceblock:
  - !begin_src [ python, scope:source.python ]
  - !begin_src [ ruby, scope:source.ruby ]
  - !begin_src [ js|javascript, scope:source.javascript ]

sourceblock-end:
  - meta_scope: todo.sourceblock
  - match: '#+END_SRC',
    scope: keyword.other.code-block
    pop: true

Disclaimer: I’m typing this on my Chromebook, so I haven’t tested this code.

0 Likes