summaryrefslogtreecommitdiffstats
path: root/mdit_py_plugins/amsmath/__init__.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:29:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:29:52 +0000
commitfcb2f10732db61d216e2105c8154486f66b3e3ff (patch)
treeefda929db4b1543eecc583e3b7d9c0bad4cd86a6 /mdit_py_plugins/amsmath/__init__.py
parentInitial commit. (diff)
downloadmdit-py-plugins-fcb2f10732db61d216e2105c8154486f66b3e3ff.tar.xz
mdit-py-plugins-fcb2f10732db61d216e2105c8154486f66b3e3ff.zip
Adding upstream version 0.3.3.upstream/0.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mdit_py_plugins/amsmath/__init__.py')
-rw-r--r--mdit_py_plugins/amsmath/__init__.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/mdit_py_plugins/amsmath/__init__.py b/mdit_py_plugins/amsmath/__init__.py
new file mode 100644
index 0000000..0b367b5
--- /dev/null
+++ b/mdit_py_plugins/amsmath/__init__.py
@@ -0,0 +1,126 @@
+"""An extension to capture amsmath latex environments."""
+import re
+from typing import Callable, Optional
+
+from markdown_it import MarkdownIt
+from markdown_it.common.utils import escapeHtml
+from markdown_it.rules_block import StateBlock
+
+# Taken from amsmath version 2.1
+# http://anorien.csc.warwick.ac.uk/mirrors/CTAN/macros/latex/required/amsmath/amsldoc.pdf
+ENVIRONMENTS = [
+ # 3.2 single equation with an automatically gen-erated number
+ "equation",
+ # 3.3 variation equation, used for equations that don’t fit on a single line
+ "multline",
+ # 3.5 a group of consecutive equations when there is no alignment desired among them
+ "gather",
+ # 3.6 Used for two or more equations when vertical alignment is desired
+ "align",
+ # allows the horizontal space between equationsto be explicitly specified.
+ "alignat",
+ # stretches the space betweenthe equation columns to the maximum possible width
+ "flalign",
+ # 4.1 The pmatrix, bmatrix, Bmatrix, vmatrix and Vmatrix have (respectively)
+ # (),[],{},||,and ‖‖ delimiters built in.
+ "matrix",
+ "pmatrix",
+ "bmatrix",
+ "Bmatrix",
+ "vmatrix",
+ "Vmatrix",
+ # eqnarray is another math environment, it is not part of amsmath,
+ # and note that it is better to use align or equation+split instead
+ "eqnarray",
+]
+# other "non-top-level" environments:
+
+# 3.4 the split environment is for single equations that are too long to fit on one line
+# and hence must be split into multiple lines,
+# it is intended for use only inside some other displayed equation structure,
+# usually an equation, align, or gather environment
+
+# 3.7 variants gathered, aligned,and alignedat are provided
+# whose total width is the actual width of the contents;
+# thus they can be used as a component in a containing expression
+
+RE_OPEN = re.compile(r"\\begin\{(" + "|".join(ENVIRONMENTS) + r")([\*]?)\}")
+
+
+def amsmath_plugin(md: MarkdownIt, *, renderer: Optional[Callable[[str], str]] = None):
+ """Parses TeX math equations, without any surrounding delimiters,
+ only for top-level `amsmath <https://ctan.org/pkg/amsmath>`__ environments:
+
+ .. code-block:: latex
+
+ \\begin{gather*}
+ a_1=b_1+c_1\\\\
+ a_2=b_2+c_2-d_2+e_2
+ \\end{gather*}
+
+ :param renderer: Function to render content, by default escapes HTML
+
+ """
+ md.block.ruler.before(
+ "blockquote",
+ "amsmath",
+ amsmath_block,
+ {"alt": ["paragraph", "reference", "blockquote", "list", "footnote_def"]},
+ )
+
+ if renderer is None:
+ _renderer = lambda content: escapeHtml(content)
+ else:
+ _renderer = renderer
+
+ def render_amsmath_block(self, tokens, idx, options, env):
+ content = _renderer(str(tokens[idx].content))
+ return f'<div class="math amsmath">\n{content}\n</div>\n'
+
+ md.add_render_rule("amsmath", render_amsmath_block)
+
+
+def match_environment(string):
+ match_open = RE_OPEN.match(string)
+ if not match_open:
+ return None
+ environment = match_open.group(1)
+ numbered = match_open.group(2)
+ match_close = re.search(
+ r"\\end\{" + environment + numbered.replace("*", r"\*") + "\\}", string
+ )
+ if not match_close:
+ return None
+ return (environment, numbered, match_close.end())
+
+
+def amsmath_block(state: StateBlock, startLine: int, endLine: int, silent: bool):
+
+ # if it's indented more than 3 spaces, it should be a code block
+ if state.sCount[startLine] - state.blkIndent >= 4:
+ return False
+
+ begin = state.bMarks[startLine] + state.tShift[startLine]
+
+ outcome = match_environment(state.src[begin:])
+ if not outcome:
+ return False
+ environment, numbered, endpos = outcome
+ endpos += begin
+
+ line = startLine
+ while line < endLine:
+ if endpos >= state.bMarks[line] and endpos <= state.eMarks[line]:
+ # line for end of block math found ...
+ state.line = line + 1
+ break
+ line += 1
+
+ if not silent:
+ token = state.push("amsmath", "math", 0)
+ token.block = True
+ token.content = state.src[begin:endpos]
+ token.meta = {"environment": environment, "numbered": numbered}
+ token.map = [startLine, line]
+
+ return True