diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2018-03-02 22:52:39 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2018-05-17 00:42:22 +0900 |
commit | e675ad2ec91407d516a51304f6bd7fd683f2371c (patch) | |
tree | d33c289de66b22d0e9c5ea133afc3b15e8f91712 | |
parent | 4e04bff4f50bc382251437d5faafff9c34c492cb (diff) | |
download | sphinx-git-e675ad2ec91407d516a51304f6bd7fd683f2371c.tar.gz |
Enable math_block node rendering by default (without HTML builders)
-rw-r--r-- | CHANGES | 1 | ||||
-rw-r--r-- | doc/extdev/index.rst | 5 | ||||
-rw-r--r-- | sphinx/addnodes.py | 25 | ||||
-rw-r--r-- | sphinx/config.py | 1 | ||||
-rw-r--r-- | sphinx/directives/patches.py | 59 | ||||
-rw-r--r-- | sphinx/ext/imgmath.py | 15 | ||||
-rw-r--r-- | sphinx/ext/jsmath.py | 4 | ||||
-rw-r--r-- | sphinx/ext/mathbase.py | 130 | ||||
-rw-r--r-- | sphinx/ext/mathjax.py | 4 | ||||
-rw-r--r-- | sphinx/transforms/post_transforms/compat.py | 34 | ||||
-rw-r--r-- | sphinx/writers/latex.py | 21 | ||||
-rw-r--r-- | sphinx/writers/manpage.py | 11 | ||||
-rw-r--r-- | sphinx/writers/texinfo.py | 7 | ||||
-rw-r--r-- | sphinx/writers/text.py | 12 | ||||
-rw-r--r-- | tests/roots/test-ext-math-compat/conf.py | 10 | ||||
-rw-r--r-- | tests/roots/test-ext-math-compat/index.rst | 6 | ||||
-rw-r--r-- | tests/test_ext_math.py | 7 |
17 files changed, 187 insertions, 165 deletions
@@ -73,6 +73,7 @@ Deprecated * ``BuildEnvironment.dumps()`` is deprecated * ``BuildEnvironment.topickle()`` is deprecated * ``sphinx.ext.mathbase.math`` node is deprecated +* ``sphinx.ext.mathbase.displaymath`` node is deprecated * ``sphinx.ext.mathbase.is_in_section_title()`` is deprecated For more details, see `deprecation APIs list diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index 08de4b095..17effd7bd 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -136,6 +136,11 @@ The following is a list of deprecated interface. - 3.0 - ``docutils.nodes.math`` + * - ``sphinx.ext.mathbase.displaymath`` (node) + - 1.8 + - 3.0 + - ``docutils.nodes.math_block`` + * - ``viewcode_import`` (config value) - 1.8 - 3.0 diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 56f23bba3..37e54cfc7 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -187,7 +187,7 @@ class production(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a single grammar production rule.""" -# math node +# math nodes class math(nodes.math): @@ -208,6 +208,29 @@ class math(nodes.math): return nodes.math.__getitem__(self, key) +class math_block(nodes.math_block): + """Node for block level equations. + + .. deprecated:: 1.8 + """ + + def __getitem__(self, key): + if key == 'latex' and 'latex' not in self.attributes: + warnings.warn("displaymath node for Sphinx was replaced by docutils'. " + "Therefore please use ``node.astext()`` to get an equation instead.", + RemovedInSphinx30Warning) + return self.astext() + else: + return nodes.math_block.__getitem__(self, key) + + +class displaymath(math_block): + """Node for block level equations. + + .. deprecated:: 1.8 + """ + + # other directive-level nodes class index(nodes.Invisible, nodes.Inline, nodes.TextElement): diff --git a/sphinx/config.py b/sphinx/config.py index 1184f1891..74b97cbeb 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -139,6 +139,7 @@ class Config(object): numfig_secnum_depth = (1, 'env', []), numfig_format = ({}, 'env', []), # will be initialized in init_numfig_format() + math_number_all = (False, 'env', []), tls_verify = (True, 'env', []), tls_cacerts = (None, 'env', []), smartquotes = (True, 'env', []), diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 00be5584d..f84f082bc 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -8,6 +8,7 @@ """ from docutils import nodes +from docutils.nodes import make_id from docutils.parsers.rst import directives from docutils.parsers.rst.directives import images, html, tables @@ -105,6 +106,63 @@ class ListTable(tables.ListTable): return title, message +class MathDirective(SphinxDirective): + + has_content = True + required_arguments = 0 + optional_arguments = 1 + final_argument_whitespace = True + option_spec = { + 'label': directives.unchanged, + 'name': directives.unchanged, + 'nowrap': directives.flag, + } + + def run(self): + # type: () -> List[nodes.Node] + latex = '\n'.join(self.content) + if self.arguments and self.arguments[0]: + latex = self.arguments[0] + '\n\n' + latex + node = nodes.math_block(latex, latex, + docname=self.state.document.settings.env.docname, + number=self.options.get('name'), + label=self.options.get('label'), + nowrap='nowrap' in self.options) + ret = [node] + set_source_info(self, node) + if hasattr(self, 'src'): + node.source = self.src + self.add_target(ret) + return ret + + def add_target(self, ret): + # type: (List[nodes.Node]) -> None + node = ret[0] + + # assign label automatically if math_number_all enabled + if node['label'] == '' or (self.config.math_number_all and not node['label']): + seq = self.env.new_serialno('sphinx.ext.math#equations') + node['label'] = "%s:%d" % (self.env.docname, seq) + + # no targets and numbers are needed + if not node['label']: + return + + # register label to domain + domain = self.env.get_domain('math') + try: + eqno = domain.add_equation(self.env, self.env.docname, node['label']) # type: ignore # NOQA + node['number'] = eqno + + # add target node + node_id = make_id('equation-%s' % node['label']) + target = nodes.target('', '', ids=[node_id]) + self.state.document.note_explicit_target(target) + ret.insert(0, target) + except UserWarning as exc: + self.state_machine.reporter.warning(exc.args[0], line=self.lineno) + + def setup(app): # type: (Sphinx) -> Dict directives.register_directive('figure', Figure) @@ -112,6 +170,7 @@ def setup(app): directives.register_directive('table', RSTTable) directives.register_directive('csv-table', CSVTable) directives.register_directive('list-table', ListTable) + directives.register_directive('math', MathDirective) return { 'version': 'builtin', diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 0e43abc74..0cdc9aba4 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -287,10 +287,7 @@ def cleanup_tempdir(app, exc): def get_tooltip(self, node): # type: (nodes.NodeVisitor, nodes.math) -> unicode if self.builder.config.imgmath_add_tooltips: - if len(node) == 1: - return ' alt="%s"' % self.encode(node.astext()).strip() - else: - return ' alt="%s"' % self.encode(node['latex']).strip() + return ' alt="%s"' % self.encode(node.astext()).strip() return '' @@ -320,18 +317,18 @@ def html_visit_math(self, node): def html_visit_displaymath(self, node): # type: (nodes.NodeVisitor, displaymath) -> None if node['nowrap']: - latex = node['latex'] + latex = node.astext() else: - latex = wrap_displaymath(node['latex'], None, + latex = wrap_displaymath(node.astext(), None, self.builder.config.math_number_all) try: fname, depth = render_math(self, latex) except MathExtError as exc: msg = text_type(exc) sm = nodes.system_message(msg, type='WARNING', level=2, - backrefs=[], source=node['latex']) + backrefs=[], source=node.astext()) sm.walkabout(self) - logger.warning(__('inline latex %r: %s'), node['latex'], msg) + logger.warning(__('inline latex %r: %s'), node.astext(), msg) raise nodes.SkipNode self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('<p>') @@ -343,7 +340,7 @@ def html_visit_displaymath(self, node): if fname is None: # something failed -- use text-only as a bad substitute self.body.append('<span class="math">%s</span></p>\n</div>' % - self.encode(node['latex']).strip()) + self.encode(node.astext()).strip()) else: self.body.append(('<img src="%s"' % fname) + get_tooltip(self, node) + '/></p>\n</div>') diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index fa9eb7913..7381da42b 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -35,10 +35,10 @@ def html_visit_displaymath(self, node): # type: (nodes.NodeVisitor, nodes.Node) -> None if node['nowrap']: self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight')) - self.body.append(self.encode(node['latex'])) + self.body.append(self.encode(node.astext())) self.body.append('</div>') raise nodes.SkipNode - for i, part in enumerate(node['latex'].split('\n\n')): + for i, part in enumerate(node.astext().split('\n\n')): part = self.encode(part) if i == 0: # necessary to e.g. set the id property correctly diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index d40d461c2..89c6e9286 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -13,22 +13,19 @@ import warnings from docutils import nodes from docutils.nodes import make_id -from docutils.parsers.rst import directives -from sphinx.addnodes import math +from sphinx.addnodes import math, math_block as displaymath from sphinx.config import string_classes from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.domains import Domain from sphinx.locale import __ from sphinx.roles import XRefRole from sphinx.util import logging -from sphinx.util.docutils import SphinxDirective -from sphinx.util.nodes import make_refnode, set_source_info +from sphinx.util.nodes import make_refnode if False: # For type annotation from typing import Any, Callable, Dict, Iterable, List, Tuple # NOQA - from docutils.parsers.rst.states import Inliner # NOQA from docutils.writers.html4css1 import Writer # NOQA from sphinx.application import Sphinx # NOQA from sphinx.builders import Builder # NOQA @@ -37,10 +34,6 @@ if False: logger = logging.getLogger(__name__) -class displaymath(nodes.Part, nodes.Element): - pass - - class eqref(nodes.Inline, nodes.TextElement): pass @@ -65,6 +58,7 @@ class MathDomain(Domain): } enumerable_nodes = { # node_class -> (figtype, title_getter) displaymath: ('displaymath', None), + nodes.math_block: ('displaymath', None), } # type: Dict[nodes.Node, Tuple[unicode, Callable]] def clear_doc(self, docname): @@ -210,85 +204,6 @@ def is_in_section_title(node): return False -class MathDirective(SphinxDirective): - - has_content = True - required_arguments = 0 - optional_arguments = 1 - final_argument_whitespace = True - option_spec = { - 'label': directives.unchanged, - 'name': directives.unchanged, - 'nowrap': directives.flag, - } - - def run(self): - # type: () -> List[nodes.Node] - latex = '\n'.join(self.content) - if self.arguments and self.arguments[0]: - latex = self.arguments[0] + '\n\n' + latex - node = displaymath() - node['latex'] = latex - node['number'] = None - node['label'] = None - if 'name' in self.options: - node['label'] = self.options['name'] - if 'label' in self.options: - node['label'] = self.options['label'] - node['nowrap'] = 'nowrap' in self.options - node['docname'] = self.env.docname - ret = [node] - set_source_info(self, node) - if hasattr(self, 'src'): - node.source = self.src - self.add_target(ret) - return ret - - def add_target(self, ret): - # type: (List[nodes.Node]) -> None - node = ret[0] - - # assign label automatically if math_number_all enabled - if node['label'] == '' or (self.config.math_number_all and not node['label']): - seq = self.env.new_serialno('sphinx.ext.math#equations') - node['label'] = "%s:%d" % (self.env.docname, seq) - - # no targets and numbers are needed - if not node['label']: - return - - # register label to domain - domain = self.env.get_domain('math') - try: - eqno = domain.add_equation(self.env, self.env.docname, node['label']) # type: ignore # NOQA - node['number'] = eqno - - # add target node - node_id = make_id('equation-%s' % node['label']) - target = nodes.target('', '', ids=[node_id]) - self.state.document.note_explicit_target(target) - ret.insert(0, target) - except UserWarning as exc: - self.state_machine.reporter.warning(exc.args[0], line=self.lineno) - - -def latex_visit_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - if not node['label']: - label = None - else: - label = "equation:%s:%s" % (node['docname'], node['label']) - - if node['nowrap']: - if label: - self.body.append(r'\label{%s}' % label) - self.body.append(node['latex']) - else: - self.body.append(wrap_displaymath(node['latex'], label, - self.builder.config.math_number_all)) - raise nodes.SkipNode - - def latex_visit_eqref(self, node): # type: (nodes.NodeVisitor, eqref) -> None label = "equation:%s:%s" % (node['docname'], node['target']) @@ -306,51 +221,14 @@ def latex_visit_eqref(self, node): raise nodes.SkipNode -def text_visit_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - self.new_state() - self.add_text(node['latex']) - self.end_state() - raise nodes.SkipNode - - -def man_visit_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - self.visit_centered(node) - - -def man_depart_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - self.depart_centered(node) - - -def texinfo_visit_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - if node.get('label'): - self.add_anchor(node['label'], node) - self.body.append('\n\n@example\n%s\n@end example\n\n' % - self.escape_arg(node['latex'])) - - -def texinfo_depart_displaymath(self, node): - # type: (nodes.NodeVisitor, displaymath) -> None - pass - - def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): # type: (Sphinx, Tuple[Callable, Any], Tuple[Callable, Any]) -> None - app.add_config_value('math_number_all', False, 'env') app.add_config_value('math_eqref_format', None, 'env', string_classes) app.add_config_value('math_numfig', True, 'env') app.add_domain(MathDomain) app.add_node(math, override=True, html=htmlinlinevisitors) - app.add_node(displaymath, - latex=(latex_visit_displaymath, None), - text=(text_visit_displaymath, None), - man=(man_visit_displaymath, man_depart_displaymath), - texinfo=(texinfo_visit_displaymath, texinfo_depart_displaymath), + app.add_node(displaymath, override=True, html=htmldisplayvisitors) app.add_node(eqref, latex=(latex_visit_eqref, None)) app.add_role('eq', EqXRefRole(warn_dangling=True)) - app.add_directive('math', MathDirective) diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index f6566a583..39fbb8539 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -38,7 +38,7 @@ def html_visit_displaymath(self, node): # type: (nodes.NodeVisitor, nodes.Node) -> None self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight')) if node['nowrap']: - self.body.append(self.encode(node['latex'])) + self.body.append(self.encode(node.astext())) self.body.append('</div>') raise nodes.SkipNode @@ -49,7 +49,7 @@ def html_visit_displaymath(self, node): self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('</span>') self.body.append(self.builder.config.mathjax_display[0]) - parts = [prt for prt in node['latex'].split('\n\n') if prt.strip()] + parts = [prt for prt in node.astext().split('\n\n') if prt.strip()] if len(parts) > 1: # Add alignment if there are more than 1 equation self.body.append(r' \begin{align}\begin{aligned}') for i, part in enumerate(parts): diff --git a/sphinx/transforms/post_transforms/compat.py b/sphinx/transforms/post_transforms/compat.py index 0f0b2367d..94360f038 100644 --- a/sphinx/transforms/post_transforms/compat.py +++ b/sphinx/transforms/post_transforms/compat.py @@ -13,7 +13,9 @@ import warnings from typing import TYPE_CHECKING from docutils import nodes +from docutils.writers.docutils_xml import XMLTranslator +from sphinx.addnodes import math_block, displaymath from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.transforms import SphinxTransform from sphinx.util import logging @@ -41,14 +43,44 @@ class MathNodeMigrator(SphinxTransform): def apply(self): # type: () -> None for node in self.document.traverse(nodes.math): + # case: old styled ``math`` node generated by old extensions if len(node) == 0: - # convert an old styled node to new one warnings.warn("math node for Sphinx was replaced by docutils'. " "Please use ``docutils.nodes.math`` instead.", RemovedInSphinx30Warning) equation = node['latex'] node += nodes.Text(equation, equation) + translator = self.app.builder.get_translator_class() + if hasattr(translator, 'visit_displaymath') and translator != XMLTranslator: + # case: old translators which does not support ``math_block`` node + warnings.warn("Translator for %s does not support math_block node'. " + "Please update your extension." % translator, + RemovedInSphinx30Warning) + for node in self.document.traverse(math_block): + alt = displaymath(latex=node.astext(), + number=node.get('number'), + label=node.get('label'), + nowrap=node.get('nowrap'), + docname=node.get('docname')) + node.replace(alt) + else: + # case: old styled ``displaymath`` node generated by old extensions + for node in self.document.traverse(math_block): + if len(node) == 0: + warnings.warn("math node for Sphinx was replaced by docutils'. " + "Please use ``docutils.nodes.math_block`` instead.", + RemovedInSphinx30Warning) + latex = node['latex'] + node += nodes.Text(latex, latex) + def setup(app): + # type: (Sphinx) -> Dict[unicode, Any] app.add_post_transform(MathNodeMigrator) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 15f72566b..d4abacd38 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2549,10 +2549,23 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_math_block(self, node): # type: (nodes.Node) -> None - logger.warning(__('using "math" markup without a Sphinx math extension ' - 'active, please use one of the math extensions ' - 'described at http://sphinx-doc.org/en/master/ext/math.html'), - location=(self.curfilestack[-1], node.line)) + if node.get('label'): + label = "equation:%s:%s" % (node['docname'], node['label']) + else: + label = None + + if node.get('nowrap'): + if label: + self.body.append(r'\label{%s}' % label) + self.body.append(node.astext()) + else: + def is_equation(part): + # type: (unicode) -> unicode + return part.strip() + + from sphinx.ext.mathbase import wrap_displaymath + self.body.append(wrap_displaymath(node.astext(), label, + self.builder.config.math_number_all)) raise nodes.SkipNode def unknown_visit(self, node): diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 1f49ced9e..02540a53d 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -18,7 +18,7 @@ from docutils.writers.manpage import ( import sphinx.util.docutils from sphinx import addnodes -from sphinx.locale import admonitionlabels, _, __ +from sphinx.locale import admonitionlabels, _ from sphinx.util import logging from sphinx.util.i18n import format_date @@ -521,10 +521,11 @@ class ManualPageTranslator(BaseTranslator): def visit_math_block(self, node): # type: (nodes.Node) -> None - logger.warning(__('using "math" markup without a Sphinx math extension ' - 'active, please use one of the math extensions ' - 'described at http://sphinx-doc.org/en/master/ext/math.html')) - raise nodes.SkipNode + self.visit_centered(node) + + def depart_math_block(self, node): + # type: (nodes.Node) -> None + self.depart_centered(node) def unknown_visit(self, node): # type: (nodes.Node) -> None diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index 3b2dd8915..4f76c6cf9 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -1736,7 +1736,8 @@ class TexinfoTranslator(nodes.NodeVisitor): def visit_math_block(self, node): # type: (nodes.Node) -> None - logger.warning(__('using "math" markup without a Sphinx math extension ' - 'active, please use one of the math extensions ' - 'described at http://sphinx-doc.org/en/master/ext/math.html')) + if node.get('label'): + self.add_anchor(node['label'], node) + self.body.append('\n\n@example\n%s\n@end example\n\n' % + self.escape_arg(node.astext())) raise nodes.SkipNode diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index 677a10df3..0f9b45fbe 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -18,7 +18,7 @@ from docutils.utils import column_width from six.moves import zip_longest from sphinx import addnodes -from sphinx.locale import admonitionlabels, _, __ +from sphinx.locale import admonitionlabels, _ from sphinx.util import logging if False: @@ -1187,11 +1187,11 @@ class TextTranslator(nodes.NodeVisitor): def visit_math_block(self, node): # type: (nodes.Node) -> None - logger.warning(__('using "math" markup without a Sphinx math extension ' - 'active, please use one of the math extensions ' - 'described at http://sphinx-doc.org/en/master/ext/math.html'), - location=(self.builder.current_docname, node.line)) - raise nodes.SkipNode + self.new_state() + + def depart_math_block(self, node): + # type: (nodes.Node) -> None + self.end_state() def unknown_visit(self, node): # type: (nodes.Node) -> None diff --git a/tests/roots/test-ext-math-compat/conf.py b/tests/roots/test-ext-math-compat/conf.py index fc3b3d0b6..c4f6005ea 100644 --- a/tests/roots/test-ext-math-compat/conf.py +++ b/tests/roots/test-ext-math-compat/conf.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- -from sphinx.ext.mathbase import math +from docutils.parsers.rst import Directive + +from sphinx.ext.mathbase import math, displaymath master_doc = 'index' extensions = ['sphinx.ext.mathjax'] @@ -10,5 +12,11 @@ def my_math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): return [math(latex='E = mc^2')], [] +class MyMathDirective(Directive): + def run(self): + return [displaymath(latex='E = mc^2')] + + def setup(app): app.add_role('my_math', my_math_role) + app.add_directive('my-math', MyMathDirective) diff --git a/tests/roots/test-ext-math-compat/index.rst b/tests/roots/test-ext-math-compat/index.rst index d5fc071f1..208878c36 100644 --- a/tests/roots/test-ext-math-compat/index.rst +++ b/tests/roots/test-ext-math-compat/index.rst @@ -18,8 +18,4 @@ Second math Multi math equations -.. math:: - - S &= \pi r^2 - - V &= \frac{4}{3} \pi r^3 +.. my-math:: diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index d3580e986..47465f07e 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -230,3 +230,10 @@ def test_math_compat(app, status, warning): [nodes.math, "E=mc^2"], '\nInline my math: ', [nodes.math, "E = mc^2"])) + assert_node(doctree[0][2], + ([nodes.title, "block"], + [nodes.math_block, "a^2+b^2=c^2\n\n"], + [nodes.paragraph, "Second math"], + [nodes.math_block, "e^{i\\pi}+1=0\n\n"], + [nodes.paragraph, "Multi math equations"], + [nodes.math_block, "E = mc^2"])) |