Have Pandoc Recognize Your Literature Links as Citations!

I use the Citations plugin to manage citations.

Within Obsidian, I really would prefer to have links to the literature note rather than citations:

(1) [[@darwin-1856-origin]]

But, of course, for Pandoc to render this citation properly this should be:

(2) [@darwin-1856-origin]

Pandoc recognizes the second as a citation, but wraps the finalrendering with the extra brackets .

The following filters the token stream to strip the extra brackets from the citation.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from pandocfilters import toJSONFilter, Str, Plain, Para
import sys
import re

def replace_citation_links_with_citation(key, value, format, meta):
    # sys.stderr.write(f"=== {key} ===>\n")
    # sys.stderr.write(f"{value}\n\n")
    elements = []
    if key == "Plain" or key == "Para":
        for item_idx, item in enumerate(value):
            if item["t"] == "Str" and item["c"] == "[":
                if item_idx < len(value) - 1:
                    if value[item_idx + 1]["t"] == "Cite":
            elif item["t"] == "Str" and item["c"] == "]":
                if item_idx > 0:
                    if value[item_idx - 1]["t"] == "Cite":
        if key == "Plain":
            return Plain(elements)
        elif key == "Para":
            return Para(elements)

if __name__ == "__main__":

If saved to a file, e.g. ~/.local/share/pandoc-filters/obisidian-citation-links.py, and invoked when running pandoc by --filter ~/.local/share/pandoc-filters/obisidian-citation-links.py, then something like this:

The best cookies in the world have cardamom in them [[@darwin-1856-origin]] .

will look like the following to Pandoc.

The best cookies in the world have cardamom in them [@darwin-1856-origin] .

So you can now have your citations and link them too.


Thanks for posting this!

1 Like

This is not working for me. Do I need to install any python packages to make it work?

In VS Code, it says:

	"resource": "/C:/Users/FeralFlora/AppData/Local/Pandoc/filters/wikilink-citation.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "reportUndefinedVariable",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pyright/blob/main/docs/configuration.md",
			"scheme": "https",
			"authority": "github.com",
			"fragment": "reportUndefinedVariable"
	"severity": 4,
	"message": "\"Para\" is not defined",
	"source": "Pylance",
	"startLineNumber": 26,
	"startColumn": 20,
	"endLineNumber": 26,
	"endColumn": 24

On this line:

It also says that Sys, Str and Re are imported but not accessed:

Typo / mispaste in original code. Note the import now includes Para:

from pandocfilters import toJSONFilter, Str, Plain, Para

Sorry for the confusion!

1 Like

Great, thanks for the answer. However, what about all the things that are not accessed, can I just remove them? Sys, re, str and the format, meta parameters in the function.


The function signature (format, meta, etc.) should remain the same. You can (probably) drop the unneeded imports.

1 Like

Great, I’m going to test it now :+1:

There seems to be a bug. This:

Becomes this (note the extra trailing ].

Also, this workflow is incompatible with the wikilinks_title_after_pipe extension, because citations will simply become links :cry:

I am considering adopting the convention:

The quick brown fox jumps over the lazy dog [[some/path/to/library/@author-year-title|[@author-year-title]]]

and just rely on stripping away the links to “reveal” the clean pandoc citation in the display name. This should be possible with the default mediawiki link filters, I think? A little bit of redundancy in typing, but IF pandoc can process the citation correctly, then it will be worth it.

Ok, @mgmeyers “Easy Bake” plugin resolves everything.

In particular:

blah blah [[sources/references/a/@anderson-1979|[@anderson-1979]]] blah

gets nicely expanded to:

blah blah [@anderson-1979] blah 

along with all other links and embeds (!!!) in a single standalone document. Can process with pandoc etc. normally after that.
:partying_face: :partying_face: :partying_face: