diff --git a/mdit_py_plugins/dollarmath/index.py b/mdit_py_plugins/dollarmath/index.py
index 240bbba..5fe0381 100644
--- a/mdit_py_plugins/dollarmath/index.py
+++ b/mdit_py_plugins/dollarmath/index.py
@@ -1,18 +1,22 @@
import re
-from typing import Callable
+from typing import Any, Callable, Dict, Optional
from markdown_it import MarkdownIt
-from markdown_it.common.utils import isWhiteSpace
+from markdown_it.common.utils import escapeHtml, isWhiteSpace
from markdown_it.rules_block import StateBlock
from markdown_it.rules_inline import StateInline
def dollarmath_plugin(
md: MarkdownIt,
+ *,
allow_labels: bool = True,
allow_space: bool = True,
allow_digits: bool = True,
double_inline: bool = False,
+ label_normalizer: Optional[Callable[[str], str]] = None,
+ renderer: Optional[Callable[[str, Dict[str, Any]], str]] = None,
+ label_renderer: Optional[Callable[[str], str]] = None,
) -> None:
"""Plugin for parsing dollar enclosed math,
e.g. inline: ``$a=1$``, block: ``$$b=2$$``
@@ -27,39 +31,64 @@ def dollarmath_plugin(
before/after the opening/closing ``$``, e.g. ``1$`` or ``$2``.
This is useful when also using currency.
:param double_inline: Search for double-dollar math within inline contexts
+ :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
+ :param label_renderer: Function to render labels, by default creates anchor
"""
+ if label_normalizer is None:
+ label_normalizer = lambda label: re.sub(r"\s+", "-", label)
md.inline.ruler.before(
"escape",
"math_inline",
math_inline_dollar(allow_space, allow_digits, double_inline),
)
- md.add_render_rule("math_inline", render_math_inline)
+ md.block.ruler.before(
+ "fence", "math_block", math_block_dollar(allow_labels, label_normalizer)
+ )
- md.block.ruler.before("fence", "math_block", math_block_dollar(allow_labels))
- md.add_render_rule("math_block", render_math_block)
- md.add_render_rule("math_block_eqno", render_math_block_eqno)
+ # TODO the current render rules are really just for testing
+ # would be good to allow "proper" math rendering,
+ # e.g. https://github.com/roniemartinez/latex2mathml
+ if renderer is None:
+ _renderer = lambda content, _: escapeHtml(content)
+ else:
+ _renderer = renderer
-# TODO the current render rules are really just for testing
-# would be good to allow "proper" math rendering, e.g. https://github.com/roniemartinez/latex2mathml
+ if label_renderer is None:
+ _label_renderer = (
+ lambda label: f'¶' # noqa: E501
+ )
+ else:
+ _label_renderer = label_renderer
+ def render_math_inline(self, tokens, idx, options, env) -> str:
+ content = _renderer(str(tokens[idx].content).strip(), {"display_mode": False})
+ return f'{content}'
-def render_math_inline(self, tokens, idx, options, env) -> str:
- return "<{0}>{1}{0}>".format(
- "eqn" if tokens[idx].markup == "$$" else "eq", tokens[idx].content
- )
+ def render_math_inline_double(self, tokens, idx, options, env) -> str:
+ content = _renderer(str(tokens[idx].content).strip(), {"display_mode": True})
+ return f'
{content}
'
+ def render_math_block(self, tokens, idx, options, env) -> str:
+ content = _renderer(str(tokens[idx].content).strip(), {"display_mode": True})
+ return f'\n{content}\n
\n'
-def render_math_block(self, tokens, idx, options, env) -> str:
- return "\n".format(tokens[idx].content)
+ def render_math_block_label(self, tokens, idx, options, env) -> str:
+ content = _renderer(str(tokens[idx].content).strip(), {"display_mode": True})
+ _id = tokens[idx].info
+ label = _label_renderer(tokens[idx].info)
+ return f'\n{label}\n{content}\n
\n'
+ md.add_render_rule("math_inline", render_math_inline)
+ md.add_render_rule("math_inline_double", render_math_inline_double)
-def render_math_block_eqno(self, tokens, idx, options, env) -> str:
- return '\n'.format(
- tokens[idx].content, tokens[idx].info
- )
+ md.add_render_rule("math_block", render_math_block)
+ md.add_render_rule("math_block_label", render_math_block_label)
def is_escaped(state: StateInline, back_pos: int, mod: int = 0) -> bool:
@@ -146,7 +175,7 @@ def _math_inline_dollar(state: StateInline, silent: bool) -> bool:
# find closing $
pos = state.pos + 1 + (1 if is_double else 0)
found_closing = False
- while True:
+ while not found_closing:
try:
end = state.srcCharCode.index(0x24, pos)
except ValueError:
@@ -167,7 +196,6 @@ def _math_inline_dollar(state: StateInline, silent: bool) -> bool:
end += 1
found_closing = True
- break
if not found_closing:
return False
@@ -199,7 +227,9 @@ def _math_inline_dollar(state: StateInline, silent: bool) -> bool:
return False
if not silent:
- token = state.push("math_inline", "math", 0)
+ token = state.push(
+ "math_inline_double" if is_double else "math_inline", "math", 0
+ )
token.content = text
token.markup = "$$" if is_double else "$"
@@ -216,6 +246,7 @@ def _math_inline_dollar(state: StateInline, silent: bool) -> bool:
def math_block_dollar(
allow_labels: bool = True,
+ label_normalizer: Optional[Callable[[str], str]] = None,
) -> Callable[[StateBlock, int, int, bool], bool]:
"""Generate block dollar rule."""
@@ -249,7 +280,7 @@ def _math_block_dollar(
# search for end of block on same line
lineText = state.src[startPos:end]
if len(lineText.strip()) > 3:
- lineText = state.src[startPos:end]
+
if lineText.strip().endswith("$$"):
haveEndMarker = True
end = end - 2 - (len(lineText) - len(lineText.strip()))
@@ -295,13 +326,13 @@ def _math_block_dollar(
state.line = nextLine + (1 if haveEndMarker else 0)
- token = state.push("math_block_eqno" if label else "math_block", "math", 0)
+ token = state.push("math_block_label" if label else "math_block", "math", 0)
token.block = True
token.content = state.src[startPos + 2 : end]
token.markup = "$$"
token.map = [startLine, state.line]
if label:
- token.info = label
+ token.info = label if label_normalizer is None else label_normalizer(label)
return True
diff --git a/setup.cfg b/setup.cfg
index ee42a10..79eeabd 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -60,4 +60,4 @@ strict_equality = True
[flake8]
max-line-length = 100
-extend-ignore = E203
+extend-ignore = E203,E731
diff --git a/tests/fixtures/dollar_math.md b/tests/fixtures/dollar_math.md
index dd0f423..a1c2d43 100644
--- a/tests/fixtures/dollar_math.md
+++ b/tests/fixtures/dollar_math.md
@@ -16,35 +16,35 @@ single character inline equation. (valid=True)
.
$a$
.
-a
+a
.
inline equation with single greek character (valid=True)
.
$\\varphi$
.
-\\varphi
+\\varphi
.
simple equation starting and ending with numbers. (valid=True)
.
$1+1=2$
.
-1+1=2
+1+1=2
.
simple equation including special html character. (valid=True)
.
$1+1<3$
.
-1+1<3
+1+1<3
.
equation including backslashes. (valid=True)
.
$a \\backslash$
.
-a \\backslash
+a \\backslash
.
use of currency symbol, i.e. digits before/after opening/closing (valid=True)
@@ -58,42 +58,42 @@ use of currency symbol (valid=True)
.
If you solve $1+2$ you get $3
.
-If you solve 1+2 you get $3
+If you solve 1+2 you get $3
.
inline fraction (valid=True)
.
$\\frac{1}{2}$
.
-\\frac{1}{2}
+\\frac{1}{2}
.
inline column vector (valid=True)
.
$\\begin{pmatrix}x\\\\y\\end{pmatrix}$
.
-\\begin{pmatrix}x\\\\y\\end{pmatrix}
+\\begin{pmatrix}x\\\\y\\end{pmatrix}
.
inline bold vector notation (valid=True)
.
${\\tilde\\bold e}_\\alpha$
.
-{\\tilde\\bold e}_\\alpha
+{\\tilde\\bold e}_\\alpha
.
exponentiation (valid=True)
.
$a^{b}$
.
-a^{b}
+a^{b}
.
conjugate complex (valid=True)
.
$a^\*b$ with $a^\*$
.
-a^\*b with a^\*
+a^\*b with a^\*
.
Inline multi-line (valid=True)
@@ -101,8 +101,8 @@ Inline multi-line (valid=True)
a $a
\not=1$ b
.
-a a
-\not=1 b
+a a
+\not=1 b
.
Inline multi-line with newline (valid=False)
@@ -119,28 +119,28 @@ single block equation, greek index (valid=True)
.
$$e_\\alpha$$
.
-
+
+e_\\alpha
+
.
display equation on its own single line. (valid=True)
.
-$$1+1=2$$
+$$1+1=2$$
.
-
+
+1+1=2
+
.
display equation with number on its own single line. (valid=True)
.
-$$1+1=2$$ (2)
+$$1+1=2$$ (2)
.
-
+
.
inline equation followed by block equation. (valid=True)
@@ -149,19 +149,19 @@ ${e}_x$
$$e_\\alpha$$
.
-{e}_x
-
+{e}_x
+
+e_\\alpha
+
.
underline tests (valid=True)
.
$$c{\\bold e}_x = a{\\bold e}_\\alpha - b\\tilde{\\bold e}_\\alpha$$
.
-
-c{\\bold e}_x = a{\\bold e}_\\alpha - b\\tilde{\\bold e}_\\alpha
-
+
+c{\\bold e}_x = a{\\bold e}_\\alpha - b\\tilde{\\bold e}_\\alpha
+
.
non-numeric character before opening $ or
@@ -171,30 +171,30 @@ a$1+1=2$
$1+1=2$b
c$x$d
.
-a1+1=2
-1+1=2b
-cxd
+a1+1=2
+1+1=2b
+cxd
.
following dollar character '$' is allowed. (valid=True)
.
-$x$ $
+$x$ $
.
-x $
+x $
.
consecutive inline equations. (valid=True)
.
$x$ $y$
.
-x y
+x y
.
inline equation after '-' sign in text. (valid=True)
.
so-what is $x$
.
-so-what is x
+so-what is x
.
display equation with line breaks. (valid=True)
@@ -203,11 +203,9 @@ $$
1+1=2
$$
.
-
-
+
1+1=2
-
-
+
.
multiple equations (valid=True)
@@ -220,16 +218,12 @@ $$
b = 2
$$
.
-
-
+
a = 1
-
-
-
+
b = 2
-
-
+
.
equation followed by a labelled equation (valid=True)
@@ -242,62 +236,58 @@ $$
b = 2
$$ (1)
.
-
-
+
a = 1
-
-
-
+
.
multiline equation. (valid=True)
.
$$\\begin{matrix}
- f & = & 2 + x + 3 \\
- & = & 5 + x
+ f & = & 2 + x + 3 \\
+ & = & 5 + x
\\end{matrix}$$
.
-
-\\begin{matrix}
- f & = & 2 + x + 3 \\
- & = & 5 + x
-\\end{matrix}
-
+
+\\begin{matrix}
+ f & = & 2 + x + 3 \\
+ & = & 5 + x
+\\end{matrix}
+
.
vector equation. (valid=True)
.
-$$\\begin{pmatrix}x_2 \\\\ y_2 \\end{pmatrix} =
+$$\\begin{pmatrix}x_2 \\\\ y_2 \\end{pmatrix} =
\\begin{pmatrix} A & B \\\\ C & D \\end{pmatrix}\\cdot
\\begin{pmatrix} x_1 \\\\ y_1 \\end{pmatrix}$$
.
-
-\\begin{pmatrix}x_2 \\\\ y_2 \\end{pmatrix} =
-\\begin{pmatrix} A & B \\\\ C & D \\end{pmatrix}\\cdot
-\\begin{pmatrix} x_1 \\\\ y_1 \\end{pmatrix}
-
+
+\\begin{pmatrix}x_2 \\\\ y_2 \\end{pmatrix} =
+\\begin{pmatrix} A & B \\\\ C & D \\end{pmatrix}\\cdot
+\\begin{pmatrix} x_1 \\\\ y_1 \\end{pmatrix}
+
.
display equation with equation number. (valid=True)
.
$$f(x) = x^2 - 1$$ (1)
.
-
+
.
inline equation following code section. (valid=True)
.
`code`$a-b$
.
-codea-b
+codea-b
.
equation following code block. (valid=True)
@@ -309,9 +299,9 @@ $$a+b$$
.
code
-
+
+a+b
+
.
numbered equation following code block. (valid=True)
@@ -323,10 +313,10 @@ $$a+b$$(1)
.
code
-
+
.
Equations in list. (valid=True)
@@ -336,10 +326,10 @@ Equations in list. (valid=True)
1. $3+4$
.
-- 1+2
-- 2+3
+
- 1+2
+- 2+3
-- 3+4
+- 3+4
@@ -349,26 +339,26 @@ Inline sum. (valid=True)
.
$\\sum\_{i=1}^n$
.
-\\sum\_{i=1}^n
+\\sum\_{i=1}^n
.
Sum without equation number. (valid=True)
.
$$\\sum\_{i=1}^n$$
.
-
+
+\\sum\_{i=1}^n
+
.
Sum with equation number. (valid=True)
.
$$\\sum\_{i=1}\^n$$ (2)
.
-
+
.
equation number always vertically aligned. (valid=True)
@@ -377,24 +367,24 @@ $${\\bold e}(\\varphi) = \\begin{pmatrix}
\\cos\\varphi\\\\\\sin\\varphi
\\end{pmatrix}$$ (3)
.
-
-{\\bold e}(\\varphi) = \\begin{pmatrix}
+
+
¶
+{\\bold e}(\\varphi) = \\begin{pmatrix}
\\cos\\varphi\\\\\\sin\\varphi
-\\end{pmatrix}
-
(3)
-
+\\end{pmatrix}
+
.
inline equations in blockquote. (valid=True)
.
-> see $a = b + c$
-> $c^2=a^2+b^2$ (2)
-> $c^2=a^2+b^2$
+> see $a = b + c$
+> $c^2=a^2+b^2$ (2)
+> $c^2=a^2+b^2$
.
-see a = b + c
-c^2=a^2+b^2 (2)
-c^2=a^2+b^2
+see a = b + c
+c^2=a^2+b^2 (2)
+c^2=a^2+b^2
.
@@ -404,14 +394,14 @@ display equation in blockquote. (valid=True)
>
> $$ a+b=c$$ (2)
>
-> in blockquote.
+> in blockquote.
.
formula
-
+
in blockquote.
.
@@ -425,15 +415,13 @@ $$ (abc)
- ab $c=1$ d
.
-
-
+
+
¶
a=1 \\
b=2
-
-
(abc)
-
+
.
@@ -443,8 +431,8 @@ dollar '$' characters. (valid=True)
\\$1+1=2$
$1+1=2\\$
.
-\1+1=2
-1+1=2\\
+\1+1=2
+1+1=2\\
.
empty line between text and display formula is required. (valid=False)
@@ -495,49 +483,49 @@ math-escaping: internal escaped $:
.
$p_2 = \$1$
.
-p_2 = \$1
+p_2 = \$1
.
math-escaping: double-escaped start $:
.
\\$p_2 = 1$
.
-\p_2 = 1
+\p_2 = 1
.
math-escaping: double-escaped end $:
.
$p_2 = \\$a
.
-p_2 = \\a
+p_2 = \\a
.
Inline double-dollar start:
.
$$a=1$$ b
.
-a=1 b
+a=1
b
.
Inline double-dollar end:
.
a $$a=1$$
.
-a a=1
+a
a=1
.
Inline double-dollar enclosed:
.
a $$a=1$$ (1) b
.
-a a=1 (1) b
+a
a=1
(1) b
.
Inline double-dollar, escaped:
.
a \$$a=1$$ b
.
-a $a=1$ b
+a $a=1$ b
.
Inline mixed single/double dollars:
@@ -548,9 +536,17 @@ $$
$$
i.e., $[\alpha \bar{X}, \infty)$ is a lower 1-sided $1-\alpha$ confidence bound for $\mu$.
.
-Hence, for \alpha \in (0, 1),
-
- \mathbb P (\alpha \bar{X} \ge \mu) \le \alpha;
-
-i.e., [\alpha \bar{X}, \infty) is a lower 1-sided 1-\alpha confidence bound for \mu.
+Hence, for \alpha \in (0, 1),
+
\mathbb P (\alpha \bar{X} \ge \mu) \le \alpha;
+i.e., [\alpha \bar{X}, \infty) is a lower 1-sided 1-\alpha confidence bound for \mu.
+.
+
+display equation with label containing whitespace. (valid=True)
+.
+$$1+1=2$$ (a b)
+.
+
.
diff --git a/tests/test_dollarmath.py b/tests/test_dollarmath.py
index 3db3a78..1cb1b12 100644
--- a/tests/test_dollarmath.py
+++ b/tests/test_dollarmath.py
@@ -49,7 +49,7 @@ def test_block_func():
block_func(state, 0, 10, False)
print(tokens[0].as_dict())
assert tokens[0].as_dict() == {
- "type": "math_block_eqno",
+ "type": "math_block_label",
"tag": "math",
"nesting": 0,
"attrs": None,
@@ -86,7 +86,7 @@ def test_plugin_parse(data_regression):
"line,title,input,expected",
read_fixture_file(FIXTURE_PATH.joinpath("dollar_math.md")),
)
-def test_dollarmath_fixturess(line, title, input, expected):
+def test_dollarmath_fixtures(line, title, input, expected):
md = MarkdownIt("commonmark").use(
dollarmath_plugin, allow_space=False, allow_digits=False, double_inline=True
)
diff --git a/tests/test_dollarmath/test_plugin_parse.yml b/tests/test_dollarmath/test_plugin_parse.yml
index 338d18c..789cbe7 100644
--- a/tests/test_dollarmath/test_plugin_parse.yml
+++ b/tests/test_dollarmath/test_plugin_parse.yml
@@ -18,7 +18,7 @@
meta: {}
nesting: 0
tag: math
- type: math_block_eqno
+ type: math_block_label
- attrs: null
block: true
children: null