Skip to content

Commit f017595

Browse files
Merge pull request #573 from navanchauhan/latex-extra
Add new LaTeX Extra
2 parents 4722442 + d171ac9 commit f017595

File tree

7 files changed

+90
-2
lines changed

7 files changed

+90
-2
lines changed

lib/markdown2.py

+50
Original file line numberDiff line numberDiff line change
@@ -2764,6 +2764,55 @@ def sub(self, match):
27642764
def run(self, text):
27652765
return self.fenced_code_block_re.sub(self.sub, text)
27662766

2767+
class Latex(Extra):
2768+
'''
2769+
Convert $ and $$ to <math> and </math> tags for inline and block math.
2770+
'''
2771+
name = 'latex'
2772+
order = (Stage.CODE_BLOCKS, FencedCodeBlocks), ()
2773+
2774+
_single_dollar_re = re.compile(r'(?<!\$)\$(?!\$)(.*?)\$')
2775+
_double_dollar_re = re.compile(r'\$\$(.*?)\$\$', re.DOTALL)
2776+
2777+
# Ways to escape
2778+
_pre_code_block_re = re.compile(r"<pre>(.*?)</pre>", re.DOTALL) # Wraped in <pre>
2779+
_triple_re = re.compile(r'```(.*?)```', re.DOTALL) # Wrapped in a code block ```
2780+
_single_re = re.compile(r'(?<!`)(`)(.*?)(?<!`)\1(?!`)') # Wrapped in a single `
2781+
2782+
converter = None
2783+
code_blocks = {}
2784+
2785+
def _convert_single_match(self, match):
2786+
return self.converter.convert(match.group(1))
2787+
2788+
def _convert_double_match(self, match):
2789+
return self.converter.convert(match.group(1).replace(r"\n", ''), display="block")
2790+
2791+
def code_placeholder(self, match):
2792+
placeholder = f"<!--CODE_BLOCK_{len(self.code_blocks)}-->"
2793+
self.code_blocks[placeholder] = match.group(0)
2794+
return placeholder
2795+
2796+
def run(self, text):
2797+
try:
2798+
import latex2mathml.converter
2799+
self.converter = latex2mathml.converter
2800+
except ImportError:
2801+
raise ImportError('The "latex" extra requires the "latex2mathml" package to be installed.')
2802+
2803+
# Escape by replacing with a code block
2804+
text = self._pre_code_block_re.sub(self.code_placeholder, text)
2805+
text = self._single_re.sub(self.code_placeholder, text)
2806+
text = self._triple_re.sub(self.code_placeholder, text)
2807+
2808+
text = self._single_dollar_re.sub(self._convert_single_match, text)
2809+
text = self._double_dollar_re.sub(self._convert_double_match, text)
2810+
2811+
# Convert placeholder tag back to original code
2812+
for placeholder, code_block in self.code_blocks.items():
2813+
text = text.replace(placeholder, code_block)
2814+
2815+
return text
27672816

27682817
class LinkPatterns(Extra):
27692818
'''
@@ -3328,6 +3377,7 @@ def test(self, text):
33283377
Breaks.register()
33293378
CodeFriendly.register()
33303379
FencedCodeBlocks.register()
3380+
Latex.register()
33313381
LinkPatterns.register()
33323382
MarkdownInHTML.register()
33333383
MiddleWordEm.register()

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333

3434
extras_require = {
3535
"code_syntax_highlighting": ["pygments>=2.7.3"],
36-
"wavedrom": ["wavedrom; python_version>='3.7'"]
36+
"wavedrom": ["wavedrom; python_version>='3.7'"],
37+
"latex": ['latex2mathml; python_version>="3.8.1"'],
3738
}
3839
# nested listcomp to combine all optional extras into convenient "all" option
3940
extras_require["all"] = [i for v in tuple(extras_require.values()) for i in v]

test/test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def setup():
3838
setup()
3939
default_tags = []
4040
warnings = []
41-
for extra_lib in ('pygments', 'wavedrom'):
41+
for extra_lib in ('pygments', 'wavedrom', 'latex2mathml'):
4242
try:
4343
mod = importlib.import_module(extra_lib)
4444
except ImportError:

test/tm-cases/latex.html

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<h2>Simple Test</h2>
2+
3+
<p>Inline Equations can be written as <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mrow><mi>y</mi><mo>&#x0003D;</mo><mi>m</mi><mi>x</mi><mo>&#x0002B;</mo><mi>b</mi></mrow></math>.
4+
Block equations are wrapped using</p>
5+
6+
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mrow><mi>x</mi><mo>&#x0003D;</mo><mfrac><mrow><mo>&#x02212;</mo><mi>b</mi><mi>&#x000B1;</mi><msqrt><mrow><msup><mi>b</mi><mn>2</mn></msup><mo>&#x02212;</mo><mn>4</mn><mi>a</mi><mi>c</mi></mrow></msqrt></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></mrow></math>
7+
8+
<p>This code block will not have the math rendered.
9+
<code>
10+
some random code, describing $a and $b will not be rendered, $y=mx$
11+
</code>
12+
This will not work either <code>$\sqrt{2}</code> or</p>
13+
14+
<p><code>
15+
$$
16+
f = 12
17+
$$
18+
</code></p>

test/tm-cases/latex.opts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"extras": ["latex","latex2mathml"]}

test/tm-cases/latex.tags

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extra latex latex2mathml

test/tm-cases/latex.text

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Simple Test
2+
Inline Equations can be written as $y=mx+b$.
3+
Block equations are wrapped using
4+
$$
5+
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
6+
$$
7+
This code block will not have the math rendered.
8+
```
9+
some random code, describing $a and $b will not be rendered, $y=mx$
10+
```
11+
This will not work either `$\sqrt{2}` or
12+
13+
```
14+
$$
15+
f = 12
16+
$$
17+
```

0 commit comments

Comments
 (0)