Basic Syntax Highlighting

This post was started on 2020-06-29. It was published on 2020-06-29.

One of the big reasons I’m diving into the “write your website generator” rabbit-hole is that I can have posts with nice syntax-highlighted blocks of code without onerous copy-pasting between Spacemacs and WordPress (or some other blogging platform), and with the flexbility to add better styling or other features to the code in question. So for today, we’ll try to set up syntax highlighting for code blocks in Colophon.

Luckily for us, Pollen (on which Colophon is based) already has support for syntax highlighting, either via Pygments or Highlight.js. We want Colophon to produce static, self-contained HTML (as much as possible), so Pygments is the better choice.

To start off, we follow the Pollen instructions and install Python 3 and Pygments. I’m on a Mac and macOS Catalina ships with an older Python 2.7. I used Homebrew to install Python 3 and then used pip to install Pygments. I aliased the bare commands to the Python 3 versions, and made sure that the pygmentize utility was on my PATH:

# Set up Python3 using aliases
alias python=$(which python3)
alias pip=$(which pip3)

Unfortunately, while this sets up Python 3 and Pygments for use from a shell, it takes a little more work to get it working with Pollen—alias commands won’t work outside of a shell, and the Pollen support for Pygments doesn’t use the pygmentize utility.

But once again, Pollen gives us an out: the Pollen helper code provides a highlight function that takes a python-executable argument which can point to the correct version of Python. I could provide the value "python3" for that argument every time I write out a code block, but that would get repetitive and clunky, just the thing we want to avoid. Instead, I wrote a basic tag function that sets the python-executable and passes on everything else to the underlying highlight function:

(define (codeblock #:line-numbers? [line-numbers? #t]
                   lang . lines)
  (apply highlight
         #:python-executable "python3"
         #:line-numbers? line-numbers?
         lang lines)

I provided #:line-numbers? argument so that individual code blocks can decide whether or not to show line numbers. The highlight function also has arguments for providing an outer CSS class and a set of lines to highlight. I can expose those later if needed.

With that in place, Pollen and Pygments together turn the code blocks into HTML with different parts for different pieces of syntax. The last remaining thing is to add some CSS so that the HTML is colored and styled correctly. Pygments supports a bunch of different styles and will generate CSS for a particular style with the following incantation:

pygmentize -S <style name> -f html -a .highlight

I’m also working on a theming system for Colophon (spoilers!), but for now, pasting into the resulting CSS into the style file is good enough.

Bringing everything together, basic syntax highlighting works. In fact, this post uses the codeblocks to provide the highlighted snippets above. There are a few rough edges. I’d like to bring Pygment styles into the theming system I’m planning for Colophon. Also, because of the way the Pollen wrapper around Pygment works, line numbers can’t be toggled on a per block basis—either all blocks have line numbers, or all don’t. As you can imagine, this is inconvenient, and will have to be fixed long term. I will have to sit down and redo the Pollen-Pygments interface at some in the not-too-distant future, but I think this is enough for a few hours’ work.