Adding code snippets to Blogger posts (or any HTML pages)

As a preparation for writing a blog post about coding, I had to look for a way to show code snippets nicely on my post. I found highlight.js to be the best solution but the way to use it is not super straightforward. I'll explain how I use it on this blog post.

Using highlight.js

To "install" highlight.js, simply add the following code inside the <head> section:

<link href='//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/default.min.css' rel='stylesheet'/>
<script src='//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js'/>
<script>hljs.initHighlightingOnLoad();</script>

If you're using Blogger, this should be done in the theme html file, which you can get to by going to the "Theme" tab, clicking the "Customize" button, and choosing "Edit HTML". This is just like how I added MathJax to Blogger.

After we have installed highlight.js to our page, we can insert a code block by putting the code snippet to highlight in a <pre><code class="language"> block, where "language" is actually the language of the code. For example, the following Python code block

def isPositive(x: int):
  if x > 0:
    return True
  else:
    return False

is produced by the following code in HTML:

<pre><code class="python">def isPositive(x: int):
  if x &gt; 0:
    return True
  else:
    return False
</code></pre>

Notice 2 things:

  • The first line of the code has to be on the same line has the HTML tag; otherwise, the produced code block will contain an empty line at the top.
  • HTML special characters have to be escaped. In the above example, > in the Python code must be changed to &gt; in HTML.

Fortunately, escaping HTML characters doesn't have to be done manually. There are many services available online. The one I use is http://www.htmlescape.net/htmlescape_tool.html. You probably won't need to escape newline and space characters so you can uncheck those boxes.

Code blocks without highlighting

To insert a monospaced block that isn't any language (like terminal output), you can use <code style="plaintext"> or <code style="nohighlight">. I prefer the former because the latter will not apply the color theme at all, making the code block blend in a little too well with its surrounding.

Customizing the highlighting style

In the installation step, the first line that we added to the HTML code was

<link href='//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/default.min.css' rel='stylesheet'/>

This line picks the "default" style by linking to the file default.min.css. There are other styles available, and you can test them out on highlight.js demo page. Once you find the style you like, go over to cdnjs page to find the corresponding file URL. The file name may be slightly different of the style name on the demo page, but you should be able to guess which file is the right one. Once you find it, just put it in place of default.min.css.

Adding uncommon languages

The installation step described above only installs a default set of "common" languages. highlight.js supports many other languages, but we'll have to add the support ourselves. You can see all the languages supported by highlight.js as well as which ones are considered common on highlight.js download page.

Let me show how to add a language that is not listed as common with an example. Suppose we want to add highlighting to Haskell code. (Haskell is not common as of version 10.1.2 of highlight.js.)

First, we check if it's available on the download page because if it isn't, we can't really do anything about it. Lucky for us Haskell is available.

Next, we go to cdnjs page and search for a js file for Haskell. Similar to how we look for a style, we might have to guess the file name a little bit, but it shouldn't be hard to find. In this case, what we want is https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.2.0/languages/haskell.min.js. Once we have the URL, we include it by inserting

<script charset='UTF-8' src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/languages/haskell.min.js'/>

right before

<script>hljs.initHighlightingOnLoad();</script>

(This is the third line in the first code snippet of this post.)

We can repeat this process to add as many languages as we want.

But for now let me show that what I did actually works for Haskell. Here's a Haskell code block:

import Control.Monad;
import Data.IORef;

class Talker a where
  hear :: a -> IO String

data IntCounter = IntCounter (IORef Int)

instance Talker IntCounter where
  hear (IntCounter c) = do
    x <- readIORef c
    modifyIORef' c (+1)
    return $ show x

-- Entry point of the program
main :: IO ()
main = do
  counterRef <- newIORef (1 :: Int)
  let counter = IntCounter counterRef
      loop = do
        heard <- hear counter
        mapM_ putStr ["I heard ", heard, ".", "\n"]
        when ((length heard) < 2) loop
  loop

And to demonstrate how to use <code class="plaintext">, here's the output of the above code:

I heard 1.
I heard 2.
I heard 3.
I heard 4.
I heard 5.
I heard 6.
I heard 7.
I heard 8.
I heard 9.
I heard 10.

Using repl.it

repl.it is a great site for learning languages because it gives you playgrounds on the browser. You don't need to install anything to play with a language. Moreover, it supports code sharing and collaboration too.

Here is a repl.it link for the Haskell code above. If you access that link and modify the code, you'll get your own fork of the original code. This is a very nice feature for blog writing!

repl.it also provides an simple way to embed the code as an iframe. The result looks like this:

The drawback of embedding an iframe is that it takes longer to load, and it doesn't display the code very nicely. My preference is to share code in my post with highlight.js, and occasionally share a repl.it link so that you can fork the code and play with it.

Note: If you use repl.it and want to upgrade, you can also help me by upgrading through my referral link 😜

Comments

Popular posts from this blog

C++: Hidden array copy operation

You could have invented the determinant