From a10f882cef6f34c3aa0add9f4a0ce1b4de8486e1 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Wed, 26 Aug 2020 23:45:27 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=8C=20IMPROVE:=20How=20mathjax=20is=20?= =?UTF-8?q?overriden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only override if we have to, and override in a more precise manner. --- myst_parser/__init__.py | 28 +------ myst_parser/mathjax.py | 83 +++++++++++++++++++ myst_parser/myst_amsmath.py | 59 ------------- .../test_extended_syntaxes.html | 7 +- 4 files changed, 89 insertions(+), 88 deletions(-) create mode 100644 myst_parser/mathjax.py delete mode 100644 myst_parser/myst_amsmath.py diff --git a/myst_parser/__init__.py b/myst_parser/__init__.py index 8c819f91..27e88cfa 100644 --- a/myst_parser/__init__.py +++ b/myst_parser/__init__.py @@ -18,17 +18,17 @@ def setup_sphinx(app): # we do this separately to setup, # so that it can be called by external packages like myst_nb from myst_parser.myst_refs import MystReferenceResolver - from myst_parser.myst_amsmath import MystAmsMathTransform + from myst_parser.mathjax import override_mathjax from myst_parser.main import MdParserConfig app.add_post_transform(MystReferenceResolver) - app.add_post_transform(MystAmsMathTransform) for name, default in MdParserConfig().as_dict().items(): if not name == "renderer": app.add_config_value(f"myst_{name}", default, "env") app.connect("builder-inited", create_myst_config) + app.connect("builder-inited", override_mathjax) def create_myst_config(app): @@ -50,27 +50,3 @@ def create_myst_config(app): except (TypeError, ValueError) as error: logger.error("myst configuration invalid: %s", error.args[0]) app.env.myst_config = MdParserConfig() - - # https://docs.mathjax.org/en/v2.7-latest/options/preprocessors/tex2jax.html#configure-tex2jax - if app.config.mathjax_config is None and app.env.myst_config.update_mathjax: - app.config.mathjax_config = { - "tex2jax": { - "inlineMath": [["\\(", "\\)"]], - "displayMath": [["\\[", "\\]"]], - "processRefs": False, - "processEnvironments": False, - } - } - elif app.env.myst_config.update_mathjax: - if "tex2jax" in app.config.mathjax_config: - logger.warning( - "`mathjax_config['tex2jax']` is set, but `myst_update_mathjax = True`, " - "and so this will be overridden. " - "Set `myst_update_mathjax = False` if you wish to use your own config" - ) - app.config.mathjax_config["tex2jax"] = { - "inlineMath": [["\\(", "\\)"]], - "displayMath": [["\\[", "\\]"]], - "processRefs": False, - "processEnvironments": False, - } diff --git a/myst_parser/mathjax.py b/myst_parser/mathjax.py new file mode 100644 index 00000000..383f792a --- /dev/null +++ b/myst_parser/mathjax.py @@ -0,0 +1,83 @@ +"""Overrides to ``sphinx.ext.mathjax`` + +This fixes two issues: + +1. Mathjax should not search for ``$`` delimiters, nor LaTeX amsmath environments, + since we already achieve this with the dollarmath and amsmath mrakdown-it-py plugins +2. amsmath math blocks should be wrapped in mathjax delimiters (default ``\\[...\\]``), + and assigned an equation number + +""" +from docutils import nodes + +from sphinx.application import Sphinx +from sphinx.ext import mathjax +from sphinx.locale import _ +from sphinx.util import logging +from sphinx.util.math import get_node_equation_number +from sphinx.writers.html import HTMLTranslator + +logger = logging.getLogger(__name__) + + +def override_mathjax(app: Sphinx): + """Override aspects of the mathjax extension, but only if necessary.""" + + if ( + app.config["myst_amsmath_enable"] + and "mathjax" in app.registry.html_block_math_renderers + ): + app.registry.html_block_math_renderers["mathjax"] = ( + html_visit_displaymath, + None, + ) + # https://docs.mathjax.org/en/v2.7-latest/options/preprocessors/tex2jax.html#configure-tex2jax + if app.config.mathjax_config is None and app.env.myst_config.update_mathjax: + app.config.mathjax_config = { + "tex2jax": { + "inlineMath": [["\\(", "\\)"]], + "displayMath": [["\\[", "\\]"]], + "processRefs": False, + "processEnvironments": False, + } + } + elif app.env.myst_config.update_mathjax: + if "tex2jax" in app.config.mathjax_config: + logger.warning( + "`mathjax_config['tex2jax']` is set, but `myst_update_mathjax = True`, " + "and so this will be overridden. " + "Set `myst_update_mathjax = False` if you wish to use your own config" + ) + app.config.mathjax_config["tex2jax"] = { + "inlineMath": [["\\(", "\\)"]], + "displayMath": [["\\[", "\\]"]], + "processRefs": False, + "processEnvironments": False, + } + + +def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None: + """Override for sphinx.ext.mathjax.html_visit_displaymath to handle amsmath. + + By default displaymath, are normally wrapped in a prefix/suffix, + defined by mathjax_display, and labelled nodes are numbered. + However, this is not the case if the math_block is set as 'nowrap', as for amsmath. + Therefore, we need to override this behaviour. + """ + if "amsmath" in node.get("classes", []): + self.body.append( + self.starttag(node, "div", CLASS="math notranslate nohighlight amsmath") + ) + if node["number"]: + number = get_node_equation_number(self, node) + self.body.append('(%s)' % number) + self.add_permalink_ref(node, _("Permalink to this equation")) + self.body.append("") + prefix, suffix = self.builder.config.mathjax_display + self.body.append(prefix) + self.body.append(self.encode(node.astext())) + self.body.append(suffix) + self.body.append("\n") + raise nodes.SkipNode + + return mathjax.html_visit_displaymath(self, node) diff --git a/myst_parser/myst_amsmath.py b/myst_parser/myst_amsmath.py deleted file mode 100644 index 6100cc70..00000000 --- a/myst_parser/myst_amsmath.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Any - -from docutils import nodes - -from sphinx.transforms.post_transforms import SphinxPostTransform -from sphinx.util.nodes import NodeMatcher - - -class MystAmsMathTransform(SphinxPostTransform): - """For the default mathjax renderer, - math_blocks are normally wrapped in a prefix/suffix defined by mathjax_display, - and labeled nodes are numbered. - However, this is not the case if the math_block is set as nowrap, - as set for amsmath. - Therefore, we need to do this independently. - """ - - default_priority = 400 - - def run(self, **kwargs: Any) -> None: - if "html" not in self.app.builder.name and self.app.builder.name not in ( - "readthedocs", - ): - return - if self.app.builder.math_renderer_name != "mathjax": - return - matcher = NodeMatcher(nodes.math_block, classes=["amsmath"]) - for node in self.document.traverse(matcher): # type: nodes.math_block - prefix, suffix = self.config.mathjax_display - node.children[0] = nodes.Text(prefix + str(node.children[0]) + suffix) - replace = [] - if node["number"]: - number = get_node_equation_number(self, node) - replace.append( - nodes.raw( - "", f'({number})', format="html" - ) - ) - # TODO add permalink (see sphinx/ext/mathjax.py) - # self.add_permalink_ref(node, _('Permalink to this equation')) - replace.append(node) - node.replace_self(replace) - - -def get_node_equation_number(tr: SphinxPostTransform, node: nodes.math_block) -> str: - """Adapted from sphinx/util/math.py""" - if tr.config.math_numfig and tr.config.numfig: - figtype = "displaymath" - if tr.app.builder.name == "singlehtml": - # TODO is this the right docname? - key = "%s/%s" % (tr.app.env.docname, figtype) - else: - key = figtype - - id = node["ids"][0] - number = tr.app.builder.fignumbers.get(key, {}).get(id, ()) - return ".".join(map(str, number)) - else: - return node["number"] diff --git a/tests/test_sphinx/test_sphinx_builds/test_extended_syntaxes.html b/tests/test_sphinx/test_sphinx_builds/test_extended_syntaxes.html index adaf982c..09de3296 100644 --- a/tests/test_sphinx/test_sphinx_builds/test_extended_syntaxes.html +++ b/tests/test_sphinx/test_sphinx_builds/test_extended_syntaxes.html @@ -31,12 +31,13 @@

$ a=1 $

-
+
(2) + + ΒΆ + -
-
\[\begin{equation} b=2 \end{equation}\]