I’ve recently started using Quarto, which is a new open source project backed by RStudio. Quarto is a system for producing reports, presentations, books and blog posts. It takes text formatted with markdown and code written in Python or R and produces PDFs, HTML or several other formats that contain the formatted text, the code (optionally) and the outputs from that code. In a lot of ways, Quarto is like R Markdown or Jupyter Notebooks. Quarto uses Pandoc to do actually convert document formats, and Quarto actually works quite well with version control software like git, unlike Jupyter Notebooks.

I’ve written about using R Markdown or Jupyter for reproducibility in engineering reports, and I’ve written about creating custom document templates for reports written using Pandoc. Much of what I’ve written in those posts should be applicable to Quarto.

To date, I’ve written two posts on this blog using Quarto: Violin Bow Stiffness and Shear of Adhesive Bonded Joints. This post describes some of my experiences using Quarto. Overall, I’ve been quite happy with it.

Blogging with Quarto and Pelican

Quarto has built-in support for blogging with Hugo. However, this blog is using Pelican, not Hugo. A few tweaks are needed.

Since the Quarto posts are written in Markdown, they have YAML headers. Here is the header for one of my blog posts:

---
title: Shear of Adhesive Bonded Joints
date: 2022-06-25
format: commonmark_x
keep-yaml: true
Tags: Engineering, Python, Adhesive Bonding
Category: Posts
filters:
    - attach-filter.lua
---

Let’s go through the lines in this header one at a time:

  • title: Self-explanatory — the title of the post
  • date: Also self-explanatory — the date of the post
  • format: There are several output formats for Quarto. I’ve found that commonmark_x works the best for Pelican. This output format produces a .md file in a format that (mostly) works with Pelican.
  • keep-yaml: Setting this option to true tells Quarto to copy the present YAML header to the output .md file.
  • Tags: This is an option used by Pelican. Since we’ve set keep-yaml = true, this gets copied to the .md file that Pelican will process.
  • Category: Another option used by Pelican.
  • filters: We’ll talk about this next.

Lua Filters

Pandoc uses something called a filter to alter the output. These filters are written in a language called Lua. In order for Pelican to include an image, the filename of the image needs to start with {attach}. This tells Pelican to include the image file in the website output.

The following filter edits each image element when it’s being processed. The name of the filter (Image) means that it applies to images. This filter concatenates the string {attach} with the src attribute of the image and stores the result in the src attribute of the resulting element.

function Image (elem)
    elem.src = "{attach}" .. elem.src
    return elem
end

Similarly, for links, Pelican requires that links to internal files on the blog start with {filename}. External links are used as-is. To do this, I use the following filter, which applies to Link elements. It checks if the target of the link starts with http. If so, it uses the link as-is. Otherwise, I assume that the link is an internal link, so the filter pre-pends the target with {filename}.

function Link (elem)
    if( string.find(elem.target, "http", 0) )
    then
        return elem
    else
        elem.target = "{filename}" .. elem.target
        return elem
    end
end

I’ve created a file called attach-filter.lua containing both of the filters above. The filters line in the YAML header tells Quarto to use these filters when processing the file.