Dec 2, 2019

Extend markdown parser for Hugo

golang article

I use Hugo for my blog and notes. And the most powerful thing I love in Hugo is Shortcodes. It's a wrapper of html but support to use Hugo's vars and functions. With shortcodes you can add a css class to your link or embed a code snippet from a Github link.

The thing is, typing a shortcodes such as {{<name "string1" "stirng2">}}, is a little bit heavey for me especially when I want to edit my blog on iPhone, I can't even type the {{}}. So I start to investigate if there is a way to simplify this in Hugo.

I found that Hugo starts to use http://github.com/yuin/goldmark as its default markup engine since v0.60.0 and goldmark is easy to extend. It should be feasible to fork Hugo to use my own goldmark extensions.

Details for writing an extension for goldmark is out of scope of this post. Typical there are 3 steps:

  1. create AST
  2. define the parser
  3. define how to render it

You can find some examples in both https://github.com/yuin/goldmark/tree/master/extension and https://github.com/kaleocheng/goldmark-extensions.

I decided to use a new syntax to replace the long shortcodes syntax:

- {{<name "string1" "stirng2">}}
+ @name("string1", "string2")

It's easier to type and readable for me. Next I forked and updated Hugo's code, re-built it to use my extenions. It's very straightforward:

  1. add extension package to go.mod and run go mod tidy to download
  2. append new extensions in Extensions https://github.com/gohugoio/hugo/blob/master/markup/goldmark/goldmark_config/config.go#L44 and enable them in https://github.com/gohugoio/hugo/blob/master/markup/goldmark/goldmark_config/config.go#L19
  3. import extenions pkg and add them to newMarkdown https://github.com/gohugoio/hugo/blob/master/markup/goldmark/convert.go#L67
  4. install mage and re-build with mage hugo

use replace github.com/xxx/xxx => /Users/xxx/localdir in go.mod when you develop the extension package.

I also wrote an extension for \LaTeX which parse \TeX code by $...$ and $$...$$. (In addition, I use a fork version of https://github.com/atishay/tex2svg as the backend to embedded \TeX svg at build time).

Finally I have my own syntax in markdown:

- {{<book "The Old Man and The Sea" >}}
+ @book("The Old Man and the Sea")
- {{<refer "example.com" >}}
+ @refer("example.com")
- {{<latex x^2 + y^2 = 0 >}}
+ $x^2 + y^2 = 0$