Plugins¶
Enable non-standard Markdown syntax with explicit Wenmode plugins.
Plugins are feature modules that install parser rules and renderer handlers together. Use them when syntax creates nodes outside the CommonMark, GFM, or mdast directive surface.
Most applications use plugins in addition to a preset:
from wenmode import Wenmode
from wenmode.presets import github
from wenmode.plugins import math
wenmode = Wenmode(github, plugins=[math])
Use a plugin when you want a complete feature. Use individual rules when you are deliberately building a small dialect and already know which parser behavior you need.
Using Plugins¶
Import a plugin module from wenmode.plugins and pass it to Wenmode with the
plugins argument. During initialization, Wenmode calls each plugin’s
setup(wenmode, **options) function with no extra options.
from wenmode import Wenmode
from wenmode.plugins import math
wenmode = Wenmode(plugins=[math])
assert wenmode.render('Inline $x + y$.\n') == (
'<p>Inline <span class="math math-inline">x + y</span>.</p>\n'
)
Install multiple plugins by listing them:
from wenmode import Wenmode
from wenmode.plugins import mark, superscript
wenmode = Wenmode(plugins=[mark, superscript])
Some plugins accept setup options. For example, math can install only inline
or block syntax. Install those plugins with use() when you need to pass
options:
from wenmode import Wenmode
from wenmode.plugins import math
inline_math = Wenmode().use(math, block=False)
block_math = Wenmode().use(math, inline=False)
Use Wenmode.use(plugin, **options) when you need to install a plugin after the
instance already exists. It returns the same Wenmode instance, so existing
chain-style setup remains supported.
Built-In Plugins¶
Plugin |
Enables |
|---|---|
|
Abbreviation definitions and |
|
Definition list syntax and nodes |
|
MyST-style fenced directives, rendered as |
|
Top-level |
|
MyST-style inline roles, rendered as |
|
|
|
|
|
Display and inline math nodes |
|
Ruby annotation nodes |
|
Block and inline spoiler nodes |
|
|
|
|
Each plugin also registers default HTML, Markdown, or RST renderer handlers when the feature has a standard representation in Wenmode’s built-in renderers.
Front Matter¶
The frontmatter plugin consumes top-level --- front matter before normal
Markdown block parsing and stores the parsed value on the root node. It does not
emit a child node. HTML output ignores front matter by default, Markdown output
serializes it back to a --- block, and RST output renders flat metadata as a
docinfo field list.
from wenmode import MarkdownRenderer, RSTRenderer, Wenmode
from wenmode.plugins import frontmatter
source = '---\ntitle: Hello\n---\n\n# Hi\n'
html = Wenmode(plugins=[frontmatter])
root = html.parse(source)
assert root.data == {'frontmatter': {'title': 'Hello'}}
assert html.render_node(root) == '<h1>Hi</h1>\n'
markdown = Wenmode(renderer=MarkdownRenderer(), plugins=[frontmatter])
assert markdown.render(source) == source
rst = Wenmode(renderer=RSTRenderer(), plugins=[frontmatter])
assert rst.render(source) == ':title: Hello\n\nHi\n==\n'
The default loader and dumper handle simple scalar key: value lines. Pass
custom callbacks when your application wants YAML or another metadata format.
The load callback receives only the text between the opening and closing
fences:
from wenmode import Wenmode
from wenmode.plugins import frontmatter
def load_meta(source: str) -> dict[str, str]:
return {'raw': source}
def dump_meta(value: object) -> str | None:
if not isinstance(value, dict):
return None
return str(value['raw'])
wenmode = Wenmode().use(frontmatter, load=load_meta, dump=dump_meta, data_key='meta')
Fenced Directives And Roles¶
The fenced_directive and inline_role plugins provide MyST-style directive
syntax. Inline roles map onto textDirective, one of the mdast-compatible
directive nodes documented in Directives. Fenced directives usually
create containerDirective nodes, and literal-body directives such as
code-block create literalDirective nodes.
from wenmode import Wenmode
from wenmode.plugins import fenced_directive, inline_role
wenmode = Wenmode(plugins=[fenced_directive, inline_role])
Fenced directives use code-fence-style syntax:
```{note} Important
:class: warning
Read this first.
```
The fenced directive plugin creates a containerDirective node by default. Its
first-line argument becomes the directive label, :key: value option lines
become attributes, and body content is parsed as Markdown.
Literal-body directives create literalDirective nodes so their body is kept as
source text instead of being parsed as Markdown. By default this applies to
code-block:
```{code-block} python
:caption: example.py
print("*not emphasis*")
```
Pass literal_names to use() when your application needs a different set.
Pass fence when your dialect also accepts other repeated fence characters,
such as MyST colon fences:
from wenmode import Wenmode
from wenmode.plugins import fenced_directive
wenmode = Wenmode().use(
fenced_directive,
literal_names={'code-block', 'sourcecode'},
fence=('`', '~', ':'),
)
Inline roles use MyST-style role syntax:
{iconify}`devicon:pypi`
The inline role plugin creates a textDirective node. The role name becomes the
directive name, and the backtick content becomes children.
After these plugins create directive nodes, custom HTML output is still handled
through directive renderers registered by node type and directive name. Without
a matching renderer, text, leaf, and container directives fall back to their
child content. Literal directives fall back to escaped literal text, and
code-block has default code-block output in the HTML renderer.
Use these plugins when you want MyST-style syntax. Use the core
TextDirective, LeafDirective, and ContainerDirective rules when you want
mdast directive syntax with colon markers.
Creating Plugins¶
A custom plugin is a module or object with a setup(wenmode, **options)
function. Inside setup(), register parser rules, renderer handlers, directive
renderers, or any combination of them.
from wenmode import Wenmode
from wenmode.rules import Emphasis
class MyPlugin:
def setup(self, wenmode: Wenmode, **options) -> None:
wenmode.register_rule(Emphasis)
wenmode = Wenmode([], plugins=[MyPlugin()])
For non-trivial syntax, define the node, rule, render handlers, and setup()
together. See Custom Plugins for a complete custom plugin walkthrough.