Skip to content

Instantly share code, notes, and snippets.

@keeferrourke
Last active February 5, 2024 22:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keeferrourke/52914770dfa6d070e50310971514f362 to your computer and use it in GitHub Desktop.
Save keeferrourke/52914770dfa6d070e50310971514f362 to your computer and use it in GitHub Desktop.
Typesetting with Pandoc Markdown

Typesetting with Pandoc Markdown: How I Take Notes

Preface

Over the past couple years in school, I've placed tremendous value in a few things:

  • Comprehensive, single-document summaries of courses I've taken;
  • Beautifully type-set reports;
  • Writing the bare-minimum of LaTeX to get by.

I've made this guide in the hopes it may be helpful to other students pursuing CS and/or math education.

Consequently, I like this method so much, this is how I take notes, write reports, and compose pretty much any document these days. If you want to see this in action in a more complicated project, I've made a custom template for composing nice-looking recipes using Pandoc YAML/Markdown here.

The Tools

Before we get started, get yourself a copy of:

  • A full LaTeX distribution with xelatex (texlive-full on Fedora Linux, other packages on other operating systems)
  • Pandoc 2.11 or higher (https://pandoc.org)
  • The pandox-xnos filter suite
  • An editor that understands Markdown syntax with pandoc extensions (VS Code and vim both have good plugins)
  • A nice pandoc template like this one

The Files

This document-creation strategy is highly-template based. I'm lazy, so I haven't scripted anything, but replace anything like ${var} with a real value for your notes/report.

  1. YAML Meta-data (metadata.yml)
  2. Markdown body (body.md)
  3. Makefile
  4. A CSL file for references (optional; I use ieee.csl, Pandoc defaults to Chicago style)

YAML Meta-data

If you're not familiar with Pandoc, you can provide a bunch of document information, invocation arguments, etc. via a well-formed YAML file. With recent versions of Pandoc, you can even define CSL-json references, instead of using gross tools like bibtex.

metadata.yml
---
# Document meta-data. See pandoc.org for a full list of options.
lang: en-CA
title: '${title}'
subtitle: '${subtitle}'
date: '${date-string}' # For reports, try \today.

author: # Yup, this is a list
  - Keefer Rourke
  - Second Author
  - And so on...

# You can omit this to use the template's default class
documentclass: scrartcl

# This is a list of what you would literally pass as geometry options to the `\documentclass{}`
geometry:
  - top=0.5in
  - bottom=0.5in
  - left=0.5in
  - right=0.5in

urlcolor: blue
fontsize: 11pt

# Section numbers, table of contents, list of figures, list of tables.
numbersections: false
toc: true
toc-own-page: false
lof: false
lot: false

# If you're using a custom template, here's a good place to put extra options specific to that tpl.

# More literal LaTeX! Whatever packages you want to include, and other configurations
# that belong in a document preamble.
header-includes:
 - \usepackage{enumitem}
 - \usepackage{amsfonts}
 - \usepackage{lipsum}
 - \usepackage{forest}
 - \setlist[itemize,1]{label=$\bullet$}
 - \setlist[itemize,2]{label=$\circ$}

# CSL-style references go under this block, as a list.
references:
 - id: example
   type: webpage
   title: Example
   author:
     - given: First
       family: Last
     - literal: Some Entity
   URL: https://example.com

...
# ^ This end of document delimiter is very important!

Markdown body

The beauty of Pandoc is that you can write vanilla Markdown, but also take advantage of syntax extensions, like GitHub pipe-tables, fenced-code blocks, and custom extensions written by the community. All items can also take additional parameters in {} curly blocks, which direct Pandoc how to render them in a PDF, HTML, or other compilation target. Furthermore (and this is particularly useful if you need to layout a weird figure or typeset math), you can intermix LaTeX commands with Markdown syntax fluidly.

Here's an example:

body.md
# Inline LaTeX

This is markdown, but now here's some lorem ipsum text generated by LaTeX: \lipsum[1]

## Math

Inline math is supported $\sum_{n=1}^{\infty} \frac{1}{n}$.

### Display Math

And display math (centered on a new line below). $$\sum_{n=1}^{\infty} \frac{1}{n}$$

Of course you can also start multi-line math environments like `\begin{align*}` if you want:

\begin{align*}
  I &= \int f(x) dx \\
    &= \int \frac{1}{x} dx \\
    &= ...
\end{align*}

### Figures
![Alt-text becomes an automatic caption.](/path/to/img){width=100% #fig:id}

Using the `fignos` extension, you can back-link to any figure, like +@fig:id.

Citations are also easy, and you can put them anywhere text goes.
They'll be formatted automatically according to the CSL file you're using [@example].

# Code snippets

Need to render some code with line numbers?

<!-- You can use backticks, but I'm writing this in a back-tick fenced block right now...
     And tildes work fine too! -->

~~~{.c .numberLines}
#include <stdio.h>
~~~

Have some commentary half way through a snippet? Restart the numbering!

~~~{.c .numberLines .startFrom=42}
int main(int argc, char* argv) {
  if (argc < 1) return 1;
  printf("Hello %s!\n", argv[1]);
  return 0;
}
~~~

# Embedded LaTeX

Need to include some fancy LaTeX stuff, like a tree diagram? Annotating a block with `{=latex}` will render the fenced code in-place, exactly as the written LaTeX, with no attempt to further process it by Pandoc.

~~~{=latex}
\begin{center}
\begin{forest}
for tree={
  grow=south,
  minimum size=2em, l sep=10mm, s sep=10mm,
  edge=->
}
[ A
 [ B ]
 [ C [ D ]
 [ E ]
]
\end{forest}
\end{center}
~~~

# References

By defaut, CSL-references will get appended to the document, but this isn't always desirable.
Control where they go by inserting a div with the `#refs` ID.

::: {#refs}
<!-- The bibliography will go here now, so I can write additional content after it. -->
:::

Awesome!

Makefile

Makefile

A simple Makefile pulls it all together and lets you easily integrate your favourite editor with a hot PDF compilation pipeline.

SHELL = /bin/bash

.SUFFIXES:
.SUFFIXES: .md .yml .jpg .png .svg .pdf

# Inputs and outputs
DOCNAME = 'notes.pdf'
SRCFILES = body.md metadata.yml

# Omit or use the string 'default' for the default Pandoc LaTeX template.
# Any other string resolves to the template installed to $HOME/.pandoc/templates/$TEMPLATE.tex.
TEMPLATE = 'default'

.PHONY: pdf clean

pdf:
	@pandoc -o $(DOCNAME) $(SRCFILES) --template $(TEMPLATE) \
		--filter pandoc-fignos \
      --filter pandoc-tablenos \
      --filter pandoc-eqnos \
		--pdf-engine=xelatex \
		--columns=3 \
      --citeproc \
      --csl=ieee.csl

clean:
	-@rm $(DOCNAME)

Useful editor integration

Vim

Not all markdown files I edit are meant for Pandoc, so I register a custom file type for pandoc-markdown. If pandoc syntax highlighting gets in the way of what I'm doing (e.g. I never want pandoc features in a README file), then I call setf markdown to switch to plasticboy's markdown highlighter instead.

Excerpts from my vimrc
call plug#begin(g:vim_home.'/plugged')

Plug 'plasticboy/vim-markdown'          " Better markdown support
Plug 'vim-pandoc/vim-pandoc'            " Pandoc integration
Plug 'vim-pandoc/vim-pandoc-syntax'     " Extended markdown syntax

call plug#end()

augroup pandoc_syntax
  au! BufNewFile,BufFilePre,BufRead *.md set filetype=md.pandoc
augroup END

au FileType markdown    set cc=100 tw=0
au FileType md.pandoc   set cc=100 tw=100 spell formatoptions-=t
au BufRead  README      set cc=72 tw=72 filetype=markdown
au BufRead  README.md   set cc=72 tw=72 filetype=markdown

VS Code

I don't extensively use VS Code, but I've found this plugin is ok:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment