Last updated: 2020-01-30 00:54:09 +0000

Upstream URL: git clone


View repository

View issue tracker

Contents of follows


This software is released into the Public Domain – Chris Warburton, 2014-09-30


You’ll need some way to run Haskell. Check your package manager or go to to get a compiler or a <code>runhaskell</code> interpreter.

You’ll also need Pandoc available as a library, which you can get from your package manager or with <code>cabal install pandoc</code>, and will probably want the <code>pandoc</code> command available too.

To use PanHandle, invoke it as a Pandoc “filter”, like this:

<code>pandoc --filter ./panhandle input_file > output_file</code>

You can also run it standalone, but note that its stdio should be in Pandoc JSON format, which you can convert to/from using <code>pandoc -t json</code>/<code>pandoc -f json</code>.

To reduce the chance for error, ensure the version of Pandoc you’re using to generate/consume the JSON is the same as the version PanHandle’s built with.


PanHandle is a simple Haskell script using PanDoc. It allows code blocks and lines in PanDoc-compatible documents, eg. Markdown, to be “unwrapped” and become part of the overall document.

Any code blocks or lines with an “unwrap” class will have their contents parsed using Pandoc, then spliced into the document (inside a Div or Span). The content must be in “pandoc-json” format, which you can get by passing the <code>-t json</code> option to Pandoc.

For example, this Markdown list:

<pre><code> - A Markdown - List</code></pre>

Converts to this JSON:


Which we can splice into a document:

<pre><code>Mumble mumble ```{.unwrap} [{"unMeta":{}},[{"t":"BulletList","c":[[{"t":"Plain","c":[{"t":"Str","c":"A"},{"t":"Space","c":[]},{"t":"Str","c":"Markdown"}]}],[{"t":"Plain","c":[{"t":"Str","c":"List"}]}]]}]] ``` Groan groan</code></pre>

To give:

<pre><code>Mumble mumble - A Markdown - List Groan groan</code></pre>

Usage Notes


Code blocks will become Pandoc-native Div blocks, code lines will become Pandoc-native Span elements. These may affect rendering in some formats, eg. LaTeX, and may also affect post-processors, eg. other Pandoc scripts and CSS.


All of the code block’s attributes except for the “unwrap” class will be applied to the resulting Div or Span:

<pre><code>```{#foo .bar .upper .unwrap baz="quux" something="nice"} [{"unMeta":{}},[{"t":"Para","c":[{"t":"Str","c":"Some"},{"t":"Space","c":[]},{"t":"Emph","c":[{"t":"Str","c":"emphasised"}]},{"t":"Space","c":[]},{"t":"Str","c":"text"}]}]] ```</code></pre>

Will become:

<pre><code><div id="foo" class="bar upper" baz="quux" something="nice"> Some *emphasised* text </div></code></pre>

Replacement Order

PanHandle operates top-down, so blocks can be nested. For example:

<pre><code>Level 1A `````{.unwrap} Level 2A ```{.unwrap} Level 3A ``` ``` Level 3B ``` Level 2B ````` Level 1B</code></pre>

Will become:

<pre><code>Level 1A Level 2A Level 3A ``` Level 3B ``` Level 2B Level 1B</code></pre>

All code blocks are unwrapped first, then all inline code.

Inline Snippets

Here’s an example of PanHandle working on inline code snippets:

<pre><code>I hope the following is `[{"unMeta":{}},[{"t":"Para","c":[{"t":"Emph","c":[{"t":"Str","c":"emphasised"}]}]}]]`{.unwrap}.</code></pre>

Will become:

<pre><code>I hope the following is *emphasised*.</code></pre>

No Straddling

PanHandle operates by splicing syntax trees together, <em>not</em> via text replacement.

One consequence is that formatting cannot ‘straddle two levels’ of a document. As an example, if we put asterisks inside and outside a code snippet (the JSON corresponds to <code>be* emphasised</code>):

<pre><code>This will *not `[{"unMeta":{}},[{"t":"Para","c":[{"t":"Str","c":"be*"},{"t":"Space","c":[]},{"t":"Str","c":"emphasised"}]}]]`{.unwrap}.</code></pre>

They will remain as asterisks:

<pre><code>This will \*not be\* emphasised.</code></pre>

They <em>will not</em> join together for emphasis, like this:

<pre><code>This will *not be* emphasised.</code></pre>


PanHandle may be useful to you as a standalone script, but it was originally created to augment PanPipe. PanPipe can send the contents of code blocks to the stdin of a UNIX shell command, and dump the stdout back into the block.

PanHandle allows these results to escape their blocks and become part of the document. This makes it easy to write documents containing code to programmatically fetch/generate parts of themselves.