diff --git a/CHANGES b/CHANGES index ae81277c1..3023ee8c0 100644 --- a/CHANGES +++ b/CHANGES @@ -49,6 +49,7 @@ Features added * HTML themes can set up default sidebars through ``theme.conf`` * #3160: html: Use ```` to represent ``:kbd:`` role * #4212: autosummary: catch all exceptions when importing modules +* #3991, #4080: Add :confval:`math_numfig` for equation numbering by section Features removed diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 66c24e902..10a26ccf4 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -44,6 +44,16 @@ or use Python raw strings (``r"raw"``). Example: ``'Eq.{number}'`` is rendered as ``Eq.10`` +.. confval:: math_numfig + + If ``True``, displayed math equations are numbered across pages in html and + related (epub, ...) output when :confval:`numfig` is enabled. + :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` role must + be used to reference equation numbers, not the :rst:role:`numref` role. + Default is ``True``. + + .. versionadded:: 1.7 + :mod:`.mathbase` defines these new markup elements: .. rst:role:: math diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 8bf4fcad5..a8a7f5d8c 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -30,6 +30,7 @@ from sphinx.util.png import read_png_depth, write_png_depth from sphinx.util.osutil import ensuredir, ENOENT, cd from sphinx.util.pycompat import sys_encoding from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath +from sphinx.ext.mathbase import get_node_equation_number if False: # For type annotation @@ -333,7 +334,8 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - self.body.append('(%s)' % 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('') if fname is None: diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index dc57c13c6..3c31b0a02 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -16,6 +16,7 @@ import sphinx from sphinx.locale import _ from sphinx.application import ExtensionError from sphinx.ext.mathbase import setup_math as mathbase_setup +from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): @@ -35,7 +36,8 @@ def html_visit_displaymath(self, node): if i == 0: # necessary to e.g. set the id property correctly if node['number']: - self.body.append('(%s)' % 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('') self.body.append(self.starttag(node, 'div', CLASS='math')) diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index f83ca5da8..50c4b157f 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -84,6 +84,13 @@ class MathDomain(Domain): newnode['target'] = target return newnode else: + if env.config.math_numfig and env.config.numfig: + if docname in env.toc_fignumbers: + id = 'equation-' + target + number = env.toc_fignumbers[docname]['displaymath'].get(id, ()) + number = '.'.join(map(str, number)) + else: + number = '' try: eqref_format = env.config.math_eqref_format or "({number})" title = nodes.Text(eqref_format.format(number=number)) @@ -126,6 +133,23 @@ class MathDomain(Domain): return len(targets) + 1 +def get_node_equation_number(writer, node): + if writer.builder.config.math_numfig and writer.builder.config.numfig: + figtype = 'displaymath' + if writer.builder.name == 'singlehtml': + key = u"%s/%s" % (writer.docnames[-1], figtype) + else: + key = figtype + + id = node['ids'][0] + number = writer.builder.fignumbers.get(key, {}).get(id, ()) + number = '.'.join(map(str, number)) + else: + number = node['number'] + + return number + + def wrap_displaymath(math, label, numbering): # type: (unicode, unicode, bool) -> unicode def is_equation(part): @@ -341,6 +365,7 @@ 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, latex=(latex_visit_math, None), @@ -348,12 +373,12 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): man=(man_visit_math, None), texinfo=(texinfo_visit_math, None), 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), - html=htmldisplayvisitors) + app.add_enumerable_node(displaymath, '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), + html=htmldisplayvisitors) app.add_node(eqref, latex=(latex_visit_eqref, None)) app.add_role('math', math_role) app.add_role('eq', EqXRefRole(warn_dangling=True)) diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index f25f91e74..8b7e700ac 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -17,6 +17,7 @@ import sphinx from sphinx.locale import _ from sphinx.errors import ExtensionError from sphinx.ext.mathbase import setup_math as mathbase_setup +from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): @@ -36,7 +37,8 @@ def html_visit_displaymath(self, node): # necessary to e.g. set the id property correctly if node['number']: - self.body.append('(%s)' % 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('') self.body.append(self.builder.config.mathjax_display[0]) diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py index 85010b799..499f37e79 100644 --- a/sphinx/ext/pngmath.py +++ b/sphinx/ext/pngmath.py @@ -30,6 +30,7 @@ from sphinx.util.png import read_png_depth, write_png_depth from sphinx.util.osutil import ensuredir, ENOENT, cd from sphinx.util.pycompat import sys_encoding from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath +from sphinx.ext.mathbase import get_node_equation_number if False: # For type annotation @@ -242,7 +243,8 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - self.body.append('(%s)' % node['number']) + number = get_node_equation_number(self, node) + self.body.append('(%s)' % number) if fname is None: # something failed -- use text-only as a bad substitute self.body.append('%s

\n' % diff --git a/tests/roots/test-ext-math/index.rst b/tests/roots/test-ext-math/index.rst index 9d16824f6..4237b73ff 100644 --- a/tests/roots/test-ext-math/index.rst +++ b/tests/roots/test-ext-math/index.rst @@ -2,8 +2,10 @@ Test Math ========= .. toctree:: + :numbered: 1 math + page .. math:: a^2+b^2=c^2 diff --git a/tests/roots/test-ext-math/page.rst b/tests/roots/test-ext-math/page.rst new file mode 100644 index 000000000..ef8040910 --- /dev/null +++ b/tests/roots/test-ext-math/page.rst @@ -0,0 +1,9 @@ +Test multiple pages +=================== + +.. math:: + :label: bar + + a = b + 1 + +Referencing equations :eq:`foo` and :eq:`bar`. diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index 4d2fb9836..4819a4143 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -157,3 +157,52 @@ def test_math_eqref_format_latex(app, status, warning): content = (app.outdir / 'test.tex').text() macro = r'Referencing equation Eq.\\ref{equation:math:foo}.' assert re.search(macro, content, re.S) + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.mathjax'], + 'numfig': True, + 'math_numfig': True}) +def test_mathjax_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'math.html').text() + html = ('
\n' + '(1.2)') + assert html in content + html = ('

Referencing equation (1.1).

') + assert html in content + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.jsmath'], + 'jsmath_path': 'dummy.js', + 'numfig': True, + 'math_numfig': True}) +def test_jsmath_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'math.html').text() + html = '(1.2)Referencing equation (1.1).

') + assert html in content + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.imgmath'], + 'numfig': True, + 'numfig_secnum_depth': 0, + 'math_numfig': True}) +def test_imgmath_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'page.html').text() + html = '(3)Referencing equations (1) and ' + '(3).

') + assert html in content