Note: As of 2023 I gave up on finishing this syntax definition. I will leave what I have written down up until now here for future reference for anyone who'd like to start writing their own syntax definitions. The repo on my github is free to be forked and worked on.
Rego is a language used for Policy Testing. It's not a particularly complex language. However, there is no syntax definition for Sublime Text yet. This blog post is about trying to write at least a basic syntax definition so the code is properly highlighted.
The related docs can be found here:
The full repo can be found here.
Basic structure
We'll start by adding a new package to Sublime Text. The path will be
~/.config/sublime-text/Packages/User/RegoSyntax
.
A basic syntax definition has some metadata:
%YAML 1.2
---
name: Rego
file_extensions:
- rego
scope: source.rego
We'll assign source.rego
to file extension .rego
.
Highlighting comments
Comments in Rego use #
. We'll add a new match to the main context:
contexts:
main:
- match: ^\s*#.*\n
scope: comment.line
This is enough for Sublime Text to highlight comments.
We'll take any number of whitespace after a start of line (^\s*
),
followed by the comment sign (#
), followed by anything until the end of
the line (.*\n
).
To verify this is working, we can go to any Rego file, open the Sublime Text console (Ctrl + `) and check the context:
view.scope_name(view.sel()[0].end())
which should give us
source.rego comment.line
Now Sublime Text will highlight this as comments. However, the scope is not exactly correct.
If you try it with Python, for example, you'll get this:
source.python comment.line.number-sign.python
You may know about CommentsAwareEnter package, which keeps the comments while you hit Enter.
This package uses the scope name to be aware that you are editing a comment.
However, if we only have source.rego comment.line
, the package will
end with an exception, because it expects a more detailed scope.
So while Sublime Text highlights the comment just fine, the scope needs
to be expanded to comment.line.number-sign.rego
:
contexts:
main:
- match: ^\s*#.*\n
scope: comment.line.number-sign.rego
Now the highlighting works and the CommentsAwareEnter package as well.
One more thing I had to borrow from other syntax definitions is a file
called Comments.tmPreferences
, which enables Sublime Text to toggle comments
with a shortcut (default key binding is Ctrl + /).
The file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Comments</string>
<key>scope</key>
<string>source.rego</string>
<key>settings</key>
<dict>
<key>shellVariables</key>
<array>
<dict>
<key>name</key>
<string>TM_COMMENT_START</string>
<key>value</key>
<string># </string>
</dict>
</array>
</dict>
</dict>
</plist>
Strings
A string in Rego is not special, it starts and ends with "
:
- match: '"'
push: string
However, here we will not match a single string on one line. We can have more
than one and we want to highlight them all. In this case, after matching a "
,
we'll push a context named string
.
The context then looks like this:
contexts:
main:
- match: '"'
push: string
string:
- meta_scope: string.quoted.rego
- match: \\.
scope: constant.character.escape.rego
- match: '"'
pop: true
When we match another "
, which is not escaped, we'll pop the context
and the string ends. For this, we define the constant.character.escape.rego
scope.
Curly braces
Sublime Text will highlight the opening and closing bracket/brace/etc. In Rego
a block is defined by {}
. Let's tell Sublime to recognize them:
- match: \{
scope: punctuation.section.block.start.rego
- match: \}
scope: punctuation.section.block.end.rego
Note: At this point I also wanted to write about defining variables, built-ins and other elements, but I no longer have the time nor motivation to finish this. If I ever come back to this, I'll update the article.