👨‍💻 about me home CV/Resume News 🖊️ Contact Github LinkedIn I’m a Haskeller 🏆 Best of LuaX pub bang ypp panda lsvg Fizzbuzz Calculadoira TPG todo pwd rrpi

About panda

About panda

Panda is a Pandoc Lua filter that works on internal Pandoc’s AST.

It provides several interesting features:

Panda is heavily inspired by abp reimplemented as a Pandoc Lua filter.

If you need a more generic text preprocessor, ypp may be a better choice.

Open source

Panda is an Open source software. Anybody can contribute on GitHub to:

If you like Panda (or LuaX) and are willing to support its development, please consider donating via Github or Liberapay.

Installation

  1. Download the sources: git clone https://github.com/CDSoft/panda.
  2. Run ninja test to run tests.
  3. Run ninja install to install panda and panda.lua to ~/.local/bin or PREFIX=prefix ninja install to install panda and panda.lua to prefix/bin

panda and panda.lua can also be installed anywhere. Nothing else is required (except from Pandoc obviously).

Note that panda can also be installed with cdelord.fr/pub. This repository contains panda as well as some other softwares more or less related to LuaX.

Usage

panda.lua is a Pandoc Lua filter and is not meant to be called directly. panda is just a shell script that calls pandoc -L panda.lua ....

$ pandoc -L panda.lua ...

or

$ panda ...

A complete example is given as a Makefile in the doc directory.

Cheat sheet

Syntactic item Class Attributes Description
any string {{var}} is replaced by the value of var if it is defined (variables can be environment variables or Lua variables)
any block comment commented block
any block include=file replaces the div block with the content of file (rendered according to its format)
div block doc=file from=start_pattern to=end_pattern replaces the div block with text blocks from file (rendered according to its format). Blocks are separated by the patterns from and to (@@@ is the default separator).
div block, code block shift=n adds n to header levels in an imported div block
div block, code block pattern="Lua string pattern" format="output format" applies a Lua string pattern to the content of the file. The emitted text is format. format may contain captures from pattern.
code block meta definitions for the string expansion (Lua script), defined in the code block
any block, any inline if name=val block emitted only if name’s value is val
code block, inline code include=file replaces the code block content with the content of file
code block, inline code fromline=n from=n includes a file from line number n
code block, inline code toline=n to=n includes a file up to line number n
code block, inline code cmd="shell command" icmd="shell command" replaces the code block by the result of the shell command. Withicmd the code block content is parsed by Pandoc and included in a Div block.
code block render="command" replaces the code block by a link to the image produced by the command (%i is the input file name, its content is the content of the code block, %o is the output file name)

Commented blocks

Div blocks with the comment class are commented:

::: comment
This block is a comment and is discarded by panda.
:::

String expansion

panda stores variables in an environment used to expand strings. Variables can be defined by a Lua script with the meta class. The include attribute can also be used to point to an external file. Variables can only contain inline elements, not blocks.

The initial environment contains:

Variable names are enclosed between double curly brackets.

E.g.:

```meta
foo = "bar (note: this is parsed as **Markdown**)"
```

foo is {{foo}}.
```{.meta include=foo.lua}
This text is ignored, definitions are in foo.lua.
```

foo is defined in `foo.lua` and is {{foo}}.

meta code blocks contain Lua code executed by the Pandoc Lua interpretor. Panda also contains the LuaX modules reimplemented in Lua. More details are available in the [Luax documentation].

Conditional blocks

Blocks can be conditionally kept or omitted. The condition is described with attributes.

:::{.if name="value"}
This block is emitted only if the value of the variable "name" is "value"
:::

Div inclusion

Fragments of documents can be imported from external files. The include attribute contains the name of the file to include. The content of the file is parsed according to its format (deduced from its name) and replaces the div block content.

:::{include=file.md shift=n}
This text is optional and will be replaced by the content of file.md.
Section title levels are shifted by n (0 if not specified).
:::

The included file can be in a different format (e.g. a markdown file can include a reStructuredText file).

If the block has an input format as a class, the file is parsed according to this format.

Block inclusion

Code examples can be imported from external files. The include attribute contains the name of the file to include. The content of the file replaces the code block content.

```{.c include=foo.c fromline=3 toline=10 pattern="Lua string pattern" format="%1"}
This text is optional and will be replaced by the content of foo.c.
```

The optional fromline and toline defines the first and last lines to be included.

The optional pattern describes the part of the text that will be rendered. The format uses the captures defined by the pattern to format the content of the block ("%1" if not defined).

If the block has an input format as a class, its result is parsed according to this format.

Documentation extraction

Documentation fragments can be extracted from other source code files. The doc attribute contains the name of the file where documentation is extracted. All the documentation blocks are extracted, concatenated and parsed. The result replaces the div block content.

:::{doc=file.h shift=n from="@@@" to="@@@"}
This text is optional and will be replaced by the content of file.h
which is delimited by @@@.
Section title levels are shifted by n (0 if not specified).
:::

Scripts

Scripts can be executed by inline or code blocks. The cmd attribute defines the command to execute. The content of the block is in a temporary file which name is added to the command. If the command contains the %s char, it is replaced by the temporary file name. If the command does not contain any %s, the file name is appended to the command. The result replaces the content of the code block.

icmd can be used instead of cmd to let Pandoc parse the result of the command and include it in the document as a Span or Div node.

An explicit file extension can be given after %s for languages that require specific file extensions (e.g. %s.fs for F#).

Source Result
```{.python cmd=python}
print("Hello from Python!")
```
Hello from Python!
Lua says `print "Hello from Lua!"`{icmd=lua}
Lua says Hello from Lua!

Note: {.python cmd=python} is equivalent to {.python cmd="python %s"} and {.python cmd="python %s.py"}.

Diagrams

Code blocks containing diagrams are replaced with an image resulting from the diagram source code.

The render command is the render field. The output image name is a hash computed from the diagram source code.

The description of the image is in the caption and alt fields. caption is the caption of the diagram. alt is the alternative description of the diagram. The optional target field is a URL pointed by the image.

In the render command, %i is replaced by the name of the input document (generated from the content of the code block) and %o by the name of the output image file.

Images are generated in a directory given by:

The file format (extension) must be in the render field, after the %o tag (e.g.: %o.png).

If the program requires a specific input file extension, it can be specified in the render field, after the %i tag (e.g.: %i.xyz).

Optional fields can be given to set some options:

Source Result
``` { render="{{plantuml}}"
      caption="Caption"
      alt="Alternative description" }
@startuml
Alice -> Bob: hello
@enduml
```

Alternative description

Some render commands are predefined:

Diagram Predefined variable Render command
GraphViz dot dot -Tsvg -o %o.svg %i
dot.svg dot -Tsvg -o %o.svg %i
dot.png dot -Tpng -o %o.png %i
dot.pdf dot -Tpdf -o %o.pdf %i
PlantUML plantuml java -jar .build/plantuml.jar -pipe -charset UTF-8 -tsvg < %i > %o.svg
plantuml.svg java -jar .build/plantuml.jar -pipe -charset UTF-8 -tsvg < %i > %o.svg
plantuml.png java -jar .build/plantuml.jar -pipe -charset UTF-8 -tpng < %i > %o.png
plantuml.pdf java -jar .build/plantuml.jar -pipe -charset UTF-8 -tpdf < %i > %o.pdf
Asymptote asy asy -f svg -o %o.svg %i
asy.svg asy -f svg -o %o.svg %i
asy.png asy -f png -o %o.png %i
asy.pdf asy -f pdf -o %o.pdf %i
blockdiag blockdiag blockdiag -a -Tsvg -o %o.svg %i
blockdiag.svg blockdiag -a -Tsvg -o %o.svg %i
blockdiag.png blockdiag -a -Tpng -o %o.png %i
blockdiag.pdf blockdiag -a -Tpdf -o %o.pdf %i
mermaid mmdc mmdc --pdfFit -i %i -o %o.svg
mmdc.svg mmdc --pdfFit -i %i -o %o.svg
mmdc.png mmdc --pdfFit -i %i -o %o.png
mmdc.pdf mmdc --pdfFit -i %i -o %o.pdf
ditaa ditaa java -jar .build/ditaa.jar --svg -o -e UTF-8 %i %o.svg
ditaa.svg java -jar .build/ditaa.jar --svg -o -e UTF-8 %i %o.svg
ditaa.png java -jar .build/ditaa.jar -o -e UTF-8 %i %o.png
gnuplot gnuplot gnuplot -e 'set terminal svg' -e 'set output "%o.svg"' -c %i
gnuplot.svg gnuplot -e 'set terminal svg' -e 'set output "%o.svg"' -c %i
gnuplot.png gnuplot -e 'set terminal png' -e 'set output "%o.png"' -c %i
gnuplot.pdf gnuplot -e 'set terminal pdf' -e 'set output "%o.pdf"' -c %i
lsvg lsvg lsvg %i.lua -o %o.svg
lsvg.svg lsvg %i.lua -o %o.svg
lsvg.png lsvg %i.lua -o %o.png
lsvg.pdf lsvg %i.lua -o %o.pdf

Notes:

E.g.:

Source Result
```{.dot render="{{dot}}"}
digraph {
    rankdir=LR;
    input -> pandoc -> output
    pandoc -> panda -> {pandoc, diagrams}
    { rank=same; pandoc, panda }
    { rank=same; diagrams, output }
}
```

```{ render="{{gnuplot}}"}
set xrange [-pi:pi]
set yrange [-1.5:1.5]
plot sin(x) lw 4, cos(x) lw 4
```

Filters can be combined. E.g.: a diagram can be stored in an external file, included and rendered by panda.

Source Result
The file `hello.dot` contains:

```{.dot include="path/hello.dot"
         pattern="digraph%s*%b{}" }
```

The file hello.dot contains:

digraph {
    rankdir=LR;
    Hello -> World;
}
and is rendered as:

```{ render="{{dot}}"
     include="path/hello.dot" }
```

and is rendered as:

Makefile dependencies

It is sometimes useful to build a dependency list on the fly. panda can generate a dependency list for make, in the same vein than the gcc -M option. The environment variable PANDA_TARGET must be defined with the target name. panda will generate a file named ${PANDA_TARGET}.d containing the dependencies of ${PANDA_TARGET}.

The dependency filename can be redefined with the environment variable PANDA_DEP_FILE (e.g. to save the dependency file in a different directory).

PANDA_TARGET and PANDA_DEP_FILE can also be defined by the pandoc variables panda_target and panda_dep_file (e.g. pandoc -Vpanda_target=... -Vpanda_dep_file=...).

E.g.:

PANDA_TARGET=index.html panda index.md -o index.html

This will produce a file named index.html.d containing index.html: ....

Licenses

Panda

Panda is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Panda is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Panda.  If not, see <https://www.gnu.org/licenses/>.

For further information about Panda you can visit
http://cdelord.fr/panda

Feedback

Your feedback and contributions are welcome. You can contact me at cdelord.fr.