Directives¶
Use directive syntax and directive renderers to add structured Markdown extensions.
Directives are parsed by rules and rendered by optional renderer plugins. These are separate steps:
Enable directive syntax rules so the parser creates directive nodes.
Register directive renderers when you want special HTML output.
Without a matching HTML directive renderer, Wenmode falls back to rendering the directive children.
Two directive families¶
Wenmode supports two related directive syntax families.
The first family is TextDirective, LeafDirective, and ContainerDirective.
These follow the mdast directive model used by
mdast-util-directive
and remark directives: one colon for text directives, two colons for leaf block
directives, and three or more colons for container block directives. They create
mdast-compatible textDirective, leafDirective, and containerDirective
nodes.
The second family is FencedDirective and Role. These follow the
MyST Parser roles and directives syntax:
fenced directives use code-fence syntax with {name}, and roles use
{name}`content`. Wenmode maps them onto the same AST node types:
FencedDirective creates containerDirective, and Role creates
textDirective.
mdast-style directives¶
from wenmode import Parser
from wenmode.rules import ContainerDirective, LeafDirective, TextDirective
parser = Parser([
TextDirective,
LeafDirective,
ContainerDirective,
])
Text directives are inline:
:abbr[HTML]{title="HyperText Markup Language"}
Leaf directives are block directives without body content:
::toc[On this page]{min=2 max=3}
Container directives hold Markdown content:
:::note[Important]
Read this first.
:::
All three rules use mdast-compatible node names:
TextDirectivecreatestextDirective.LeafDirectivecreatesleafDirective.ContainerDirectivecreatescontainerDirective.
Directive attributes¶
Directive heads can include labels and attributes. Attribute shortcuts map
#id to id and .class to class.
:::note[Title]{#intro .wide data-kind=guide}
Body.
:::
Parsed directive nodes store the directive name, optional attributes, and child
nodes. Container directive labels are stored as the first paragraph child with
data={"directiveLabel": True}.
MyST-style directives and roles¶
Fenced directives use code-fence-style syntax and serialize back to container
directives with MarkdownRenderer.
from wenmode import Parser
from wenmode.rules import FencedDirective, Role
parser = Parser([FencedDirective, Role])
```{note} Important
:class: warning
Read this first.
```
Roles are inline:
{iconify}`devicon:pypi`
FencedDirective creates a containerDirective node. Its first-line argument
becomes the directive label, and :key: value option lines become attributes.
Role creates a textDirective node. The role name becomes the directive
name, and the backtick content becomes children.
HTML directive renderers¶
Register HTML directive renderers on Wenmode or pass them to HTMLRenderer.
from wenmode import Wenmode
from wenmode.directives import Admonition
from wenmode.rules import ContainerDirective
wenmode = Wenmode([ContainerDirective])
wenmode.register_directive_renderer(Admonition())
text = '''
:::note[Title]
Body.
:::
'''
html = wenmode.render(text)
register_directive_renderer() requires an HTMLRenderer, because directive
renderers produce HTML.
You can also pass directive renderers at construction time:
from wenmode import Wenmode
from wenmode.directives import Abbreviation, Admonition, Details, Figure, TableOfContents
from wenmode.rules import AtxHeading, ContainerDirective, LeafDirective
wenmode = Wenmode(
[AtxHeading(id_transform=True), LeafDirective, ContainerDirective],
directives=[Abbreviation(), Admonition(), Details(), Figure(), TableOfContents()],
)
Built-in directive renderers¶
Abbreviation¶
Abbreviation renders text directives named abbr with a title attribute as
<abbr> elements.
from wenmode.directives import Abbreviation
Abbreviation()
:abbr[HTML]{title="HyperText Markup Language"}
Admonition¶
Admonition renders container directives such as note, tip, caution, and
danger as <aside> elements with admonition classes.
from wenmode.directives import Admonition
Admonition()
Admonition(names=['warning', 'important'])
Details¶
Details renders details container directives as native HTML
<details> elements. The directive label becomes a <summary>.
from wenmode.directives import Details
Details()
:::details[Advanced options]{open}
Hidden content.
:::
Figure¶
Figure renders figure container directives as <figure> with an optional
<figcaption> from the directive label.
TableOfContents¶
TableOfContents renders a toc leaf directive from heading IDs already
present in the parsed tree. Use heading rules with id_transform=True when you
want Wenmode to create those heading IDs.
from wenmode import HTMLRenderer, Parser
from wenmode.directives import TableOfContents
from wenmode.rules import AtxHeading, LeafDirective
parser = Parser([AtxHeading(id_transform=True), LeafDirective])
text = '''
::toc{min=2 max=3}
# Title
## Usage
'''
root = parser.parse(text)
html = HTMLRenderer(directives=[TableOfContents()]).render(root)
You can also collect and render a table of contents manually from the AST.
from wenmode import HTMLRenderer, Parser
from wenmode.headings import Slugger, add_heading_ids
from wenmode.presets import commonmark
from wenmode.toc import collect_toc, render_toc_html
markdown = '''# Title
## Usage
### Options
### Example
'''
root = Parser(commonmark).parse(markdown)
add_heading_ids(root, slugger=Slugger(), min_depth=2)
toc = collect_toc(root, min_depth=2, max_depth=3)
html = render_toc_html(toc) + HTMLRenderer().render(root)