Cette page existe aussi en français.

Quartz is a static site generator that turns Markdown content into websites. It’s the main stack of the site you’re on and allows me to write my notes in Obsidian without having to struggle with any CMS.

Although the tool is almost perfect, for some guides, some notes, I was missing the ability to present code cleanly (with syntax highlighted) for obscure languages or at least not as well known as Python, JavaScript and pals.

Notably, for one of my guides, I needed to be able to correctly present command lines for network equipment from MikroTik. But the syntax for the RouterOS Script language doesn’t seem to be supported by either Obsidian or Quartz.

Here’s how I went about it:

How does Quartz syntax highlighter works?

The first step is to understand how syntax highlighting works in Quartz.

On the Syntax Highlighting page of the Quartz documentation, we learn that the system uses the TypeScript library Rehype Pretty Code.

Rehype Pretty Code uses the shiki rendering engine, which is based on the TextMate language definitions.

Finding a TextMate definition for RouterOS Script

Luckily for us, TextMate definitions are also what Visual Studio Code uses to perform its syntax highlighting.

Among the VSCode extensions adding support for RouterOS Script, the one by Korzhov Mikhail (vscode_mikrotik_routeros_script) seems to me to offer the most accurate colouring.

The extension’s source code includes the TextMate Grammar.

Here is a snippet:

rosScript.tmLanguage.json
{
  "name": "rosScript",
  "scopeName": "source.rsc",
  "fileTypes": ["rsc"],
  "patterns": [
    {
      "match": "\\b(ipsec-esp|ipsec-ah|idpr-cmtp|iso-tp4|xns-idp|udp-lite|ip-encap|icmp|igmp|ggp|st|tcp|egp|pup|udp|hmp|rdp|dccp|xtp|ddp|rsvp|gre|rspf|vmtp|ospf|ipip|etherip|encap|pim|vrrp|l2tp|sctp)\\b",
      "name": "variable.other.rosScript"
    },
    ...
    ]
    },
    "string_escaped_char": {
      "patterns": [
        {
          "match": "\\\\(\\\\|[nrt$?abfv\"?]|[0-9A-F]{2})",
          "name": "constant.character.escape.rosScript"
        },
        {
          "match": "\\\\.",
          "name": "invalid.illegal.unknown-escape.rosScript"
        }
      ]
    }
  }
}

Integration of TextMate Grammar in Quartz

The Rehype Pretty Code documentation has a page explaining how to customise syntax highlighting, including how to add your own language.

The Quartz documentation on syntax highlighting states that the functionality is managed by its SyntaxHighlighting plugin. And on the plugin page we find the location of the file to be modified in our Quartz installation: quartz/plugins/transformers/syntax.ts.

And here’s how to modify it to include our new language:

syntax.ts
import { QuartzTransformerPlugin } from "../types"
import rehypePrettyCode, { Options as CodeOptions, Theme as CodeTheme } from "rehype-pretty-code"
import { getHighlighter } from "shiki";
import { readFileSync } from "fs";
 
interface Theme extends Record<string, CodeTheme> {
  light: CodeTheme
  dark: CodeTheme
}
 
interface Options {
  theme?: Theme
  keepBackground?: boolean
  getHighlighter?(options: BundledHighlighterOptions): Promise<Highlighter>
}
 
const defaultOptions: Options = {
  theme: {
    light: "github-light",
    dark: "github-dark",
  },
  keepBackground: false,
  getHighlighter: (options) =>
    getHighlighter({
      ...options,
      langs: [
        () => JSON.parse(readFileSync("/random_location_on_your_machine/rosScript.tmLanguage.json", "utf-8")),
      ],
    }),
}
 
export const SyntaxHighlighting: QuartzTransformerPlugin<Options> = (
  userOpts?: Partial<Options>,
) => {
  const opts: Partial<CodeOptions> = { ...defaultOptions, ...userOpts }
 
  return {
    name: "SyntaxHighlighting",
    htmlPlugins() {
      return [[rehypePrettyCode, opts]]
    },
  }
}

Check

# RouterOS script: ip-addr-bridge
# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de>
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
#
# enable or disable ip addresses based on bridge port state
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md
 
:foreach Bridge in=[ /interface/bridge/find ] do={
  :local BrName [ /interface/bridge/get $Bridge name ];
  :if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={
    :if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={
      /ip/address/disable [ find where !dynamic interface=$BrName ];
    } else={
      /ip/address/enable [ find where !dynamic interface=$BrName ];
    }
  }
}