(plugins)=
# Plugins
```{rst-class} lead
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:
```python
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.
```python
from wenmode import Wenmode
from wenmode.plugins import math
wenmode = Wenmode(plugins=[math])
assert wenmode.render('Inline $x + y$.\n') == (
'
Inline x + y.
\n'
)
```
Install multiple plugins by listing them:
```python
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:
```python
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 |
| --- | --- |
| `wenmode.plugins.abbr` | Abbreviation definitions and `abbreviation` nodes |
| `wenmode.plugins.definition_list` | Definition list syntax and nodes |
| `wenmode.plugins.fenced_directive` | MyST-style fenced directives, rendered as `containerDirective` or `literalDirective` nodes |
| `wenmode.plugins.frontmatter` | Top-level `---` front matter stored on `root.data["frontmatter"]` |
| `wenmode.plugins.inline_role` | MyST-style inline roles, rendered as `textDirective` nodes |
| `wenmode.plugins.insert` | `insert` inline nodes |
| `wenmode.plugins.mark` | `mark` inline nodes |
| `wenmode.plugins.math` | Display and inline math nodes |
| `wenmode.plugins.ruby` | Ruby annotation nodes |
| `wenmode.plugins.spoiler` | Block and inline spoiler nodes |
| `wenmode.plugins.subscript` | `subscript` inline nodes |
| `wenmode.plugins.superscript` | `superscript` inline 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.
```python
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) == 'Hi
\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:
```python
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 {ref}`directives`. Fenced directives usually
create `containerDirective` nodes, and literal-body directives such as
`code-block` create `literalDirective` nodes.
```python
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:
````markdown
```{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`:
````markdown
```{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:
```python
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:
```markdown
{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.
```python
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 {ref}`custom-plugins` for a complete custom plugin walkthrough.