diff options
Diffstat (limited to '')
-rw-r--r-- | mdit_py_plugins/texmath/LICENSE | 21 | ||||
-rw-r--r-- | mdit_py_plugins/texmath/README.md | 137 | ||||
-rw-r--r-- | mdit_py_plugins/texmath/__init__.py | 1 | ||||
-rw-r--r-- | mdit_py_plugins/texmath/index.py | 307 | ||||
-rw-r--r-- | mdit_py_plugins/texmath/port.yaml | 7 |
5 files changed, 473 insertions, 0 deletions
diff --git a/mdit_py_plugins/texmath/LICENSE b/mdit_py_plugins/texmath/LICENSE new file mode 100644 index 0000000..b88387c --- /dev/null +++ b/mdit_py_plugins/texmath/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-17 Stefan Goessner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mdit_py_plugins/texmath/README.md b/mdit_py_plugins/texmath/README.md new file mode 100644 index 0000000..f79f335 --- /dev/null +++ b/mdit_py_plugins/texmath/README.md @@ -0,0 +1,137 @@ +[![License](https://img.shields.io/github/license/goessner/markdown-it-texmath.svg)](https://github.com/goessner/markdown-it-texmath/blob/master/licence.txt) +[![npm](https://img.shields.io/npm/v/markdown-it-texmath.svg)](https://www.npmjs.com/package/markdown-it-texmath) +[![npm](https://img.shields.io/npm/dt/markdown-it-texmath.svg)](https://www.npmjs.com/package/markdown-it-texmath) + +# markdown-it-texmath + +Add TeX math equations to your Markdown documents rendered by [markdown-it](https://github.com/markdown-it/markdown-it) parser. [KaTeX](https://github.com/Khan/KaTeX) is used as a fast math renderer. + +## Features +Simplify the process of authoring markdown documents containing math formulas. +This extension is a comfortable tool for scientists, engineers and students with markdown as their first choice document format. + +* Macro support +* Simple formula numbering +* Inline math with tables, lists and blockquote. +* User setting delimiters: + * `'dollars'` (default) + * inline: `$...$` + * display: `$$...$$` + * display + equation number: `$$...$$ (1)` + * `'brackets'` + * inline: `\(...\)` + * display: `\[...\]` + * display + equation number: `\[...\] (1)` + * `'gitlab'` + * inline: ``$`...`$`` + * display: `` ```math ... ``` `` + * display + equation number: `` ```math ... ``` (1)`` + * `'julia'` + * inline: `$...$` or ``` ``...`` ``` + * display: `` ```math ... ``` `` + * display + equation number: `` ```math ... ``` (1)`` + * `'kramdown'` + * inline: ``$$...$$`` + * display: `$$...$$` + * display + equation number: `$$...$$ (1)` + +## Show me + +View a [test table](https://goessner.github.io/markdown-it-texmath/index.html). + +[try it out ...](https://goessner.github.io/markdown-it-texmath/markdown-it-texmath-demo.html) + +## Use with `node.js` + +Install the extension. Verify having `markdown-it` and `katex` already installed . +``` +npm install markdown-it-texmath +``` +Use it with JavaScript. +```js +let kt = require('katex'), + tm = require('markdown-it-texmath').use(kt), + md = require('markdown-it')().use(tm,{delimiters:'dollars',macros:{"\\RR": "\\mathbb{R}"}}); + +md.render('Euler\'s identity \(e^{i\pi}+1=0\) is a beautiful formula in $\\RR 2$.') +``` + +## Use in Browser +```html +<html> +<head> + <meta charset='utf-8'> + <link rel="stylesheet" href="katex.min.css"> + <link rel="stylesheet" href="texmath.css"> + <script src="markdown-it.min.js"></script> + <script src="katex.min.js"></script> + <script src="texmath.js"></script> +</head> +<body> + <div id="out"></div> + <script> + let md; + document.addEventListener("DOMContentLoaded", () => { + const tm = texmath.use(katex); + md = markdownit().use(tm,{delimiters:'dollars',macros:{"\\RR": "\\mathbb{R}"}}); + out.innerHTML = md.render('Euler\'s identity $e^{i\pi}+1=0$ is a beautiful formula in //RR 2.'); + }) + </script> +</body> +</html> +``` +## CDN + +Use following links for `texmath.js` and `texmath.css` +* `https://gitcdn.xyz/cdn/goessner/markdown-it-texmath/master/texmath.js` +* `https://gitcdn.xyz/cdn/goessner/markdown-it-texmath/master/texmath.css` + +## Dependencies + +* [`markdown-it`](https://github.com/markdown-it/markdown-it): Markdown parser done right. Fast and easy to extend. +* [`katex`](https://github.com/Khan/KaTeX): This is where credits for fast rendering TeX math in HTML go to. + +## ToDo + + nothing yet + +## FAQ + +* __`markdown-it-texmath` with React Native does not work, why ?__ + * `markdown-it-texmath` is using regular expressions with `y` [(sticky) property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky) and cannot avoid this. The use of the `y` flag in regular expressions means the plugin is not compatible with React Native (which as of now doesn't support it and throws an error `Invalid flags supplied to RegExp constructor`). + +## CHANGELOG + +### [0.6.0] on October 04, 2019 +* Add support for [Julia Markdown](https://docs.julialang.org/en/v1/stdlib/Markdown/) on [request](https://github.com/goessner/markdown-it-texmath/issues/15). + +### [0.5.5] on February 07, 2019 +* Remove [rendering bug with brackets delimiters](https://github.com/goessner/markdown-it-texmath/issues/9). + +### [0.5.4] on January 20, 2019 +* Remove pathological [bug within blockquotes](https://github.com/goessner/mdmath/issues/50). + +### [0.5.3] on November 11, 2018 +* Add support for Tex macros (https://katex.org/docs/supported.html#macros) . +* Bug with [brackets delimiters](https://github.com/goessner/markdown-it-texmath/issues/9) . + +### [0.5.2] on September 07, 2018 +* Add support for [Kramdown](https://kramdown.gettalong.org/) . + +### [0.5.0] on August 15, 2018 +* Fatal blockquote bug investigated. Implemented workaround to vscode bug, which has finally gone with vscode 1.26.0 . + +### [0.4.6] on January 05, 2018 +* Escaped underscore bug removed. + +### [0.4.5] on November 06, 2017 +* Backslash bug removed. + +### [0.4.4] on September 27, 2017 +* Modifying the `block` mode regular expression with `gitlab` delimiters, so removing the `newline` bug. + +## License + +`markdown-it-texmath` is licensed under the [MIT License](./license.txt) + + © [Stefan Gössner](https://github.com/goessner) diff --git a/mdit_py_plugins/texmath/__init__.py b/mdit_py_plugins/texmath/__init__.py new file mode 100644 index 0000000..f0c2588 --- /dev/null +++ b/mdit_py_plugins/texmath/__init__.py @@ -0,0 +1 @@ +from .index import texmath_plugin # noqa F401 diff --git a/mdit_py_plugins/texmath/index.py b/mdit_py_plugins/texmath/index.py new file mode 100644 index 0000000..ecf178c --- /dev/null +++ b/mdit_py_plugins/texmath/index.py @@ -0,0 +1,307 @@ +import re +from typing import Optional + +from markdown_it import MarkdownIt +from markdown_it.common.utils import charCodeAt + + +def texmath_plugin(md: MarkdownIt, delimiters="dollars", macros: Optional[dict] = None): + """Plugin ported from + `markdown-it-texmath <https://github.com/goessner/markdown-it-texmath>`__. + + It parses TeX math equations set inside opening and closing delimiters: + + .. code-block:: md + + $\\alpha = \\frac{1}{2}$ + + :param delimiters: one of: brackets, dollars, gitlab, julia, kramdown + + """ + macros = macros or {} + + if delimiters in rules: + for rule_inline in rules[delimiters]["inline"]: + md.inline.ruler.before( + "escape", rule_inline["name"], make_inline_func(rule_inline) + ) + + def render_math_inline(self, tokens, idx, options, env): + return rule_inline["tmpl"].format( + render(tokens[idx].content, False, macros) + ) + + md.add_render_rule(rule_inline["name"], render_math_inline) + + for rule_block in rules[delimiters]["block"]: + md.block.ruler.before( + "fence", rule_block["name"], make_block_func(rule_block) + ) + + def render_math_block(self, tokens, idx, options, env): + return rule_block["tmpl"].format( + render(tokens[idx].content, True, macros), tokens[idx].info + ) + + md.add_render_rule(rule_block["name"], render_math_block) + + +def applyRule(rule, string: str, begin, inBlockquote): + + if not ( + string.startswith(rule["tag"], begin) + and (rule["pre"](string, begin) if "pre" in rule else True) + ): + return False + + match = rule["rex"].match(string[begin:]) # type: re.Match + + if not match or match.start() != 0: + return False + + lastIndex = match.end() + begin - 1 + if "post" in rule: + if not ( + rule["post"](string, lastIndex) # valid post-condition + # remove evil blockquote bug (https:#github.com/goessner/mdmath/issues/50) + and (not inBlockquote or "\n" not in match.group(1)) + ): + return False + return match + + +def make_inline_func(rule): + def _func(state, silent): + res = applyRule(rule, state.src, state.pos, False) + if res: + if not silent: + token = state.push(rule["name"], "math", 0) + token.content = res[1] # group 1 from regex .. + token.markup = rule["tag"] + + state.pos += res.end() + + return bool(res) + + return _func + + +def make_block_func(rule): + def _func(state, begLine, endLine, silent): + begin = state.bMarks[begLine] + state.tShift[begLine] + res = applyRule(rule, state.src, begin, state.parentType == "blockquote") + if res: + if not silent: + token = state.push(rule["name"], "math", 0) + token.block = True + token.content = res[1] + token.info = res[len(res.groups())] + token.markup = rule["tag"] + + line = begLine + endpos = begin + res.end() - 1 + + 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 + + state.pos = begin + res.end() + + return bool(res) + + return _func + + +def dollar_pre(str, beg): + prv = charCodeAt(str[beg - 1], 0) if beg > 0 else False + return ( + (not prv) or prv != 0x5C and (prv < 0x30 or prv > 0x39) # no backslash, + ) # no decimal digit .. before opening '$' + + +def dollar_post(string, end): + try: + nxt = string[end + 1] and charCodeAt(string[end + 1], 0) + except IndexError: + return True + return ( + (not nxt) or (nxt < 0x30) or (nxt > 0x39) + ) # no decimal digit .. after closing '$' + + +def render(tex, displayMode, macros): + return tex + # TODO better HTML renderer port for math + # try: + # res = katex.renderToString(tex,{throwOnError:False,displayMode,macros}) + # except: + # res = tex+": "+err.message.replace("<","<") + # return res + + +# def use(katex): # math renderer used ... +# texmath.katex = katex; # ... katex solely at current ... +# return texmath; +# } + + +# All regexes areg global (g) and sticky (y), see: +# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky + +rules: dict = { + "brackets": { + "inline": [ + { + "name": "math_inline", + "rex": re.compile(r"^\\\((.+?)\\\)", re.DOTALL), + "tmpl": "<eq>{0}</eq>", + "tag": "\\(", + } + ], + "block": [ + { + "name": "math_block_eqno", + "rex": re.compile( + r"^\\\[(((?!\\\]|\\\[)[\s\S])+?)\\\]\s*?\(([^)$\r\n]+?)\)", re.M + ), + "tmpl": '<section class="eqno"><eqn>{0}</eqn><span>({1})</span></section>', + "tag": "\\[", + }, + { + "name": "math_block", + "rex": re.compile(r"^\\\[([\s\S]+?)\\\]", re.M), + "tmpl": "<section>\n<eqn>{0}</eqn>\n</section>\n", + "tag": "\\[", + }, + ], + }, + "gitlab": { + "inline": [ + { + "name": "math_inline", + "rex": re.compile(r"^\$`(.+?)`\$"), + "tmpl": "<eq>{0}</eq>", + "tag": "$`", + } + ], + "block": [ + { + "name": "math_block_eqno", + "rex": re.compile( + r"^`{3}math\s+?([^`]+?)\s+?`{3}\s*?\(([^)$\r\n]+?)\)", re.M + ), + "tmpl": '<section class="eqno">\n<eqn>{0}</eqn><span>({1})</span>\n</section>\n', # noqa: E501 + "tag": "```math", + }, + { + "name": "math_block", + "rex": re.compile(r"^`{3}math\s+?([^`]+?)\s+?`{3}", re.M), + "tmpl": "<section>\n<eqn>{0}</eqn>\n</section>\n", + "tag": "```math", + }, + ], + }, + "julia": { + "inline": [ + { + "name": "math_inline", + "rex": re.compile(r"^`{2}([^`]+?)`{2}"), + "tmpl": "<eq>{0}</eq>", + "tag": "``", + }, + { + "name": "math_inline", + "rex": re.compile(r"^\$(\S[^$\r\n]*?[^\s\\]{1}?)\$"), + "tmpl": "<eq>{0}</eq>", + "tag": "$", + "pre": dollar_pre, + "post": dollar_post, + }, + { + "name": "math_single", + "rex": re.compile(r"^\$([^$\s\\]{1}?)\$"), + "tmpl": "<eq>{0}</eq>", + "tag": "$", + "pre": dollar_pre, + "post": dollar_post, + }, + ], + "block": [ + { + "name": "math_block_eqno", + "rex": re.compile( + r"^`{3}math\s+?([^`]+?)\s+?`{3}\s*?\(([^)$\r\n]+?)\)", re.M + ), + "tmpl": '<section class="eqno"><eqn>{0}</eqn><span>({1})</span></section>', + "tag": "```math", + }, + { + "name": "math_block", + "rex": re.compile(r"^`{3}math\s+?([^`]+?)\s+?`{3}", re.M), + "tmpl": "<section><eqn>{0}</eqn></section>", + "tag": "```math", + }, + ], + }, + "kramdown": { + "inline": [ + { + "name": "math_inline", + "rex": re.compile(r"^\${2}([^$\r\n]*?)\${2}"), + "tmpl": "<eq>{0}</eq>", + "tag": "$$", + } + ], + "block": [ + { + "name": "math_block_eqno", + "rex": re.compile(r"^\${2}([^$]*?)\${2}\s*?\(([^)$\r\n]+?)\)", re.M), + "tmpl": '<section class="eqno"><eqn>{0}</eqn><span>({1})</span></section>', + "tag": "$$", + }, + { + "name": "math_block", + "rex": re.compile(r"^\${2}([^$]*?)\${2}", re.M), + "tmpl": "<section><eqn>{0}</eqn></section>", + "tag": "$$", + }, + ], + }, + "dollars": { + "inline": [ + { + "name": "math_inline", + "rex": re.compile(r"^\$(\S[^$]*?[^\s\\]{1}?)\$"), + "tmpl": "<eq>{0}</eq>", + "tag": "$", + "pre": dollar_pre, + "post": dollar_post, + }, + { + "name": "math_single", + "rex": re.compile(r"^\$([^$\s\\]{1}?)\$"), + "tmpl": "<eq>{0}</eq>", + "tag": "$", + "pre": dollar_pre, + "post": dollar_post, + }, + ], + "block": [ + { + "name": "math_block_eqno", + "rex": re.compile(r"^\${2}([^$]*?)\${2}\s*?\(([^)$\r\n]+?)\)", re.M), + "tmpl": '<section class="eqno">\n<eqn>{0}</eqn><span>({1})</span>\n</section>\n', # noqa: E501 + "tag": "$$", + }, + { + "name": "math_block", + "rex": re.compile(r"^\${2}([^$]*?)\${2}", re.M), + "tmpl": "<section>\n<eqn>{0}</eqn>\n</section>\n", + "tag": "$$", + }, + ], + }, +} diff --git a/mdit_py_plugins/texmath/port.yaml b/mdit_py_plugins/texmath/port.yaml new file mode 100644 index 0000000..ba47ac8 --- /dev/null +++ b/mdit_py_plugins/texmath/port.yaml @@ -0,0 +1,7 @@ +- package: markdown-it-texmath + commit: 78c548829ce2ef85c73dc71e680d01e5ae41ffbf + date: Oct 4, 2019 + version: 0.6 + changes: | + both dollars/math_inline and brackets/math_inline regexes have been changed, + to allow (single) line breaks |