Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/mdit_py_plugins/amsmath/__init__.py: 50%
52 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:15 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:15 +0000
1"""An extension to capture amsmath latex environments."""
2from __future__ import annotations
4import re
5from typing import TYPE_CHECKING, Callable, Optional, Sequence
7from markdown_it import MarkdownIt
8from markdown_it.common.utils import escapeHtml
9from markdown_it.rules_block import StateBlock
11from mdit_py_plugins.utils import is_code_block
13if TYPE_CHECKING:
14 from markdown_it.renderer import RendererProtocol
15 from markdown_it.token import Token
16 from markdown_it.utils import EnvType, OptionsDict
18# Taken from amsmath version 2.1
19# http://anorien.csc.warwick.ac.uk/mirrors/CTAN/macros/latex/required/amsmath/amsldoc.pdf
20ENVIRONMENTS = [
21 # 3.2 single equation with an automatically gen-erated number
22 "equation",
23 # 3.3 variation equation, used for equations that dont fit on a single line
24 "multline",
25 # 3.5 a group of consecutive equations when there is no alignment desired among them
26 "gather",
27 # 3.6 Used for two or more equations when vertical alignment is desired
28 "align",
29 # allows the horizontal space between equationsto be explicitly specified.
30 "alignat",
31 # stretches the space betweenthe equation columns to the maximum possible width
32 "flalign",
33 # 4.1 The pmatrix, bmatrix, Bmatrix, vmatrix and Vmatrix have (respectively)
34 # (),[],{},||,and ‖‖ delimiters built in.
35 "matrix",
36 "pmatrix",
37 "bmatrix",
38 "Bmatrix",
39 "vmatrix",
40 "Vmatrix",
41 # eqnarray is another math environment, it is not part of amsmath,
42 # and note that it is better to use align or equation+split instead
43 "eqnarray",
44]
45# other "non-top-level" environments:
47# 3.4 the split environment is for single equations that are too long to fit on one line
48# and hence must be split into multiple lines,
49# it is intended for use only inside some other displayed equation structure,
50# usually an equation, align, or gather environment
52# 3.7 variants gathered, aligned,and alignedat are provided
53# whose total width is the actual width of the contents;
54# thus they can be used as a component in a containing expression
56RE_OPEN = re.compile(r"\\begin\{(" + "|".join(ENVIRONMENTS) + r")([\*]?)\}")
59def amsmath_plugin(
60 md: MarkdownIt, *, renderer: Optional[Callable[[str], str]] = None
61) -> None:
62 """Parses TeX math equations, without any surrounding delimiters,
63 only for top-level `amsmath <https://ctan.org/pkg/amsmath>`__ environments:
65 .. code-block:: latex
67 \\begin{gather*}
68 a_1=b_1+c_1\\\\
69 a_2=b_2+c_2-d_2+e_2
70 \\end{gather*}
72 :param renderer: Function to render content, by default escapes HTML
74 """
75 md.block.ruler.before(
76 "blockquote",
77 "amsmath",
78 amsmath_block,
79 {"alt": ["paragraph", "reference", "blockquote", "list", "footnote_def"]},
80 )
82 _renderer = (lambda content: escapeHtml(content)) if renderer is None else renderer
84 def render_amsmath_block(
85 self: RendererProtocol,
86 tokens: Sequence[Token],
87 idx: int,
88 options: OptionsDict,
89 env: EnvType,
90 ) -> str:
91 content = _renderer(str(tokens[idx].content))
92 return f'<div class="math amsmath">\n{content}\n</div>\n'
94 md.add_render_rule("amsmath", render_amsmath_block)
97def match_environment(string: str) -> None | tuple[str, str, int]:
98 match_open = RE_OPEN.match(string)
99 if not match_open:
100 return None
101 environment = match_open.group(1)
102 numbered = match_open.group(2)
103 match_close = re.search(
104 r"\\end\{" + environment + numbered.replace("*", r"\*") + "\\}", string
105 )
106 if not match_close:
107 return None
108 return (environment, numbered, match_close.end())
111def amsmath_block(
112 state: StateBlock, startLine: int, endLine: int, silent: bool
113) -> bool:
114 if is_code_block(state, startLine):
115 return False
117 begin = state.bMarks[startLine] + state.tShift[startLine]
119 outcome = match_environment(state.src[begin:])
120 if not outcome:
121 return False
122 environment, numbered, endpos = outcome
123 endpos += begin
125 line = startLine
126 while line < endLine:
127 if endpos >= state.bMarks[line] and endpos <= state.eMarks[line]:
128 # line for end of block math found ...
129 state.line = line + 1
130 break
131 line += 1
133 if not silent:
134 token = state.push("amsmath", "math", 0)
135 token.block = True
136 token.content = state.src[begin:endpos]
137 token.meta = {"environment": environment, "numbered": numbered}
138 token.map = [startLine, line]
140 return True