Plugins
Plugins automate and simplify typical tasks and make the documentation more structural and easy to use.
The main approach used by this program is no interference in the Markdown syntax. So the documentation content must be readable in plain text even without processing by this program. Plugins provide extra possibilities for the templates processing and visualization.
See here for an example of how plugins are defined in the argument file.
Motivation
The program generates static HTML pages that reference other pages and resources like CSS and pictures. The generated HTML pages may be located in different places of the project structure, so the same resources must be referenced differently from different pages.
In the following example:
$ tree -L 2 --charset=ascii --dirsfirst
.
|-- doc
| |-- about.html
| `-- styles.css
|-- pict
| `-- logo.png
`-- readme.html
the reference to styles.css
is:
doc/styles.css
from the readme.html
page;styles.css
from the about.html
page.This plugin automatically recalculates relative paths for certain pages depending on their location and avoids manual definition of these paths for every page individually. It also allows substitution of such paths inside the documents.
Definition
Here's an example of the plugin definition:
{
"documents": [
{ "input": "readme.txt", "output": "readme.html", "title": "Home" },
{ "input": "doc_src/about.txt", "output": "doc/about.html", "title": "About" }
],
"plugins": {
"relative-paths": {
"markers": ["path"],
"paths": {
"resource_path": "doc/",
"pict": "doc/pict/"
}
}
}
}
This is the new syntax. The previous syntax (that doesn't support substitution inside documents) is also supported:
"relative-paths": { "resource_path": "doc/" }
In this example, resource_path
and pict
are path codes, and the corresponding values are
paths themselves.
The plugin considers the paths and the current page location being relative to the
same location, that is the program invocation current directory in this case. When it
calculates the path with the code resource_path
then:
readme.html
, it'll return doc/
;doc/about.html
it'll return ""
(empty path, as they are located in the same
directory).Usage
Include the following tag to the template:
<link rel="stylesheet" type="text/css" href="{{resource_path}}styles.css"/>
That's it. When a document using this template is generated, this tag will be replaced with the desired path.
For substitution inside a document insert the text like this:

After the page is generated this fragment will look like this:
For page readme.html |
For page doc/about.html |
---|---|
 |
 |
Motivation
Sidebar provides quick access to different project pages. It's often very helpful to put a sequence of pages that are intended to be read in order. Doing it manually is pretty cumbersome and error-prone.
This plugin defines such pages sequences and and provides them for easy manipulation in templates.
Definition
Note
You may want to also look at the new syntax described here.
In the "plugins"
sections:
{
"documents": [
{ "input": "page1.txt", "output": "page1.html", "title": "Page 1" },
{ "input": "page2.txt", "output": "doc/page2.html", "title": "Page 2" },
{ "input": "page3.txt", "output": "doc/page3.html", "title": "Page 3" }
],
"plugins": {
"page-flows": {
"sidebar": [
{ "link": "page1.html", "title": "Page 1" },
{ "link": "doc/page2.html", "title": "Page 2", "class": "align_right" },
{ "link": "doc/page3.html", "title": "Page 3", "highlight": true },
{ "link": "www.google.com", "title": "Search", "external": true }
]
}
}
}
Here we see the page flow sidebar
that contains four link definitions. Each link definition
has main attributes link
, title
, external
. Also other arbitrary attributes (like class
and highlight
) may be added and then used in the templates (will be discussed below).
In the above example the three pages are defined twice. To avoid such repetition the page flows
may be defined directly in the "documents"
section:
{
"documents": [
{ "input": "page1.txt", "title": "Page 1", "page-flows": ["sidebar"] },
{ "input": "page2.txt", "title": "Page 2", "page-flows": ["sidebar"] },
{ "input": "page3.txt", "title": "Page 3", "page-flows": ["sidebar"] }
],
"plugins": {
"page-flows": {}
}
}
But the plugin itself must be activated to make it work. So even if all page flows are defined
in the "documents"
section the plugin empty definition must be added to the "plugins"
section.
The "page-flows"
document definition may be carried out to the "default"
section (not
demonstrated here). Several page flows may be defined and a single page may be a part of several
page flows.
Usage
In a template, each page flow is accessible by its name (sidebar
in this example) and
provides the following structured data:
Field | Description |
---|---|
{{sidebar}} |
Iterable, returns pages |
{{sidebar.previous}} |
Previous page if exists |
{{sidebar.current}} |
Current page if exists |
{{sidebar.next}} |
Next page if exists |
{{sidebar.has_navigation}} |
Boolean, true if ether previous or next page exist |
{{sidebar.not_empty}} |
Boolean, true if contains at least one page |
The page has the following structure:
Field | Description |
---|---|
{{link}} |
The link that references the page. Recalculated for the current page |
{{title}} |
The title of the page |
{{external}} |
Boolean, external pages can never be current |
{{first}} |
Boolean, true if this is the first page in the sequence |
{{last}} |
Boolean, true if this is the last page in the sequence |
{{class}} |
Example of a custom arbitrary attribute |
This data is calculated for every page that uses this template. So for the current page we can know the previous and the next pages and render the navigations. Here's a simple example:
{{#sidebar.previous}}<a href="{{link}}">[PREVIOUS]</a>{{/sidebar.previous}}
{{#sidebar.next}}<a href="{{link}}">[NEXT]</a>{{/sidebar.next}}
Explanation
{{#sidebar.previous}}...{{/sidebar.previous}}
means that if sidebar.previous
value
exists then the enclosed content is rendered. sidebar.previous
value is a page and has
attribute link
that is used in the rendered block.
Also for the current page we have the whole page sequence of the page flow and can render this list in the sidebar. As we know which page or pages are current, we can highlight this links. Here's a simplified example of how the sidebar items may be rendered:
<ul>{{#sidebar}}
<li><a class="sidebarItem{{#current}} selected{{/current}}" href="{{link}}">{{title}}</a></li>
{{/sidebar}}</ul>
Explanation
{{#sidebar}}...{{/sidebar}}
means that for each item in the sidebar
value (that is
iterable) render the enclosed content. The items are pages and their attributes link
,
title
and current
are used in the rendered block.
This documentation demonstrates pretty typical usage of this plugin. Also see the template
doc_src/templates/multipage.html
and the argument file md2html_args.json
for more
understanding of correspondence between the plugin's definition and usage.
In version 1.0.3 new syntax was introduced. The following example demonstrates the differences:
. . .
"plugins": {
"page-flows": {
"sections": { "groups": ["sidebar"] },
"header": [
{ "link": "readme.html", "title": "Home" },
{ "link": "doc/content/sections/installation.html", "title": "Installation" },
{ "link": "doc/content/sections/usage.html", "title": "Usage" }
],
"useful_links": { "title": "Useful links", "groups": ["sidebar"], "items": [
{ "link": "https://mustache.github.io/", "title": "Mustache", "external": true },
{ "link": "https://json.org/", "title": "JSON", "external": true }
]}
},
}
. . .
The useful_links
page flow is defined using the full syntax. The page flow has a title, a list
of groups and the content defined by the items
attributes. The content definition is a list of
the pages just the same way as in the old syntax.
The sections
page flow defines only the necessary attributes. The title is an empty string by
default. The content is empty initially and it may be defined in the documents
section.
The header
page flow uses the old syntax. Two syntaxes may be used in the same argument file
that makes the previously written documentation compatible with the new version of the program.
The purpose of this change is to remove specific elements from the templates and to avoid boilerplates. Now sidebar page flows may be defined solely in the argument file and the template file in the documentation project may be updated with the other one taken from the outside without subsequent customization. Here's a sidebar block that may be defined for the above argument file fragment:
{{#sidebar}}
{{#title}}<h3>{{.}}</h3>{{/title}}
{{#.}}<a class="sidebar_item{{#current}} selected{{/current}}" href="{{link}}">{{title}}</a>
{{/.}}
{{/sidebar}}
The sidebar
variable contains a list of page flows for which it's defined (here there are
two such page flows). As each page flow now has a title then this title may be conditionally
rendered using the Mustache syntax. Elements {{#.}}
and {{/.}}
represent a current
page flow that here is represented as a number of links. Current links are highlighted
with the selected
CSS class.
Motivation
This plugin extracts variables from document source texts and provides these variables to be used in the template.
Definition
"plugins": {
"page-variables": {"variables": {"only-at-page-start": true} }
}
This means that variables will be extracted from the page metadata blocks with marker
variables
and only from those blocks that are the first non-blank text on the page.
This is the definition of the default marker so it may be simplified to "page-variables": {}
,
and this is the recommended form.
Usage
For the above plugin definition the metadata blocks may look like:
<!--variables {"title": "My page", "noPageTitle": true}-->
The marker is variables
and it is case insensitive. The variables are title
and noPageTitle
and the tags {{title}}
and {{noPageTitle}}
will be replaced with the defined values when
this page is processed.
The page metadata blocks will be removed from the source text if they are recognized and processed by the defined markers.
The metadata content must be a valid JSON [json].
Note
Opening <!--
and closing markers -->
must not be used inside the metadata
section. Also consecutive hyphens --
inside HTML comments may probably be a problem in some
browsers. In JSON strings, Unicode entities may be used to resolve these issues, i.e. string
"<!\u002D-text-\u002D>"
will be interpreted as "<!--text-->"
. Still, depending on the
page content and the context, opening and closing markers, even when escaped in JSON, may
cause unexpected result. Check it first if you really need to use these symbols.
Motivation
This plugin defines variables that are not bound to certain pages. Actually such values may be included directly into the template with no need of using this plugin. But when the same template is used by several projects it may be convenient to define some template variable parts that different projects may substitute using their argument files.
Definition
"variables": {"logo": "<img src=\"logo.png\" />" }
Usage
Tag (or tags) {{{logo}}}
in the template will be substituted in the template. (Note that in
this case three pairs of curly braces are used to avoid HTML-escaping on substitution.)
Motivation
Some terms, abbreviations and other kind of keywords may be defined, described and mentioned in different pages within the documentation. Searching such keywords may be hard, especially if the documentation is large. This plugin allows marking such points on the pages as index entries and then collects these entries and put them together on a separate index page. See the index page of this documentation as an example.
Definition
"plugins": {
"index": {"index": {"output": "index_page.html", "title": "Index", "index-cache": "index_cache.json",
"index-cache-relative": true, "letters": true, "letters-block": true }
}
}
This example defines one index with marker index
. It's possible to define several indexes with
different markers.
All possible properties are listed in the table below. They are mostly the same as those
of the documents
section so see that section for the
absent descriptions.
Name | Type | Required | Default | Description |
---|---|---|---|---|
output-root | string | No | ||
output | string | Yes | Index page that must be created: absolute or relative to the output-root property value |
|
title | string | No | ||
template | string | No | ||
link-css | array of string | No | ||
include-css | array of string | No | ||
no-css | boolean | No | ||
add-link-css | array of string | No | ||
add-include-css | array of string | No | ||
page-flows | array of string | No | ||
add-page-flows | array of string | No | ||
verbose | boolean | No | ||
report | boolean | No | ||
index-cache | string | Yes | Index cache file (see the note below) | |
index-cache-relative | boolean | No | false | true means that the index cache file location is defined relative to the index page location |
letters | boolean | No | false | true means that the index page content will be divided by the terms first letters |
letters-block | boolean | No | false | true means that all terms first letters will be listed at the top of the index page |
Index cache file
Index page is generated using the entries from all the documents but the program may regenerate the documentation project partially, i.e. it may regenerate only those documents that were changed or added since the previous program run. In order to always generate a complete index page the program uses an index cache file that keeps the collected index entries between the runs.
In some cases a forceful full regeneration (with -f
flag or "force": true
option,
see here for more details) is required, for example, if the "index" plugin is
activated on an existing project or if the index cache file is deleted.
Index cache file is a generated artifact so in case of any problem it may be manually deleted and the further forceful full documents regeneration may resolve the problem.
Usage
Index entries may be added in two different ways:
<!--index Term 2 -->
;<!--INDEX ["term 1", "term 3"]-->
.The index
marker is case-insensitive. If the above two entries are added then the index page
will be generated with terms "term 1", "Term 2" and "term 3" in the sorted order.
In the index page, the term list will be included into a <div class="index-content">
element.
The term first letter delimiters will look like this:
<p class="index-letter" id="index_letter_A">A</p>
The terms themselves will look like this:
<p class="index-entry"><a href="usage.html#index_entry_1" title="Usage">argument file</a></p>
The first letter link block will look like this:
<p class="index_letters">
<a href="#index_letter_A">A</a>
<a href="#index_letter_C">C</a>
. . .
</p>
The above information allows define desirable styling with CSS.
Motivation
HTML pages inside documentation usually reference each other using links. A link specifies its target relative to the page where it's placed. When the target page is moved or renamed the link need to be modified accordingly, otherwise it won't work. And what's worse, all pages that reference the relocated page need to be found and modified. This plugin automatically calculates link target pages location thus eliminating the need of specifying them manually.
Definition
To make this plugin work the target document must have a code
. Here is an example of an argument
file that uses this plugin:
{
"documents": [
{ "input": "page1.txt", "code": "p1" },
{ "input": "subdir/page2.txt", "code-from-variable": "code" }
],
"plugins": {
"page-variables": {},
"page-links": { "markers": ["page"] }
}
}
The first page has a code p1
specified in the document definition. The second page has a code
(let's say p2
) specified in the page metadata (see the
"page-variables" plugin), variable code
. If page metadata is used
then "page-variables" plugin must be activated.
Marker page
is defined in the "page-links" plugin. There may be several markers.
Usage
On the page page1.txt
the following link to the page subdir/page2.txt
may be added:
[](<!--page p2-->#some_anchor)
and the plugin will convert it to
[](subdir/page2.html#some_anchor)
. Consequently link [](<!--page p1-->)
on the second page will
become [](../page1.html)
.
Attention
-f
flag or "force": true
option, see here for more details).code
will invalidate all links that reference this page by its code
.Motivation
Different plugins fulfill page metadata substitution. But sometimes it's required to show a metadata block without substitutions. To achieve that, there are methods that use direct HTML inclusions and masking, but they are quite tedious and cumbersome. This plugin gives an easy way of doing that.
Definition
Here is an example of an argument file that uses this plugin:
{
"documents": [
{ "input": "page1.txt" }
],
"plugins": {
"ignore": { "markers": ["ignore"] }
}
}
The example shows the default marker usage, so the other, and recommended, way is the following
definition: "ignore": { }
. There may be several markers if required.
Usage
Let's consider two different code blocks:

and

In the first block the source text is 
and substitution
is fulfilled, while in the second block the source text is

so substitution is omitted.
Motivation
Pages may contain links to source code files like Java (*.java), Python (*.py), XML (*.xml), and so on. When viewing such pages locally (as HTML files) the linked files are often opened by browsers as text. When the page is published and is viewed by URL, the browsers will often offer downloading the linked files that's very inconvenient and significantly slows down the documentation usage.
The "wrap-code" plugin wraps source code files into HTML pages and provides links to these wrapping pages.
Definition
The plugin definition may look like this:
"plugins": {
. . .
"wrap-code": {
"wrap_java": {"style": "code", "input-root": "projects/", "output-root": "doc/code",
"template": "doc_src/templates/code.html", "variables": {"noPageTitle": true}},
"wrap_xml": {"style": "xml", "input-root": "projects/", "output-root": "doc/code",
"template": "doc_src/templates/code.html", "variables": {"noPageTitle": true}}
}
. . .
}
In this example wrap_java
and wrap_xml
are markers to be used in the placeholders (see below).
The markers define the wrapping HTML page generation options: where to take the source code files,
where to place the wrapping HTML pages, which rendering style and template to use.
Note
The style
parameter may be defined directly per each page metadata, see below. So just one
wrap-code
definition may be used and customized directly in place.
All possible properties are listed in the table below. They are mostly the same as those
of the documents
section so see that section for the
absent descriptions.
Name | Type | Required | Default | Description |
---|---|---|---|---|
input-root | string | No | ||
output-root | string | No | ||
template | string | No | ||
link-css | array of string | No | ||
include-css | array of string | No | ||
no-css | boolean | No | ||
add-link-css | array of string | No | ||
add-include-css | array of string | No | ||
verbose | boolean | No | ||
report | boolean | No | ||
style | string | No | empty string | style, like code , shell , etc. |
variables | object | No | empty | additional variables to be used in the template |
Usage
Let's say there's the file projects/hello/Main.java
with some content. To link this file in
a source text, use something like this:
The main class is [here](<!--wrap_java hello/Main.java-->).
The alternative form is:
The main class is [here](<!--wrap_java {"file": "hello/Main.java", "style": "code"}-->).
As the result, the new file doc/code/hello/Main.java.html
will be generated based on the
following transformed content:
````code
<the file content here>
````
The source text will be transformed like this:
The main class is [here](../code/hello/Main.java.html).
An example may be viewed here. Also see the argument file
md2html_args.json
in this project.
The following additional variables may be used in the template:
Variable | Description |
---|---|
{{wrap_code_path}} |
Path to the wrapped file |
{{wrap_code_file_name}} |
The wrapped file name |
Note
The wrapping HTML file will be generated (or regenerated) only if the source text is processed.
To assure regeneration, use -f
flag or "force": true
option (see here
for more details).
Motivation
When writing and running program code, it may be desired to place some source code into the documentation. Just copy-pasting will require updating documentation each time the source code is changed. "wrap-code" plugin may help by generating a separate page for this code. But if the source text is small it may be better to show it directly in the text where it's described. This plugin does such kind of inclusion.
Definition
The plugin is defined the following way:
"plugins": {
. . .
"include-file": [
{ "markers": ["include_code"], "root-dir": "sample_code/", "trim": "all" },
{ "markers": ["include_text1", "include_text2"], "root-dir": "sample_text/",
"recursive": true, "start-with": "<body>", "end-with": "</body>",
"start-marker": "// INCLUDE FROM HERE", "end-marker": "// INCLUDE UP TO HERE" }
],
. . .
}
In this example:
include_code
is the marker to be used in the placeholders (see below);
There may be several markers;sample_code/
and sample_text/
define the places where to take the source code files;"trim": "all"
defines whether to trim leading and trailing white spaces (all
by default).
Other options are empty-lines
and none
;"recursive": true
(false
by default) means that if the included file content contains
metadata blocks, like <!--path pict-->
, then these metadata blocks will be
processed;start-with
and start-marker
parameters specify the text that will be the fragment start.
The start-with
text will be present in the included fragment while the start-marker
text will not be included. The first of these markers will be used. If ether of these
parameters are specified and they are not found in the file then nothing will be included;end-with
and end-marker
specify the text that will be the fragment end. If no text
defined by these parameters are found then the fragment will be to the end of the file.Usage
By adding the following content on the page:
````code
<!--include_code_part hello/Main.java-->
````
we will get the following output:
public class Main {
// method start
public static void main(String[] args) {
System.out.println("Hi!");
}
// method end
}
For a certain file, custom parameters may be defined the following way:
````code
<!--include_code_part {"file": "hello/Main.java", "start-marker": "// method start",
"end-marker": "// method end", "trim": "empty-lines"}-->
````
The result will look like this:
public static void main(String[] args) {
System.out.println("Hi!");
}
Motivation
This plugin makes replacements by template. It may be helpful for contracting long and recurring fragments. Probably, long and cumbersome HTML inclusions are the first fragments that may be addressed by this plugin.
Important
This plugin must be used with care. When used too much, it may become a replacement for the Markdown syntax, and that, in its turn, may significantly reduce the documents readability and compatibility in source text.
Definition
The plugin is defined the following way:
"plugins": {
. . .
"replace": [
{ "markers": ["red"], "replace-with": "<span style=\"color:red;\">${1}</span>" },
{ "markers": ["blue"], "replace-with": "<span style=\"color:blue;\">${1}</span>" },
{ "markers": ["pict"], "replace-with": "", "recursive": true }
],
. . .
}
In this example:
red
, blue
and pict
are the marker to be used in the placeholders (see below).
There may be several markers in one replacement definition;replace-with
attributes define the templates to be extended;${1}
, ${2}
, ${3}
, etc. are the placeholders that will be replaced in the template.
To add a dollar sign $
it must be doubled. So $${4}
will be interpreted as ${4}
.
There's a need for this doubling only if a dollar sign if followed by a curly brace.
So $3
will be taken literary as $3
;recursive
flag is set to true
then the resulting text (after the template is
extending) will be considered as containing metadata blocks. In the replacement definition
with marker pict
the fragment <!--path pict-->
will be processed and replaced if
the marker path
is defined.Usage
The content may be added the following ways:
<!--red some text -->
— using a string, only one value may be specified;<!--red ["some text ", "some other text"] -->
— using a list. Unused items will be
ignored.The output will be the same in both cases:
<span style="color:red;">some text </span>
This result may look like this: some text .
If there are not enough values provided for the template, the missing positions will be replaced with empty strings.