Basic Templates

'That's the idea,' replied Norton. 'This may be an indexed catalogue for 3-D images—templates—solid blueprints, if you like to call them that.'

Arthur C. Clarke, Rendezvous with Rama (1973)

So far, Mau provides features similar to Markdown, Asciidoc, and other markup languages. The real power of Mau, however, relies in its use of templates to render the output of the syntax.

Everything you saw in the previous chapters is rendered as described thanks to the default Jinja templates provided by the visitor, but such templates can be easily customised to provide the output you prefer.

The Abstract Syntax Tree

To start off on our journey with templates let's have a look at how Mau parses text. Let's assume the input is

Mau source
Stars identify *important* text.

This piece of text is processed by Mau and an internal representation called Abstract Syntax Tree (AST) is created. A compact version of the AST for this input is

Abstract Syntax Tree
data:
  type: document
  content:
  - data:
      type: paragraph
      content:
      - data:
          type: text
          value: 'Stars identify '
      - data:
          type: style
          value: star
          content:
          - data:
              type: text
              value: important
      - data:
          type: text
          value: ' text.'

You can see the AST at any time using the output format yaml on the command line

mau -f yaml -i input.mau -o -

Templates

Once the AST has been created, the chosen visitor is used to render each node. In this case the nodes are of type text, sentence, style, paragraph, and document.

The style node in the previous AST is

- data:
    type: style
    value: star
    content:
    - data:
        type: text
        value: important

And the visitor called JinjaVisitor will identify certain templates based on the properties of the node.

For the text node the template will be text, while for the style node the template will be style.star.

However, as we want to generate a specific type of output, for example HTML, we will select a more specialised visitor that selects the templates using a custom extension. In this case the visitor is HtmlVisitor and the templates are text.html and style.star.html

text.html
{{ value }}
style.star.html
<strong>{{ content }}</strong>

The output of the text node will then be

HTML output
important

and the output of the style node will then be

HTML output
<strong>important</strong>.

as {{ content }} is the rendering of all nodes contained in the style node.

If we changed the style template to

style.star.html
<span class="italic">{{ content }}</span>

the result would be

HTML output
<span class="italic">important</span>

Jinja

Currently, the hierarchy of visitors is the following

Mau visitors
           BaseVisitor
               ^
               |
               |
          JinjaVisitor
               ^
               |
               |
    +----------+--------+
    |                   |
    |                   |
HtmlVisitor         TexVisitor

BaseVisitor is used to produce the YAML representation of the AST, while JinjaVisitor augments it with a list of plugin names for each node, loads them, and calls the Jinja templating engine to transform them into text.

HtmlVisitor and TexVisitor are provided as plugins and build on top of what JinjaVisitor does, adding some specific features connected with the output format. For example, HtmlVisitor processes source code blocks using Pygments.

Loading visitors from plugins means that it's pretty easy to add a new templating engine or to add other formats on top of JinjaVisitor

Mau visitors
           BaseVisitor
               ^
               |
               +-------------------------+
               |                         |
          JinjaVisitor        TemplatingEngineVisitor
               ^
               |
               |
    +----------+--------+-------------------+
    |                   |                   |
    |                   |                   |
HtmlVisitor         TexVisitor      OtherFormatVisitor

How to define templates

Mau templates can be provided in the YAML configuration or as individual files.

YAML Configuration file

Mau templates can be defined in the YAML configuration file using the key custom_templates. For example

---
target_format: html
custom_templates:
  style.underscore.html: '<span class="bold">{{ content }}</span>'
  style.star.html: '<span class="italic">{{ content }}</span>'

This is a good solution for simple templates, but it might quickly become unmanageable if your templates include a lot of Jinja operators.

Individual files

You can store templates in individual files inside a directory and pass the latter to Mau through the configuration file with the key mau.visitor.templates_directory.

---
mau:
  visitor:
    templates_directory: templates

The file has to be named after the template and have an extension matching the output format. This is a good solution for complex templates, as it doesn't require to quote the text. You can also benefit from syntax highlighting in your editor while writing the template.

Template files can be created with a flat or nested structure. Each file can be created with its full name, so you can have

templates/
  header.html
  source.html
  source.python.html
  source.javascript.html
  style.star.html
  style.underscore.html

or you can use each part of the dotted name as a subdirectory

templates/
  header.html
  source.html
  source/
    python.html
    javascript.html
  style/
    star.html
    underscore.html

This is true at individual level, so you can mix the two styles

templates/
  header.html
  source.html
  source.python.html
  source/
    javascript.html
  style/
    star.html
    underscore.html

Install visitor plugins

The two classes HtmlVisitor and TexVisitor are provided by plugins. They can be installed in any virtual environment using pip

pip install mau-html-visitor
pip install mau-tex-visitor

The two plugins provide default templates for their output format. You can see them in the relative repositories

Template plugins

Mau supports plugins that only add templates, such as mau-docs-templates (link). Such plugins provide only template files, without a specific visitor.

The templates provided by the plugin can be used directly as they are loaded by visitors, or can be included in your own templates using Jinja extend or include.