Plugins
Plugins allow you to write a server-side executed Python script that can modify or generate pages. The plugins are found in:
/services/http/kondo/plugins
If you use the following directive:
@plugin censor-bad-words
Then the following plugin will be loaded:
/services/http/kondo/plugins/censor-bad-words.py
The plugin name must only have unaccented latin letters, digits, and -
and _
.
A plugin is just a Python 3 script with a filter_markdown
function, which takes a single context
argument containing the Markdown body
. Plugins can modify the body
variable to change any part of the page:
import re
def filter_markdown(context):
context.body = re.sub(r"[Ee]macs", "VIM", context.body)
This plugin is actually running on this page, so I can tell you that the two best text editors are VIM and VIM. (I tried to be neutral in the editor holy war, but the plugin wouldn't let meācheck the source of /services/http/kondo/index.ucc
if you don't believe me!)
You can use multiple @plugin
directives, and each plugin will run in the order that the directives are listed in.
The properties and methods available on the context
are currently:
Property | Description |
---|---|
file_path |
The absolute file system path of the .ucc file being rendered. |
styles |
The list of styles added by the @style directive. You can manipulate this list to add plugin specific styles, which should be stored in /services/http/kondo/styles/for-plugins . |
get_data(path) |
Parses a YAML file given a path that is relative to the /data directory found in the web site root directory. Changes to this file will trigger hot reloading. |
render_string_template(data, template) |
Given a dictionary of variables data , and a Jinja2 template as a string in template , returns the rendered template. |
render_markdown(text) |
Renders Markdown into HTML. |
The plugin .py
file is reloaded each time a page is generated, and runs under a user that has the webmasters
group. While it doesn't get any input from remote browsers, other than in the path
variable, it still could in theory be poisoned by something in the .ucc
file, so be conservative about handling potentially tainted data.
Syntax Tree Plugins
Instead of a filter_markdown
function, a plugin can also implement a filter_ast
function (or both) that is given a context.body
that is the root of the Mistletoe Abstract Syntax Tree (AST). The root Document
node can be replaced, or the child nodes in the tree can be manipulated:
from mistletoe.block_tokens import Paragraph
from mistletoe.span_tokens import RawText
def filter_ast(context):
context.body.children.append(
Paragraph(children = [
RawText("This paragraph was added by a plugin.")
])
)
There is an existing plugin, dump-markdown-ast
, that converts the entire page into a listing of the AST notes. Since plugins are executed in the order they are defined in the page header, you can place this plugin before or after your plugin to test document manipulations.
Also, the above example plugin is running on this page:
This paragraph was added by a plugin.