Custom Pandoc Options with Hakyll 4

Pandoc has a huge set of extensions which are not enabled by default and whilst Hakyll does enable quite a few in its own options (like footnotes), I wanted to add support for definition lists.

In Hakyll, the best way to do this seems to be to implement a custom content compiler, as this can then be used everywhere you render content. This is exactly what I did.

The first thing was to look up the reference to the default compilers and see what was already there. Hakyll provides:

  • pandocCompiler
  • pandocCompilerWith
  • pandocCompilerWithTransform

The second of these allows you to pass in options (ReaderOptions and WriterOptions) and is actually called by the first but with only the default options. The implementation of pandocCompiler looks like:

pandocCompiler :: Compiler (Item String)
pandocCompiler =
    pandocCompilerWith defaultHakyllReaderOptions defaultHakyllWriterOptions

Which gives us both the pattern to copy and the type declaration. The next step is to add on custom options to the defaults. Pandoc gives a list of the options that can be passed to it in it’s documentation.

The defaultHakyllWriterOptions are defined as a set, so we’ll need to add to that set and we’ll also need to be able to access the Pandoc options, so first import those:

import qualified Data.Set as S
import           Text.Pandoc.Options

Then, we need to build up the custom compiler. That looks like this:

customPandocCompiler :: Compiler (Item String)
customPandocCompiler =
    let customExtensions = [Ext_definition_lists]
        defaultExtensions = writerExtensions defaultHakyllWriterOptions
        newExtensions = foldr S.insert defaultExtensions customExtensions
        writerOptions = defaultHakyllWriterOptions {
                          writerExtensions = newExtensions
    in pandocCompilerWith defaultHakyllReaderOptions writerOptions

(To see it in place, you can see the version in the repository.)

To walk through the compiler:

  1. We set the list of extensions we wish to apply.
  2. Compute the default set of extensions.
  3. Insert our list of extensions into the set.
  4. Initialise the writer options.
  5. Pass that over to the pandocCompilerWith compiler.

Subsequently, we can use customCompiler everywhere we were previously using pandocCompiler, and without having to repeat our options.