Table of Contents

Syntax Highlighting with Chroma in Hugo

And adding filename support using render hooks

10 Sep 2022. 404 words.


Motivation

You can config Hugo to generate highlighted code blocks with Chroma. This post records my experience of switching from highlight.js to Chroma, and implementation of some popular code block features such as adding filename as titles.

You can find the complete Hugo documentation here.

Result

This markdown

```html {path="layouts/partials/head.html", hl_lines="2-4"}
<head>
    <meta name="author" content="{{ with .Site.Params.author }}{{ . }}{{ end }}" />
    <meta name="description" content="{{if .IsHome }}{{ $.Site.Params.description }}{{ else }}{{ .Description }}{{ end }}" />
    <meta name="theme-color" content="#111111" />
</head>
```

is rendered as

layouts/partials/head.html
1
2
3
4
5
<head>
    <meta name="author" content="{{ with .Site.Params.author }}{{ . }}{{ end }}" />
    <meta name="description" content="{{if .IsHome }}{{ $.Site.Params.description }}{{ else }}{{ .Description }}{{ end }}" />
    <meta name="theme-color" content="#111111" />
</head>

Quick Chroma Tutorial

Chroma is enabled by default, so we can start highlighting codes by either specifying one of the languages Chroma supports in the markdown:

```javascript
function addOne(number) {
    return number + 1;
}
```

or by using the built-in highlight shortcode:

{{< highlight javascript >}}
function addOne(number) {
    return number + 1;
}
{{< /highlight >}}

You can also add parameters to adjust the code blocks further. For example, both markdown blocks:

```javascript {linenos=inline, hl_lines="1 4-6"}
function addOne(number) {
    return number + 1;
}
function addTwo(number) {
    return number + 2;
}
```
{{< highlight javascript "linenos=inline, hl_lines=1 4-6" >}}
function addOne(number) {
    return number + 1;
}
function addTwo(number) {
    return number + 2;
}
{{< /highlight >}}

render as follows.

1function addOne(number) {
2    return number + 1;
3}
4function addTwo(number) {
5    return number + 2;
6}

For the full list of options, visit the Hugo documentation.

Adding Titles

The usual approach to add a custom title to a code block is to write a separate shortcode above the code fence.

{{< path "/src/lib/util.js" >}}
```javascript
function addOne(number) {
    return number + 1;
}
```

This is rather cumbersome, so I added a custom markdown render hook so that the path can be specified within the inline option.

layouts/_default/_markup/render-codeblock.html
1
2
3
4
5
6
7
8
<div class="codeblock">
  {{- with (index .Attributes "path") -}}
    <div class="code-header">&gt; {{ . }}</div>
  {{- end -}}
  <div class="code-body">
    {{- highlight .Inner .Type .Options -}}
  </div>
</div>

This custom template allows us to provide a path option in code fences. For example, the source code for the code block above looks like this.

```html {path="layouts/_default/_markup/render-codeblock.html"}
<div class="code-container">
  ...
</div>
```