Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
version: 2

build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.10"
python: "3.13"

python:
install:
Expand Down
103 changes: 96 additions & 7 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,38 @@ See <inv:markdown_it#using>

## mdit-py-plugins package

The [`mdit_py_plugins`](https://github.com/executablebooks/mdit-py-plugins), contains a number of common plugins.
They can be chained and loaded *via*:
The [`mdit_py_plugins`](https://github.com/executablebooks/mdit-py-plugins) package contains a number of common plugins.
Each plugin is a function in its own submodule (for example `mdit_py_plugins.footnote.footnote_plugin`),
so import it from there; the top-level package does not re-export them.

Load a plugin with `MarkdownIt.use`, passing any options as keyword arguments.
`use` returns the `MarkdownIt` instance, so the calls can be chained:

```python
from markdown_it import MarkdownIt
from mdit_py_plugins import plugin1, plugin2
md = MarkdownIt().use(plugin1, keyword=value).use(plugin2, keyword=value)
html_string = md.render("some *Markdown*")
from mdit_py_plugins.footnote import footnote_plugin
from mdit_py_plugins.front_matter import front_matter_plugin
from mdit_py_plugins.tasklists import tasklists_plugin

md = (
MarkdownIt("commonmark")
.use(front_matter_plugin)
.use(footnote_plugin)
.use(tasklists_plugin, enabled=True)
)
text = """\
---
title: Example
---
- [x] Some *Markdown*[^1]

[^1]: A footnote.
"""
html_string = md.render(text)
```

The options of each plugin are listed in its section below.

## Front-Matter

```{eval-rst}
Expand Down Expand Up @@ -118,13 +140,80 @@ html_string = md.render("some *Markdown*")
```

```{eval-rst}
.. autofunction:: mdit_py_plugins.dollarmath.dollarmath_plugin
.. autofunction:: mdit_py_plugins.amsmath.amsmath_plugin
```

```{eval-rst}
.. autofunction:: mdit_py_plugins.amsmath.amsmath_plugin
.. autofunction:: mdit_py_plugins.dollarmath.dollarmath_plugin
```

### Rendering dollarmath output

`dollarmath_plugin` does not typeset math: it wraps each piece of math in an HTML element, listed above.
The tag says how to display the math, and the class says where it was written.
So inline `$$x$$` (with `double_inline=True`) becomes `<div class="math inline">`:
display math written inside a paragraph.
Pick the display mode from the tag (`div` or `span`), not from the class.

There are two common ways to typeset the output.

**Add delimiters on the server, with `renderer=`.**
The `renderer` function receives the math content and `{"display_mode": bool}`,
and returns the HTML to put inside the element.
Wrapping the content in `\(...\)` or `\[...\]` lets MathJax (with its default configuration)
or KaTeX's auto-render extension find it in the page:

```python
from markdown_it import MarkdownIt
from markdown_it.common.utils import escapeHtml
from mdit_py_plugins.dollarmath import dollarmath_plugin


def render_tex(content: str, options: dict) -> str:
content = escapeHtml(content)
if options["display_mode"]:
return rf"\[{content}\]"
return rf"\({content}\)"


md = MarkdownIt().use(dollarmath_plugin, double_inline=True, renderer=render_tex)
html_string = md.render("Inline $a<b$ and $$x^2$$ in a paragraph.")
```

which gives:

```html
<p>Inline <span class="math inline">\(a&lt;b\)</span> and <div class="math inline">\[x^2\]</div> in a paragraph.</p>
```

A browser closes the `<p>` before the `<div>`, so in the page the text after inline `$$...$$`
falls outside the paragraph: allow for that when styling or selecting this output.

The returned string is inserted as is, so escape the content, as above, unless it comes from a trusted source
(the default renderer escapes it for you).
The same function can instead return fully typeset output, such as MathML from a converter library.

**Typeset the elements in the browser.**
Without a `renderer`, each element holds the escaped LaTeX source,
and a script can typeset the elements in place, for example with KaTeX:

```javascript
for (const el of document.querySelectorAll("span.math, div.math")) {
// a labelled block starts with its permalink anchor: keep it out of the math
const label = el.querySelector(".mathlabel");
if (label) label.remove();
katex.render(el.textContent.trim(), el, {
displayMode: el.tagName === "DIV",
throwOnError: false,
});
if (label) el.prepend(label);
}
```

To change the label anchor, pass `label_renderer=`.
To change the tags or classes themselves, replace the render rule for a token type
with `md.add_render_rule` after loading the plugin.

## Subscripts

```{eval-rst}
Expand Down
21 changes: 20 additions & 1 deletion mdit_py_plugins/dollarmath/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,28 @@ def dollarmath_plugin(
:param label_normalizer: Function to normalize the label,
by default replaces whitespace with `-`
:param renderer: Function to render content: `(str, {"display_mode": bool}) -> str`,
by default escapes HTML
by default escapes HTML.
Its return value is placed inside the element as is,
so a custom renderer is responsible for escaping it (the default renderer does).
:param label_renderer: Function to render labels, by default creates anchor

The plugin does not typeset the math.
Each token becomes an HTML element holding the rendered content,
and typesetting is left to a library such as MathJax or KaTeX:

- ``math_inline`` (``$a$``):
``<span class="math inline">``, with ``display_mode=False``
- ``math_inline_double`` (``$$a$$`` inside a paragraph, with ``double_inline``):
``<div class="math inline">``, with ``display_mode=True``
- ``math_block`` (``$$a$$`` on its own lines):
``<div class="math block">``, with ``display_mode=True``
- ``math_block_label`` (``$$a$$ (eq1)``):
``<div id="eq1" class="math block">``, starting with the label anchor,
with ``display_mode=True``

The tag says how to display the math (``div`` for display, ``span`` for inline),
and the class says where it was written (``inline`` inside a paragraph,
``block`` on its own lines), as in executablebooks/markdown-it-dollarmath.
"""
if label_normalizer is None:
label_normalizer = lambda label: re.sub(r"\s+", "-", label) # noqa: E731
Expand Down
Loading