Skip to content

jez/pandoc-sidenote

Repository files navigation

pandoc-sidenote

Convert Pandoc Markdown-style footnotes into sidenotes

This is a simple Pandoc filter to convert footnotes into a format that can be consumed by Tufte CSS and Pandoc Markdown CSS Theme.

Lua filter vs JSON filter

This project provides two, equivalent filters:

  • pandoc-sidenote.lua, a Lua filter, which is run invoked internal to the pandoc binary. See Lua filters in the Pandoc docs for more.

    This is the preferred way to use pandoc-sidenote.

    The Lua filter is newer than the JSON filter, but I have tested it on a wide range of Markdown files and it produces byte-wise identical results.

  • pandoc-sidenote, a JSON filter which reads a JSON representation of the pandoc AST on stdin and produces JSON on stdout.

    This filter is written in Haskell and compiled to a native executable. It uses the upstream pandoc-types library to deserialize the JSON it receives on stdin, which means that pandoc-sidenote can only be used with a version of pandoc built against the same pandoc-types version. See JSON filter dependencies below.

    This is cumbersome, as it means that pandoc-sidenote needs to be rebuilt and republished for any new pandoc versions which makes a change to the core AST, even if it's a part of the AST that this filter doesn't care about.

JSON filter dependencies

The Lua filter has no dependencies. Skip ahead to Installation to install the Lua filter.

The JSON filter is built against a specific version of Pandoc. This table maps pandoc versions to pandoc-sidenote versions:

pandoc pandoc-sidenote
3.0 0.23.0
2.11 0.22.0, 0.22.1, 0.22.2
2.9 0.20.0
2.1, 1.19 0.19.0
1.18 0.9.0

If a newer version of pandoc has been released, the Stack build manifest will need to be adjusted for that version, and the project then rebuilt.

Installation

The Lua filter (pandoc-sidenote.lua) is the preferred way to use this project. You can install it globally or local to a project. The Lua filter is a single Lua file that works on all platforms where pandoc works.

Alternatively, you can install the pandoc-sidenote native executable, which works as a JSON filter. JSON filters are slower and more tedious to use with cutting edge Pandoc versions.

Lua filter, globally installed

Consult the docs for how Pandoc searches for Lua filters.

To install globally:

  1. Download pandoc-sidenote.lua

    pandoc-sidenote.lua

  2. Put the file in the Pandoc user data directory. See the Pandoc docs for what the data directory is on your system. Specify a data directory by passing --data-dir when invoking pandoc.

  3. Invoke pandoc like this:

    pandoc --lua-filter pandoc-sidenote.lua [...]
    

As an example, on macOS or Linux, this shell snippet will download and install the filter globally:

curl --remote-name --no-clobber --create-dirs \
  --output-dir "${XDG_DATA_DIR:-$HOME/.local/share/}/pandoc/filters" \
  -sSL "https://github.com/jez/pandoc-sidenote/raw/refs/heads/master/pandoc-sidenote.lua"

Lua filter, locally installed

Consult the docs for how Pandoc searches for Lua filters.

To install locally:

  1. Download pandoc-sidenote.lua

    pandoc-sidenote.lua

  2. Put the file in the Pandoc user data directory. See the Pandoc docs for what the data directory is on your system. Specify a data directory by passing --data-dir when invoking pandoc.

  3. Invoke pandoc like this:

    pandoc --lua-filter ./pandoc-sidenote.lua [...]
    

As an example, on macOS or Linux, this shell snippet will download and install the filter into the current directory:

curl --remote-name --no-clobber \
  -sSL "https://github.com/jez/pandoc-sidenote/raw/refs/heads/master/pandoc-sidenote.lua"

JSON filter, Cabal

pandoc-sidenote is on Hackage and can thus be installed using cabal:

cabal install pandoc-sidenote

JSON filter, Homebrew

If you're on OS X, you can install the pandoc-sidenote binary from my Homebrew tap:

brew install jez/formulae/pandoc-sidenote

JSON filter, From Source

Otherwise, you'll have to install from source. This project is written in Haskell and built using Stack. If you're new to Haskell, now's a perfect time to wet your toes! Go install Stack first, then run these commands:

git clone https://github.com/jez/pandoc-sidenote

cd pandoc-sidenote

# this is going to be reaaally long the first time
stack build

# copy the compiled binary onto your PATH
stack install

Features

  • By default, all markdown foot notes will be converted into numbered side notes.

    This will be a side note.[^1]
    
    [^1]: Example side note text.
    
  • To get a margin note (which has no number), make the footnote text start with {-}. This is akin to the # Heading {-} syntax that Pandoc supports for eliding numbers in documents that would otherwise have numbered headings.

    This will be a margin note.[^2] It will not have numbers
    
    [^2]: {-} Example margin note text.
    
  • To leave a footnote untouched so that it remains in the document as a normal footnote, prefix the text with {.}.

    This text will remain a footnote.[^3]
    
    [^3]: {.} Example footnote text.
    

    Be careful mixing side notes with footnotes in the same document, because they will be numbered independently. Documents that make heavy use of footnotes may want to use margin notes ({-}) instead of side notes.

  • By default, side notes and margin notes cannot contain block elements, like code blocks, lists, or tables. If they do, they are silently dropped.

    To avoid having block elements dropped, use {^} or {^-} for block-based side notes and margin notes, respectively.

    This side note[^4] and this margin note[^5] can contain block elements.
    
    [^4]:
        {^} There are block elements in this side note:
    
        - Hello, world!
    
    [^5]:
        {^} There are block elements in this margin note:
    
        ```python
        print("Hello, world!")
        ```
    

    Note: these two features produce an HTML structure that is currently only supported by Pandoc Markdown CSS Theme. Notably, Tufte CSS does not support this structure yet.

    Note: these two features are only supported by the Lua filter, not the JSON filter.

Haskell Library

The core functionality is also exposed as a Haskell library, which can be called by Haskell applications such as Hakyll. It comes in two different flavours:

  • SideNote.hs: An implementation making use of pandoc's native Span constructors. This is what's used in the pandoc-sidenote executable.

  • SideNoteHTML.hs: An implementation that converts the footnote directly into HTML, enabling the embedding of arbitrary blocks inside of side and marginnotes.

On the whole, each file weighs in at just about 100 lines of code—check them out if you're curious how they work.

Notes to myself

Side note: I run this command to generate the zip files attached to releases that are downloaded by the Homebrew formula:

make

It would be nice to get GitHub Actions set up to build and publish releases for each tagged commit automatically.

I run this command to publish packages to Hackage:

# First, edit `package.yaml` to remove `-Werror`, then:

stack upload .

License

MIT License

About

Convert Pandoc Markdown-style footnotes into sidenotes

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors