Hugo Syntax Highlighting

TL;DR 🚀

As much as I like Hugo, trying to figure out syntax highlighting when writing the last post, wasn’t as straight forward as I wanted it to be. The information I was looking for was a bit all over the place.

First it seems that Hugo is able to use different Markdown handlers. Basically different processors to generate HTML from Markdown. According to Wikipedia Markdown was invented in 2004 by no other than Aaron Swartz. And it also seems Hugo not only supports Markdown handlers, but also processors, which handle other formats, like rst, pandoc or even HTML. Crazy, writing HTML like it’s the 90s 🙃 Here is a list of all content format options.

Configure which Markdown handler to use Link to heading

So first thing which had to be done was telling Hugo which Markdown handler to use. This is what I added to my config.toml:

1
2
[markup]
  defaultMarkdownHandler = "goldmark"

As of Hugo version 0.60 this is not even needed as it seems Goldmark is Hugo’s default Markdown handler. However, sometimes there is some value in being explicit. Knowing from the config file which Markdown handler is actually in use may make it easier to search for additional parameters in the future. Forgetting “obvious” information is kind of easy. Here you can also find an example of how this looks like using yaml or json; and a list of alternatives like Blackfriday (Hugo’s default before version 0.60) or Highlight.

This is the GitHub repository of the Goldmark Golang module: https://github.com/yuin/goldmark. The README of this repository stresses that Goldmark is CommonMark compatible, which seems to be an effort to standardise Markdown. So CommonMark is [a] strongly defined, highly compatible specification of Markdown, while Markdown is a plain text format for writing structured documents, based on formatting conventions from email and usenet.1

Configure Syntax Highlighting Link to heading

The syntax highlighting can be configured in the config.toml file as well:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[markup.highlight]
  style = "solarized-dark"
  anchorLineNos = false
  codeFences = true
  guessSyntax = true
  lineAnchors = ""
  lineNoStart = 1
  lineNos = true
  lineNumbersInTable = true
  noClasses = true
  tabWidth = 2

And Goldmark can be configured as shown in the complete example at the end of this post.

Using Syntax Highlighting Link to heading

The example below shows how to create a code block with syntax highlighting now in Markdown. Specific lines can be highlighted. And some parameters set globally in the config.toml can be overwritten at the code block, too.2

```LANGUAGE {hl_lines=[1],linenos=false}
EXAMPLE CODE
```

LANGUAGE needs to be replaced by the language being used in the code block. Like go, markdown or haskell. A full list of supported languages can be found here.

This example actually uses the local overrides shown in the example itself. No line numbers (linenos) and highlight line 1 (hl_lines). It wasn’t straight forward to find out what parameters could be used at the beginning of the code blocks. Turns out it’s these below, taken straight from the code on GitHub:

Parameter Value(s)
hl_lines Highlight certain lines. Possible values as found in the unit tests: [1], [3,5] or [1-4,10].
hl_style Full list of styles can be found here. Examples below.
nohl No highlighting. Any value seems to be considered true.
linenos true, false, inline and table. The latter two only influence the generated HTML according to the unit tests.
linenostart Any integer the code should start at.

Multiple parameters have to look like in this example. No spaces between them:

0
1
2
3
4
5
6
7
8
  ```go {hl_lines=[1],linenostart=0,hl_style=bw}
  package main

  import "fmt"

  func main() {
      fmt.Println("Hello World")
  }
  ```

This example also shows that the lines to highlight don’t seem to change with linenostart. Which seems to be a feature not a bug as one parameter doesn’t depend on the other.

The Styles Link to heading

In line 2 of the highlighting configuration in config.toml, but also at the beginning of the code block, there is the style (or hl_style) parameter, which influences how the code blocks actually look like.

Here is a list of all available styles: https://xyproto.github.io/splash/docs/all.html

This is what monokai looks like:

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}

Or something lighter? This is murphy:

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}

fruity looks also nice:

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}

The Solution Link to heading

Here is the complete section with all available options of the config.toml for syntax highlighting in code blocks:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[markup]
  defaultMarkdownHandler = "goldmark"

[markup.highlight]
  style = "solarized-dark"
  anchorLineNos = false
  codeFences = true
  guessSyntax = true
  lineAnchors = ""
  lineNoStart = 1
  lineNos = true
  lineNumbersInTable = true
  noClasses = true
  tabWidth = 2

[markup.goldmark]
  [markup.goldmark.extensions]
    definitionList = true
    footnote = true
    linkify = true
    strikethrough = true
    table = true
    taskList = true
    typographer = true
  [markup.goldmark.parser]
    autoHeadingID = true
    autoHeadingIDType = "github"
    [markup.goldmark.parser.attribute]
      block = false
      title = true
  [markup.goldmark.renderer]
    hardWraps = false
    unsafe = false
    xhtml = false

Use like this:

1
2
3
4
5
6
7
8
9
  ```go {hl_lines=[6]}
  package main

  import "fmt"

  func main() {
      fmt.Println("Hello World")
  }
  ```

Get HTML, which looks like this:

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}