Today I learned how to create a VS Code extension to do custom syntax highlighting.

Textual CSS

At my day job, developing Textual, I have been tasked with writing a VS Code extension that does proper syntax colouring of Textual CSS.

That's because Textual CSS looks a lot like regular CSS but the syntax highlighting of regular CSS doesn't look great. For example, most editors will highlight the code below in an uneven way:

ModalScreen, #input, .some-class {
    border: heavy white;
    tint: $primary 30%;
}

(Try copying & pasting into your code editor of choice.)

For example, the selectors #input and .some-class are highlighted but the selector ModalScreen isn't. Furthermore, Textual CSS has rules that regular CSS doesn't, and that is why border is a different colour than tint.

Writing a VS Code extension

After getting started with VS Code's guide on writing your first extension, I found a guide specific to creating extensions that do custom syntax highlighting.

A few rabbit holes later and I had an extension that does syntax highlighting of the words "textual" and "Textual" in .tcss files.

"All" I needed to do was create a new extension template with yo code (as the first guide teaches).

Then, I went to the extension manifest file package.json and modified the "contributes" key:

{
  "contributes": {
    "languages": [
      {
        "id": "Textual CSS",
        "extensions": [".tcss"]
      }
    ],
    "grammars": [
      {
        "language": "Textual CSS",
        "scopeName": "source.tcss",
        "path": "./syntaxes/tcss.tmGrammar.json"
      }
    ]
  }
}

First, we need to "contribute" a language, which is Textual CSS, and that corresponds to the language that we want to target with our extension.

Then, we contribute a grammar, which is the TextMate grammar file that specifies how tokens get parsed. Token names and scopes are still a bit confusing to me, but after reading an article that is linked to by the VS Code guide, I seem to understand that we prefix the scope name with source so that we create a nested scope inside source.

In other words, the scope source is already a scope that VS Code knows about and we are saying that our Textual CSS files not only contain source code (scoped as source), but that they contain a more specific type of source code. This nesting is achieved with the .tcss.

Finally, we need to create the actual grammar file. The file tcss.tmGrammar.json currently looks like this:

{
    "scopeName": "source.tcss",
    "patterns": [{"include": "#textual"}],
    "repository": {
        "textual": {
            "match": "(T|t)extual",
            "name": "keyword"
        }
    }
}

The value that you attribute to "name" inside "textual" inside "repository" is what classifies the words "textual" and "Textual" as a meaningful token. In this example, I randomly chose keyword. Then, it is up to the theme that you use to specify what is the colour that keyword tokens use.

In the screenshot below, you can see a couple of lines of text with some random highlighting:

A screenshot of some source code with custom highlighting provided by a custom VS Code extension that will eventually do custom syntax highlighting of Textual CSS.

That's it for now! Stay tuned and I'll see you around!

Become a better Python 🐍 developer 🚀

+35 chapters. +400 pages. Hundreds of examples. Over 30,000 readers!

My book “Pydon'ts” teaches you how to write elegant, expressive, and Pythonic code, to help you become a better developer. >>> Download it here 🐍🚀.

References

Previous Post Next Post

Blog Comments powered by Disqus.