Posted in:

For many years I have been using Alex Gorbatchev’s Syntax Highlighter to provide the syntax highlighting on my blog. For the most part, it works well, and I use the excellent precode Windows Live Writer plugin to input my code snippets into blog posts. But I have run into a few problems with syntax highlighter, including scroll bars appearing even when they are not necessary, and not being able to get F# syntax highlighting working. Annoyingly Syntax Highlighter, throws up message boxes whenever it can’t find the syntax highlighter.

So I started taking a look at highlight.js, which has a number of very nice looking themes, a good up to date range of supported languages, and all the files available on a CDN, which makes it very easy to integrate with a blog. Integrating highlight.js is very easy, but it assumes that you will wrap all your code inside  <pre><code class="lang"> … </code></pre>.

However, for syntax highlighter, all code is wrapped inside a pre block with a rather unusual class syntax for specifying the brush: <pre class="brush: lang"> … </pre>. So to make the transition I would need to update all my posts to wrap each code snippet in a pre and a code block, and I would also no longer be able to use the precode plugin.

But the nice thing about highlight.js, is that you can programmatically point it at the DOM elements you want it to highlight, so I decided to see if I could write some javascript that would use highlight.js to format the code previously formatted by syntax highlighter.

There were two steps. First, in the <head> portion of my page, I needed to reference the highlight.js CSS and javascript files, as well as pull in the one non-core brush that I needed (F#).

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/tomorrow-night.min.css"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/languages/fsharp.min.js"></script>

Then, on page load, I needed to find each of the syntax highlighter code blocks, discover the language to format them with, and pass them on to highlight.js to be highlighted. I used a regex to find the original “brush”, and had to convert the “plain” brush to “nohighlight”. I deliberately decided against highlighting any blocks that didn’t match the regex as this allows me to use GitHub gists, or start using the proper highlight.js syntax if I want to in future. Since I’m not using JQuery, I just used vanilla JavaScript. As I’m not really much of a JavaScript expert, I’m sure this could be improved on a fair bit, but it seems to do the trick nicely.

document.addEventListener("DOMContentLoaded", function (event) {
    var languages = hljs.listLanguages();
    // console.log(languages);
    var codeBlocks = document.getElementsByTagName("pre");

    for (var i = 0; i < codeBlocks.length; i++) {
        var block = codeBlocks[i];

        var regex = /brush\:\s([a-zA-z]+)/g;
        match = regex.exec(block.className);
        var brushName = "nohighlight";
        if (match != null) {
            var oldBrushName = match[1];
            if (oldBrushName == "csharp") oldBrushName = "cs";
            if (oldBrushName == "js") oldBrushName = "javascript";
            if (languages.indexOf(oldBrushName) === -1) {
                // console.log("unsupported brush " + oldBrushName);
            }
            else {
                brushName = oldBrushName;
            }
            block.className = "hljs " + brushName;
            hljs.highlightBlock(block);
        }
    }
});

And that’s all there is to it. I’m using this both here at markheath.net and at my old no longer updated blog at blogger (which still gets way more traffic than this site).

Comments

Comment by khartnjava

Thank you very much!

khartnjava