Show More
@@ -1,118 +1,122 b'' | |||||
1 | """Markdown filters with mistune |
|
1 | """Markdown filters with mistune | |
2 |
|
2 | |||
3 | Used from markdown.py |
|
3 | Used from markdown.py | |
4 | """ |
|
4 | """ | |
5 | # Copyright (c) IPython Development Team. |
|
5 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
7 | |||
8 | from __future__ import print_function |
|
8 | from __future__ import print_function | |
9 |
|
9 | |||
10 | import re |
|
10 | import re | |
11 |
|
11 | |||
12 | import mistune |
|
12 | import mistune | |
13 |
|
13 | |||
14 | from pygments import highlight |
|
14 | from pygments import highlight | |
15 | from pygments.lexers import get_lexer_by_name |
|
15 | from pygments.lexers import get_lexer_by_name | |
16 | from pygments.formatters import HtmlFormatter |
|
16 | from pygments.formatters import HtmlFormatter | |
17 | from pygments.util import ClassNotFound |
|
17 | from pygments.util import ClassNotFound | |
18 |
|
18 | |||
19 | from IPython.nbconvert.filters.strings import add_anchor |
|
19 | from IPython.nbconvert.filters.strings import add_anchor | |
20 | from IPython.nbconvert.utils.exceptions import ConversionException |
|
20 | from IPython.nbconvert.utils.exceptions import ConversionException | |
21 | from IPython.utils.decorators import undoc |
|
21 | from IPython.utils.decorators import undoc | |
22 |
|
22 | |||
23 |
|
23 | |||
24 | @undoc |
|
24 | @undoc | |
25 | class MathBlockGrammar(mistune.BlockGrammar): |
|
25 | class MathBlockGrammar(mistune.BlockGrammar): | |
26 |
block_math = re.compile("^\$\$( |
|
26 | block_math = re.compile(r"^\$\$(.*?)\$\$", re.DOTALL) | |
27 | latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}", |
|
27 | latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}", | |
28 | re.DOTALL) |
|
28 | re.DOTALL) | |
29 |
|
29 | |||
30 | @undoc |
|
30 | @undoc | |
31 | class MathBlockLexer(mistune.BlockLexer): |
|
31 | class MathBlockLexer(mistune.BlockLexer): | |
32 | default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules |
|
32 | default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules | |
33 |
|
33 | |||
34 | def __init__(self, rules=None, **kwargs): |
|
34 | def __init__(self, rules=None, **kwargs): | |
35 | if rules is None: |
|
35 | if rules is None: | |
36 | rules = MathBlockGrammar() |
|
36 | rules = MathBlockGrammar() | |
37 | super(MathBlockLexer, self).__init__(rules, **kwargs) |
|
37 | super(MathBlockLexer, self).__init__(rules, **kwargs) | |
38 |
|
38 | |||
39 | def parse_block_math(self, m): |
|
39 | def parse_block_math(self, m): | |
40 | """Parse a $$math$$ block""" |
|
40 | """Parse a $$math$$ block""" | |
41 | self.tokens.append({ |
|
41 | self.tokens.append({ | |
42 | 'type': 'block_math', |
|
42 | 'type': 'block_math', | |
43 | 'text': m.group(1) |
|
43 | 'text': m.group(1) | |
44 | }) |
|
44 | }) | |
45 |
|
45 | |||
46 | def parse_latex_environment(self, m): |
|
46 | def parse_latex_environment(self, m): | |
47 | self.tokens.append({ |
|
47 | self.tokens.append({ | |
48 | 'type': 'latex_environment', |
|
48 | 'type': 'latex_environment', | |
49 | 'name': m.group(1), |
|
49 | 'name': m.group(1), | |
50 | 'text': m.group(2) |
|
50 | 'text': m.group(2) | |
51 | }) |
|
51 | }) | |
52 |
|
52 | |||
53 | @undoc |
|
53 | @undoc | |
54 | class MathInlineGrammar(mistune.InlineGrammar): |
|
54 | class MathInlineGrammar(mistune.InlineGrammar): | |
55 |
math = re.compile("^\$( |
|
55 | math = re.compile(r"^\$(.+?)\$") | |
|
56 | block_math = re.compile(r"^\$\$(.+?)\$\$", re.DOTALL) | |||
56 | text = re.compile(r'^[\s\S]+?(?=[\\<!\[_*`~$]|https?://| {2,}\n|$)') |
|
57 | text = re.compile(r'^[\s\S]+?(?=[\\<!\[_*`~$]|https?://| {2,}\n|$)') | |
57 |
|
58 | |||
58 | @undoc |
|
59 | @undoc | |
59 | class MathInlineLexer(mistune.InlineLexer): |
|
60 | class MathInlineLexer(mistune.InlineLexer): | |
60 | default_rules = ['math'] + mistune.InlineLexer.default_rules |
|
61 | default_rules = ['math', 'block_math'] + mistune.InlineLexer.default_rules | |
61 |
|
62 | |||
62 | def __init__(self, renderer, rules=None, **kwargs): |
|
63 | def __init__(self, renderer, rules=None, **kwargs): | |
63 | if rules is None: |
|
64 | if rules is None: | |
64 | rules = MathInlineGrammar() |
|
65 | rules = MathInlineGrammar() | |
65 | super(MathInlineLexer, self).__init__(renderer, rules, **kwargs) |
|
66 | super(MathInlineLexer, self).__init__(renderer, rules, **kwargs) | |
66 |
|
67 | |||
67 | def output_math(self, m): |
|
68 | def output_math(self, m): | |
68 | return self.renderer.inline_math(m.group(1)) |
|
69 | return self.renderer.inline_math(m.group(1)) | |
69 |
|
70 | |||
|
71 | def output_block_math(self, m): | |||
|
72 | return self.renderer.block_math(m.group(1)) | |||
|
73 | ||||
70 | @undoc |
|
74 | @undoc | |
71 | class MarkdownWithMath(mistune.Markdown): |
|
75 | class MarkdownWithMath(mistune.Markdown): | |
72 | def __init__(self, renderer, **kwargs): |
|
76 | def __init__(self, renderer, **kwargs): | |
73 | if 'inline' not in kwargs: |
|
77 | if 'inline' not in kwargs: | |
74 | kwargs['inline'] = MathInlineLexer |
|
78 | kwargs['inline'] = MathInlineLexer | |
75 | if 'block' not in kwargs: |
|
79 | if 'block' not in kwargs: | |
76 | kwargs['block'] = MathBlockLexer |
|
80 | kwargs['block'] = MathBlockLexer | |
77 | super(MarkdownWithMath, self).__init__(renderer, **kwargs) |
|
81 | super(MarkdownWithMath, self).__init__(renderer, **kwargs) | |
78 |
|
82 | |||
79 | def output_block_math(self): |
|
83 | def output_block_math(self): | |
80 | return self.renderer.block_math(self.token['text']) |
|
84 | return self.renderer.block_math(self.token['text']) | |
81 |
|
85 | |||
82 | def output_latex_environment(self): |
|
86 | def output_latex_environment(self): | |
83 | return self.renderer.latex_environment(self.token['name'], self.token['text']) |
|
87 | return self.renderer.latex_environment(self.token['name'], self.token['text']) | |
84 |
|
88 | |||
85 | @undoc |
|
89 | @undoc | |
86 | class IPythonRenderer(mistune.Renderer): |
|
90 | class IPythonRenderer(mistune.Renderer): | |
87 | def block_code(self, code, lang): |
|
91 | def block_code(self, code, lang): | |
88 | if lang: |
|
92 | if lang: | |
89 | try: |
|
93 | try: | |
90 | lexer = get_lexer_by_name(lang, stripall=True) |
|
94 | lexer = get_lexer_by_name(lang, stripall=True) | |
91 | except ClassNotFound: |
|
95 | except ClassNotFound: | |
92 | code = lang + '\n' + code |
|
96 | code = lang + '\n' + code | |
93 | lang = None |
|
97 | lang = None | |
94 |
|
98 | |||
95 | if not lang: |
|
99 | if not lang: | |
96 | return '\n<pre><code>%s</code></pre>\n' % \ |
|
100 | return '\n<pre><code>%s</code></pre>\n' % \ | |
97 | mistune.escape(code) |
|
101 | mistune.escape(code) | |
98 |
|
102 | |||
99 | formatter = HtmlFormatter() |
|
103 | formatter = HtmlFormatter() | |
100 | return highlight(code, lexer, formatter) |
|
104 | return highlight(code, lexer, formatter) | |
101 |
|
105 | |||
102 | def header(self, text, level, raw=None): |
|
106 | def header(self, text, level, raw=None): | |
103 | html = super(IPythonRenderer, self).header(text, level, raw=raw) |
|
107 | html = super(IPythonRenderer, self).header(text, level, raw=raw) | |
104 | return add_anchor(html) |
|
108 | return add_anchor(html) | |
105 |
|
109 | |||
106 | # Pass math through unaltered - mathjax does the rendering in the browser |
|
110 | # Pass math through unaltered - mathjax does the rendering in the browser | |
107 | def block_math(self, text): |
|
111 | def block_math(self, text): | |
108 | return '$$%s$$' % text |
|
112 | return '$$%s$$' % text | |
109 |
|
113 | |||
110 | def latex_environment(self, name, text): |
|
114 | def latex_environment(self, name, text): | |
111 | return r'\begin{%s}%s\end{%s}' % (name, text, name) |
|
115 | return r'\begin{%s}%s\end{%s}' % (name, text, name) | |
112 |
|
116 | |||
113 | def inline_math(self, text): |
|
117 | def inline_math(self, text): | |
114 | return '$%s$' % text |
|
118 | return '$%s$' % text | |
115 |
|
119 | |||
116 | def markdown2html_mistune(source): |
|
120 | def markdown2html_mistune(source): | |
117 | """Convert a markdown string to HTML using mistune""" |
|
121 | """Convert a markdown string to HTML using mistune""" | |
118 | return MarkdownWithMath(renderer=IPythonRenderer()).render(source) |
|
122 | return MarkdownWithMath(renderer=IPythonRenderer()).render(source) |
General Comments 0
You need to be logged in to leave comments.
Login now