Sphinx 8.1.3__py3-none-any.whl → 8.2.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +48 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +114 -57
- sphinx/domains/python/_object.py +151 -67
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +21 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +66 -0
- sphinx/ext/autodoc/__init__.py +829 -480
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +271 -143
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +61 -50
- sphinx/writers/latex.py +80 -65
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +44 -45
- sphinx/writers/text.py +48 -30
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/writers/html5.py
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import os
|
|
6
5
|
import posixpath
|
|
7
6
|
import re
|
|
8
7
|
import urllib.parse
|
|
9
|
-
from
|
|
10
|
-
from typing import TYPE_CHECKING, cast
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
11
9
|
|
|
12
10
|
from docutils import nodes
|
|
13
11
|
from docutils.writers.html5_polyglot import HTMLTranslator as BaseTranslator
|
|
@@ -44,9 +42,7 @@ def multiply_length(length: str, scale: int) -> str:
|
|
|
44
42
|
|
|
45
43
|
|
|
46
44
|
class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
47
|
-
"""
|
|
48
|
-
Our custom HTML translator.
|
|
49
|
-
"""
|
|
45
|
+
"""Our custom HTML translator."""
|
|
50
46
|
|
|
51
47
|
builder: StandaloneHTMLBuilder
|
|
52
48
|
# Override docutils.writers.html5_polyglot:HTMLTranslator
|
|
@@ -66,6 +62,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
66
62
|
self._table_row_indices = [0]
|
|
67
63
|
self._fieldlist_row_indices = [0]
|
|
68
64
|
self.required_params_left = 0
|
|
65
|
+
self._has_maths_elements: bool = False
|
|
69
66
|
|
|
70
67
|
def visit_start_of_file(self, node: Element) -> None:
|
|
71
68
|
# only occurs in the single-file builder
|
|
@@ -175,6 +172,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
175
172
|
self.required_params_left = sum(self.list_is_required_param)
|
|
176
173
|
self.param_separator = node.child_text_separator
|
|
177
174
|
self.multi_line_parameter_list = node.get('multi_line_parameter_list', False)
|
|
175
|
+
self.trailing_comma = node.get('multi_line_trailing_comma', False)
|
|
178
176
|
if self.multi_line_parameter_list:
|
|
179
177
|
self.body.append('\n\n')
|
|
180
178
|
self.body.append(self.starttag(node, 'dl'))
|
|
@@ -201,10 +199,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
201
199
|
|
|
202
200
|
# If required parameters are still to come, then put the comma after
|
|
203
201
|
# the parameter. Otherwise, put the comma before. This ensures that
|
|
204
|
-
# signatures like the following render correctly
|
|
202
|
+
# signatures like the following render correctly:
|
|
205
203
|
#
|
|
206
204
|
# foo([a, ]b, c[, d])
|
|
207
205
|
#
|
|
206
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/1001
|
|
208
207
|
def visit_desc_parameter(self, node: Element) -> None:
|
|
209
208
|
on_separate_line = self.multi_line_parameter_list
|
|
210
209
|
if on_separate_line and not (
|
|
@@ -232,14 +231,15 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
232
231
|
next_is_required = (
|
|
233
232
|
not is_last_group
|
|
234
233
|
and self.list_is_required_param[self.param_group_index + 1]
|
|
235
|
-
)
|
|
234
|
+
)
|
|
236
235
|
opt_param_left_at_level = self.params_left_at_level > 0
|
|
237
236
|
if (
|
|
238
237
|
opt_param_left_at_level
|
|
239
238
|
or is_required
|
|
240
239
|
and (is_last_group or next_is_required)
|
|
241
240
|
):
|
|
242
|
-
self.
|
|
241
|
+
if not is_last_group or opt_param_left_at_level or self.trailing_comma:
|
|
242
|
+
self.body.append(self.param_separator)
|
|
243
243
|
self.body.append('</dd>\n')
|
|
244
244
|
|
|
245
245
|
elif self.required_params_left:
|
|
@@ -282,19 +282,26 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
282
282
|
|
|
283
283
|
def depart_desc_optional(self, node: Element) -> None:
|
|
284
284
|
self.optional_param_level -= 1
|
|
285
|
+
level = self.optional_param_level
|
|
285
286
|
if self.multi_line_parameter_list:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
max_level = self.max_optional_param_level
|
|
288
|
+
len_lirp = len(self.list_is_required_param)
|
|
289
|
+
is_last_group = self.param_group_index + 1 == len_lirp
|
|
290
|
+
# If it's the first time we go down one level, add the separator before the
|
|
291
|
+
# bracket, except if this is the last parameter and the parameter list
|
|
292
|
+
# should not feature a trailing comma.
|
|
293
|
+
if level == max_level - 1 and (
|
|
294
|
+
not is_last_group or level > 0 or self.trailing_comma
|
|
295
|
+
):
|
|
289
296
|
self.body.append(self.param_separator)
|
|
290
297
|
self.body.append('<span class="optional">]</span>')
|
|
291
298
|
# End the line if we have just closed the last bracket of this
|
|
292
299
|
# optional parameter group.
|
|
293
|
-
if
|
|
300
|
+
if level == 0:
|
|
294
301
|
self.body.append('</dd>\n')
|
|
295
302
|
else:
|
|
296
303
|
self.body.append('<span class="optional">]</span>')
|
|
297
|
-
if
|
|
304
|
+
if level == 0:
|
|
298
305
|
self.param_group_index += 1
|
|
299
306
|
|
|
300
307
|
def visit_desc_annotation(self, node: Element) -> None:
|
|
@@ -327,9 +334,9 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
327
334
|
atts['href'] = self.cloak_mailto(atts['href'])
|
|
328
335
|
self.in_mailto = True
|
|
329
336
|
else:
|
|
330
|
-
assert (
|
|
331
|
-
'refid'
|
|
332
|
-
)
|
|
337
|
+
assert 'refid' in node, (
|
|
338
|
+
'References must have "refuri" or "refid" attribute.'
|
|
339
|
+
)
|
|
333
340
|
atts['href'] = '#' + node['refid']
|
|
334
341
|
if not isinstance(node.parent, nodes.TextElement):
|
|
335
342
|
assert len(node) == 1 and isinstance(node[0], nodes.image) # NoQA: PT018
|
|
@@ -359,12 +366,21 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
359
366
|
|
|
360
367
|
# overwritten
|
|
361
368
|
def visit_admonition(self, node: Element, name: str = '') -> None:
|
|
362
|
-
|
|
369
|
+
attributes = {}
|
|
370
|
+
tag_name = 'div'
|
|
371
|
+
if collapsible := node.get('collapsible'):
|
|
372
|
+
tag_name = 'details'
|
|
373
|
+
if collapsible == 'open':
|
|
374
|
+
attributes['open'] = 'open'
|
|
375
|
+
self.body.append(
|
|
376
|
+
self.starttag(node, tag_name, CLASS=f'admonition {name}', **attributes)
|
|
377
|
+
)
|
|
378
|
+
self.context.append(f'</{tag_name}>\n')
|
|
363
379
|
if name:
|
|
364
380
|
node.insert(0, nodes.title(name, admonitionlabels[name]))
|
|
365
381
|
|
|
366
382
|
def depart_admonition(self, node: Element | None = None) -> None:
|
|
367
|
-
self.body.append(
|
|
383
|
+
self.body.append(self.context.pop())
|
|
368
384
|
|
|
369
385
|
def visit_seealso(self, node: Element) -> None:
|
|
370
386
|
self.visit_admonition(node, 'seealso')
|
|
@@ -379,7 +395,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
379
395
|
if isinstance(node.parent, nodes.section):
|
|
380
396
|
if self.builder.name == 'singlehtml':
|
|
381
397
|
docname = self.docnames[-1]
|
|
382
|
-
anchorname = f
|
|
398
|
+
anchorname = f'{docname}/#{node.parent["ids"][0]}'
|
|
383
399
|
if anchorname not in self.builder.secnumbers:
|
|
384
400
|
# try first heading which has no anchor
|
|
385
401
|
anchorname = f'{docname}/'
|
|
@@ -419,9 +435,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
419
435
|
self.body.append(prefix % '.'.join(map(str, numbers)) + ' ')
|
|
420
436
|
self.body.append('</span>')
|
|
421
437
|
|
|
422
|
-
figtype = self.
|
|
423
|
-
node
|
|
424
|
-
)
|
|
438
|
+
figtype = self._domains.standard_domain.get_enumerable_node_type(node)
|
|
425
439
|
if figtype:
|
|
426
440
|
if len(node['ids']) == 0:
|
|
427
441
|
msg = __('Any IDs not assigned for %s node') % node.tagname
|
|
@@ -494,6 +508,15 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
494
508
|
)
|
|
495
509
|
self.body.append('<span class="caption-text">')
|
|
496
510
|
self.context.append('</span></p>\n')
|
|
511
|
+
elif (
|
|
512
|
+
isinstance(node.parent, nodes.Admonition)
|
|
513
|
+
and isinstance(node.parent, nodes.Element)
|
|
514
|
+
and 'collapsible' in node.parent
|
|
515
|
+
):
|
|
516
|
+
self.body.append(
|
|
517
|
+
self.starttag(node, 'summary', '', CLASS='admonition-title')
|
|
518
|
+
)
|
|
519
|
+
self.context.append('</summary>\n')
|
|
497
520
|
else:
|
|
498
521
|
super().visit_title(node)
|
|
499
522
|
self.add_secnumber(node)
|
|
@@ -671,24 +694,9 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
671
694
|
|
|
672
695
|
def visit_productionlist(self, node: Element) -> None:
|
|
673
696
|
self.body.append(self.starttag(node, 'pre'))
|
|
674
|
-
productionlist = cast(Iterable[addnodes.production], node)
|
|
675
|
-
names = (production['tokenname'] for production in productionlist)
|
|
676
|
-
maxlen = max(len(name) for name in names)
|
|
677
|
-
lastname = None
|
|
678
|
-
for production in productionlist:
|
|
679
|
-
if production['tokenname']:
|
|
680
|
-
lastname = production['tokenname'].ljust(maxlen)
|
|
681
|
-
self.body.append(self.starttag(production, 'strong', ''))
|
|
682
|
-
self.body.append(lastname + '</strong> ::= ')
|
|
683
|
-
elif lastname is not None:
|
|
684
|
-
self.body.append('%s ' % (' ' * len(lastname)))
|
|
685
|
-
production.walkabout(self)
|
|
686
|
-
self.body.append('\n')
|
|
687
|
-
self.body.append('</pre>\n')
|
|
688
|
-
raise nodes.SkipNode
|
|
689
697
|
|
|
690
698
|
def depart_productionlist(self, node: Element) -> None:
|
|
691
|
-
|
|
699
|
+
self.body.append('</pre>\n')
|
|
692
700
|
|
|
693
701
|
def visit_production(self, node: Element) -> None:
|
|
694
702
|
pass
|
|
@@ -752,8 +760,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
752
760
|
# but it tries the final file name, which does not necessarily exist
|
|
753
761
|
# yet at the time the HTML file is written.
|
|
754
762
|
if not ('width' in node and 'height' in node):
|
|
755
|
-
|
|
756
|
-
size = get_image_size(path)
|
|
763
|
+
size = get_image_size(self.builder.srcdir / olduri)
|
|
757
764
|
if size is None:
|
|
758
765
|
logger.warning(
|
|
759
766
|
__('Could not obtain image size. :scale: option is ignored.'),
|
|
@@ -820,7 +827,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
820
827
|
if token.strip():
|
|
821
828
|
# protect literal text from line wrapping
|
|
822
829
|
self.body.append('<span class="pre">%s</span>' % token)
|
|
823
|
-
elif token in ' \n':
|
|
830
|
+
elif token in {' ', '\n'}:
|
|
824
831
|
# allow breaks at whitespace
|
|
825
832
|
self.body.append(token)
|
|
826
833
|
else:
|
|
@@ -957,29 +964,33 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
|
957
964
|
else:
|
|
958
965
|
node['classes'].append('field-odd')
|
|
959
966
|
|
|
960
|
-
def visit_math(self, node:
|
|
967
|
+
def visit_math(self, node: nodes.math, math_env: str = '') -> None:
|
|
968
|
+
self._has_maths_elements = True
|
|
969
|
+
|
|
961
970
|
# see validate_math_renderer
|
|
962
971
|
name: str = self.builder.math_renderer_name # type: ignore[assignment]
|
|
963
|
-
visit, _ = self.builder.
|
|
972
|
+
visit, _ = self.builder.env._registry.html_inline_math_renderers[name]
|
|
964
973
|
visit(self, node)
|
|
965
974
|
|
|
966
|
-
def depart_math(self, node:
|
|
975
|
+
def depart_math(self, node: nodes.math, math_env: str = '') -> None:
|
|
967
976
|
# see validate_math_renderer
|
|
968
977
|
name: str = self.builder.math_renderer_name # type: ignore[assignment]
|
|
969
|
-
_, depart = self.builder.
|
|
978
|
+
_, depart = self.builder.env._registry.html_inline_math_renderers[name]
|
|
970
979
|
if depart:
|
|
971
980
|
depart(self, node)
|
|
972
981
|
|
|
973
|
-
def visit_math_block(self, node:
|
|
982
|
+
def visit_math_block(self, node: nodes.math_block, math_env: str = '') -> None:
|
|
983
|
+
self._has_maths_elements = True
|
|
984
|
+
|
|
974
985
|
# see validate_math_renderer
|
|
975
986
|
name: str = self.builder.math_renderer_name # type: ignore[assignment]
|
|
976
|
-
visit, _ = self.builder.
|
|
987
|
+
visit, _ = self.builder.env._registry.html_block_math_renderers[name]
|
|
977
988
|
visit(self, node)
|
|
978
989
|
|
|
979
|
-
def depart_math_block(self, node:
|
|
990
|
+
def depart_math_block(self, node: nodes.math_block, math_env: str = '') -> None:
|
|
980
991
|
# see validate_math_renderer
|
|
981
992
|
name: str = self.builder.math_renderer_name # type: ignore[assignment]
|
|
982
|
-
_, depart = self.builder.
|
|
993
|
+
_, depart = self.builder.env._registry.html_block_math_renderers[name]
|
|
983
994
|
if depart:
|
|
984
995
|
depart(self, node)
|
|
985
996
|
|
sphinx/writers/latex.py
CHANGED
|
@@ -8,11 +8,11 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import re
|
|
10
10
|
from collections import defaultdict
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import TYPE_CHECKING, cast
|
|
14
13
|
|
|
15
14
|
from docutils import nodes, writers
|
|
15
|
+
from roman_numerals import RomanNumeral
|
|
16
16
|
|
|
17
17
|
from sphinx import addnodes, highlighting
|
|
18
18
|
from sphinx.errors import SphinxError
|
|
@@ -24,13 +24,10 @@ from sphinx.util.nodes import clean_astext, get_prev_node
|
|
|
24
24
|
from sphinx.util.template import LaTeXRenderer
|
|
25
25
|
from sphinx.util.texescape import tex_replace_map
|
|
26
26
|
|
|
27
|
-
try:
|
|
28
|
-
from docutils.utils.roman import toRoman
|
|
29
|
-
except ImportError:
|
|
30
|
-
# In Debian/Ubuntu, roman package is provided as roman, not as docutils.utils.roman
|
|
31
|
-
from roman import toRoman # type: ignore[no-redef, import-not-found]
|
|
32
|
-
|
|
33
27
|
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Iterable
|
|
29
|
+
from typing import Any, ClassVar
|
|
30
|
+
|
|
34
31
|
from docutils.nodes import Element, Node, Text
|
|
35
32
|
|
|
36
33
|
from sphinx.builders.latex import LaTeXBuilder
|
|
@@ -100,7 +97,7 @@ class LaTeXWriter(writers.Writer): # type: ignore[type-arg]
|
|
|
100
97
|
self.document, self.builder, self.theme
|
|
101
98
|
)
|
|
102
99
|
self.document.walkabout(visitor)
|
|
103
|
-
self.output = cast(LaTeXTranslator, visitor).astext()
|
|
100
|
+
self.output = cast('LaTeXTranslator', visitor).astext()
|
|
104
101
|
|
|
105
102
|
|
|
106
103
|
# Helper classes
|
|
@@ -219,8 +216,8 @@ class Table:
|
|
|
219
216
|
self.cell_id += 1
|
|
220
217
|
for col in range(width):
|
|
221
218
|
for row in range(height):
|
|
222
|
-
assert self.cells[
|
|
223
|
-
self.cells[
|
|
219
|
+
assert self.cells[self.row + row, self.col + col] == 0
|
|
220
|
+
self.cells[self.row + row, self.col + col] = self.cell_id
|
|
224
221
|
|
|
225
222
|
def cell(
|
|
226
223
|
self,
|
|
@@ -246,25 +243,25 @@ class TableCell:
|
|
|
246
243
|
"""Data of a cell in a table."""
|
|
247
244
|
|
|
248
245
|
def __init__(self, table: Table, row: int, col: int) -> None:
|
|
249
|
-
if table.cells[
|
|
246
|
+
if table.cells[row, col] == 0:
|
|
250
247
|
raise IndexError
|
|
251
248
|
|
|
252
249
|
self.table = table
|
|
253
|
-
self.cell_id = table.cells[
|
|
250
|
+
self.cell_id = table.cells[row, col]
|
|
254
251
|
self.row = row
|
|
255
252
|
self.col = col
|
|
256
253
|
|
|
257
254
|
# adjust position for multirow/multicol cell
|
|
258
|
-
while table.cells[
|
|
255
|
+
while table.cells[self.row - 1, self.col] == self.cell_id:
|
|
259
256
|
self.row -= 1
|
|
260
|
-
while table.cells[
|
|
257
|
+
while table.cells[self.row, self.col - 1] == self.cell_id:
|
|
261
258
|
self.col -= 1
|
|
262
259
|
|
|
263
260
|
@property
|
|
264
261
|
def width(self) -> int:
|
|
265
262
|
"""Returns the cell width."""
|
|
266
263
|
width = 0
|
|
267
|
-
while self.table.cells[
|
|
264
|
+
while self.table.cells[self.row, self.col + width] == self.cell_id:
|
|
268
265
|
width += 1
|
|
269
266
|
return width
|
|
270
267
|
|
|
@@ -272,7 +269,7 @@ class TableCell:
|
|
|
272
269
|
def height(self) -> int:
|
|
273
270
|
"""Returns the cell height."""
|
|
274
271
|
height = 0
|
|
275
|
-
while self.table.cells[
|
|
272
|
+
while self.table.cells[self.row + height, self.col] == self.cell_id:
|
|
276
273
|
height += 1
|
|
277
274
|
return height
|
|
278
275
|
|
|
@@ -291,7 +288,7 @@ def rstdim_to_latexdim(width_str: str, scale: int = 100) -> str:
|
|
|
291
288
|
amount, unit = match.groups()[:2]
|
|
292
289
|
if scale == 100:
|
|
293
290
|
float(amount) # validate amount is float
|
|
294
|
-
if unit in
|
|
291
|
+
if unit in {'', 'px'}:
|
|
295
292
|
res = r'%s\sphinxpxdimen' % amount
|
|
296
293
|
elif unit == 'pt':
|
|
297
294
|
res = '%sbp' % amount # convert to 'bp'
|
|
@@ -299,7 +296,7 @@ def rstdim_to_latexdim(width_str: str, scale: int = 100) -> str:
|
|
|
299
296
|
res = r'%.3f\linewidth' % (float(amount) / 100.0)
|
|
300
297
|
else:
|
|
301
298
|
amount_float = float(amount) * scale / 100.0
|
|
302
|
-
if unit in
|
|
299
|
+
if unit in {'', 'px'}:
|
|
303
300
|
res = r'%.5f\sphinxpxdimen' % amount_float
|
|
304
301
|
elif unit == 'pt':
|
|
305
302
|
res = '%.5fbp' % amount_float
|
|
@@ -326,7 +323,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
326
323
|
|
|
327
324
|
# flags
|
|
328
325
|
self.in_title = 0
|
|
329
|
-
self.in_production_list =
|
|
326
|
+
self.in_production_list = False
|
|
330
327
|
self.in_footnote = 0
|
|
331
328
|
self.in_caption = 0
|
|
332
329
|
self.in_term = 0
|
|
@@ -564,7 +561,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
564
561
|
indices_config = frozenset(indices_config)
|
|
565
562
|
else:
|
|
566
563
|
check_names = False
|
|
567
|
-
for domain in self.
|
|
564
|
+
for domain in self._domains.sorted():
|
|
568
565
|
for index_cls in domain.indices:
|
|
569
566
|
index_name = f'{domain.name}-{index_cls.name}'
|
|
570
567
|
if check_names and index_name not in indices_config:
|
|
@@ -583,18 +580,19 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
583
580
|
def render(self, template_name: str, variables: dict[str, Any]) -> str:
|
|
584
581
|
renderer = LaTeXRenderer(latex_engine=self.config.latex_engine)
|
|
585
582
|
for template_dir in self.config.templates_path:
|
|
586
|
-
template =
|
|
587
|
-
if
|
|
588
|
-
return renderer.render(template, variables)
|
|
589
|
-
elif template.
|
|
590
|
-
|
|
591
|
-
|
|
583
|
+
template = self.builder.confdir / template_dir / template_name
|
|
584
|
+
if template.exists():
|
|
585
|
+
return renderer.render(str(template), variables)
|
|
586
|
+
elif template.suffix == '.jinja':
|
|
587
|
+
legacy_template_name = template.name.removesuffix('.jinja') + '_t'
|
|
588
|
+
legacy_template = template.with_name(legacy_template_name)
|
|
589
|
+
if legacy_template.exists():
|
|
592
590
|
logger.warning(
|
|
593
591
|
__('template %s not found; loading from legacy %s instead'),
|
|
594
592
|
template_name,
|
|
595
593
|
legacy_template,
|
|
596
594
|
)
|
|
597
|
-
return renderer.render(legacy_template, variables)
|
|
595
|
+
return renderer.render(str(legacy_template), variables)
|
|
598
596
|
|
|
599
597
|
return renderer.render(template_name, variables)
|
|
600
598
|
|
|
@@ -673,22 +671,20 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
673
671
|
def visit_productionlist(self, node: Element) -> None:
|
|
674
672
|
self.body.append(BLANKLINE)
|
|
675
673
|
self.body.append(r'\begin{productionlist}' + CR)
|
|
676
|
-
self.in_production_list =
|
|
674
|
+
self.in_production_list = True
|
|
677
675
|
|
|
678
676
|
def depart_productionlist(self, node: Element) -> None:
|
|
677
|
+
self.in_production_list = False
|
|
679
678
|
self.body.append(r'\end{productionlist}' + BLANKLINE)
|
|
680
|
-
self.in_production_list = 0
|
|
681
679
|
|
|
682
680
|
def visit_production(self, node: Element) -> None:
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
else:
|
|
688
|
-
self.body.append(r'\productioncont{')
|
|
681
|
+
# Nothing to do, the productionlist LaTeX environment
|
|
682
|
+
# is configured to render the nodes line-by-line
|
|
683
|
+
# But see also visit_literal_strong special clause.
|
|
684
|
+
pass
|
|
689
685
|
|
|
690
686
|
def depart_production(self, node: Element) -> None:
|
|
691
|
-
|
|
687
|
+
pass
|
|
692
688
|
|
|
693
689
|
def visit_transition(self, node: Element) -> None:
|
|
694
690
|
self.body.append(self.elements['transition'])
|
|
@@ -956,6 +952,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
956
952
|
self.required_params_left = sum(self.list_is_required_param)
|
|
957
953
|
self.param_separator = r'\sphinxparamcomma '
|
|
958
954
|
self.multi_line_parameter_list = node.get('multi_line_parameter_list', False)
|
|
955
|
+
self.trailing_comma = node.get('multi_line_trailing_comma', False)
|
|
959
956
|
|
|
960
957
|
def visit_desc_parameterlist(self, node: Element) -> None:
|
|
961
958
|
if self.has_tp_list:
|
|
@@ -1015,7 +1012,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1015
1012
|
if (
|
|
1016
1013
|
opt_param_left_at_level
|
|
1017
1014
|
or is_required
|
|
1018
|
-
and (
|
|
1015
|
+
and (next_is_required or self.trailing_comma)
|
|
1019
1016
|
):
|
|
1020
1017
|
self.body.append(self.param_separator)
|
|
1021
1018
|
|
|
@@ -1057,13 +1054,20 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1057
1054
|
|
|
1058
1055
|
def depart_desc_optional(self, node: Element) -> None:
|
|
1059
1056
|
self.optional_param_level -= 1
|
|
1057
|
+
level = self.optional_param_level
|
|
1060
1058
|
if self.multi_line_parameter_list:
|
|
1059
|
+
max_level = self.max_optional_param_level
|
|
1060
|
+
len_lirp = len(self.list_is_required_param)
|
|
1061
|
+
is_last_group = self.param_group_index + 1 == len_lirp
|
|
1061
1062
|
# If it's the first time we go down one level, add the separator before the
|
|
1062
|
-
# bracket
|
|
1063
|
-
|
|
1063
|
+
# bracket, except if this is the last parameter and the parameter list
|
|
1064
|
+
# should not feature a trailing comma.
|
|
1065
|
+
if level == max_level - 1 and (
|
|
1066
|
+
not is_last_group or level > 0 or self.trailing_comma
|
|
1067
|
+
):
|
|
1064
1068
|
self.body.append(self.param_separator)
|
|
1065
1069
|
self.body.append('}')
|
|
1066
|
-
if
|
|
1070
|
+
if level == 0:
|
|
1067
1071
|
self.param_group_index += 1
|
|
1068
1072
|
|
|
1069
1073
|
def visit_desc_annotation(self, node: Element) -> None:
|
|
@@ -1090,7 +1094,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1090
1094
|
self.no_latex_floats -= 1
|
|
1091
1095
|
|
|
1092
1096
|
def visit_rubric(self, node: nodes.rubric) -> None:
|
|
1093
|
-
if len(node) == 1 and node.astext() in
|
|
1097
|
+
if len(node) == 1 and node.astext() in {'Footnotes', _('Footnotes')}:
|
|
1094
1098
|
raise nodes.SkipNode
|
|
1095
1099
|
tag = 'subsubsection'
|
|
1096
1100
|
if 'heading-level' in node:
|
|
@@ -1115,7 +1119,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1115
1119
|
|
|
1116
1120
|
def visit_footnote(self, node: Element) -> None:
|
|
1117
1121
|
self.in_footnote += 1
|
|
1118
|
-
label = cast(nodes.label, node[0])
|
|
1122
|
+
label = cast('nodes.label', node[0])
|
|
1119
1123
|
if self.in_parsed_literal:
|
|
1120
1124
|
self.body.append(r'\begin{footnote}[%s]' % label.astext())
|
|
1121
1125
|
else:
|
|
@@ -1337,7 +1341,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1337
1341
|
if (
|
|
1338
1342
|
len(node) == 1
|
|
1339
1343
|
and isinstance(node[0], nodes.paragraph)
|
|
1340
|
-
and node.astext()
|
|
1344
|
+
and not node.astext()
|
|
1341
1345
|
):
|
|
1342
1346
|
pass
|
|
1343
1347
|
else:
|
|
@@ -1386,8 +1390,8 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1386
1390
|
def visit_acks(self, node: Element) -> None:
|
|
1387
1391
|
# this is a list in the source, but should be rendered as a
|
|
1388
1392
|
# comma-separated list here
|
|
1389
|
-
bullet_list = cast(nodes.bullet_list, node[0])
|
|
1390
|
-
list_items = cast(Iterable[nodes.list_item], bullet_list)
|
|
1393
|
+
bullet_list = cast('nodes.bullet_list', node[0])
|
|
1394
|
+
list_items = cast('Iterable[nodes.list_item]', bullet_list)
|
|
1391
1395
|
self.body.append(BLANKLINE)
|
|
1392
1396
|
self.body.append(', '.join(n.astext() for n in list_items) + '.')
|
|
1393
1397
|
self.body.append(BLANKLINE)
|
|
@@ -1420,8 +1424,9 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1420
1424
|
else:
|
|
1421
1425
|
return get_nested_level(node.parent)
|
|
1422
1426
|
|
|
1423
|
-
|
|
1424
|
-
|
|
1427
|
+
nested_level = get_nested_level(node)
|
|
1428
|
+
enum = f'enum{RomanNumeral(nested_level).to_lowercase()}'
|
|
1429
|
+
enumnext = f'enum{RomanNumeral(nested_level + 1).to_lowercase()}'
|
|
1425
1430
|
style = ENUMERATE_LIST_STYLE.get(get_enumtype(node))
|
|
1426
1431
|
prefix = node.get('prefix', '')
|
|
1427
1432
|
suffix = node.get('suffix', '.')
|
|
@@ -1648,7 +1653,9 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1648
1653
|
options = ''
|
|
1649
1654
|
if include_graphics_options:
|
|
1650
1655
|
options = '[%s]' % ','.join(include_graphics_options)
|
|
1651
|
-
|
|
1656
|
+
img_path = Path(uri)
|
|
1657
|
+
base = img_path.with_suffix('')
|
|
1658
|
+
ext = img_path.suffix
|
|
1652
1659
|
|
|
1653
1660
|
if self.in_title and base:
|
|
1654
1661
|
# Lowercase tokens forcely because some fncychap themes capitalize
|
|
@@ -1657,8 +1664,8 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1657
1664
|
else:
|
|
1658
1665
|
cmd = rf'\sphinxincludegraphics{options}{{{{{base}}}{ext}}}'
|
|
1659
1666
|
# escape filepath for includegraphics, https://tex.stackexchange.com/a/202714/41112
|
|
1660
|
-
if '#' in base:
|
|
1661
|
-
cmd =
|
|
1667
|
+
if '#' in str(base):
|
|
1668
|
+
cmd = rf'{{\catcode`\#=12{cmd}}}'
|
|
1662
1669
|
self.body.append(cmd)
|
|
1663
1670
|
self.body.extend(post)
|
|
1664
1671
|
|
|
@@ -1684,7 +1691,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1684
1691
|
if any(isinstance(child, nodes.caption) for child in node):
|
|
1685
1692
|
self.body.append(r'\capstart')
|
|
1686
1693
|
self.context.append(r'\end{sphinxfigure-in-table}\relax' + CR)
|
|
1687
|
-
elif node.get('align', '') in
|
|
1694
|
+
elif node.get('align', '') in {'left', 'right'}:
|
|
1688
1695
|
length = None
|
|
1689
1696
|
if 'width' in node:
|
|
1690
1697
|
length = self.latex_image_length(node['width'])
|
|
@@ -1816,7 +1823,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1816
1823
|
while isinstance(next_node, nodes.target):
|
|
1817
1824
|
next_node = next_node.next_node(ascend=True)
|
|
1818
1825
|
|
|
1819
|
-
domain = self.
|
|
1826
|
+
domain = self._domains.standard_domain
|
|
1820
1827
|
if isinstance(next_node, HYPERLINK_SUPPORT_NODES):
|
|
1821
1828
|
return
|
|
1822
1829
|
if (
|
|
@@ -1840,7 +1847,8 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1840
1847
|
else:
|
|
1841
1848
|
add_target(node['refid'])
|
|
1842
1849
|
# Temporary fix for https://github.com/sphinx-doc/sphinx/issues/11093
|
|
1843
|
-
# TODO: investigate if a more elegant solution exists
|
|
1850
|
+
# TODO: investigate if a more elegant solution exists
|
|
1851
|
+
# (see comments of https://github.com/sphinx-doc/sphinx/issues/11093)
|
|
1844
1852
|
if node.get('ismod', False):
|
|
1845
1853
|
# Detect if the previous nodes are label targets. If so, remove
|
|
1846
1854
|
# the refid thereof from node['ids'] to avoid duplicated ids.
|
|
@@ -2061,9 +2069,16 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2061
2069
|
self.body.append('}')
|
|
2062
2070
|
|
|
2063
2071
|
def visit_literal_strong(self, node: Element) -> None:
|
|
2072
|
+
if self.in_production_list:
|
|
2073
|
+
ctx = [r'\phantomsection']
|
|
2074
|
+
ctx += [self.hypertarget(id_, anchor=False) for id_ in node['ids']]
|
|
2075
|
+
self.body.append(''.join(ctx))
|
|
2076
|
+
return
|
|
2064
2077
|
self.body.append(r'\sphinxstyleliteralstrong{\sphinxupquote{')
|
|
2065
2078
|
|
|
2066
2079
|
def depart_literal_strong(self, node: Element) -> None:
|
|
2080
|
+
if self.in_production_list:
|
|
2081
|
+
return
|
|
2067
2082
|
self.body.append('}}')
|
|
2068
2083
|
|
|
2069
2084
|
def visit_abbreviation(self, node: Element) -> None:
|
|
@@ -2092,8 +2107,8 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2092
2107
|
self.body.append('}')
|
|
2093
2108
|
|
|
2094
2109
|
def visit_thebibliography(self, node: Element) -> None:
|
|
2095
|
-
citations = cast(Iterable[nodes.citation], node)
|
|
2096
|
-
labels = (cast(nodes.label, citation[0]) for citation in citations)
|
|
2110
|
+
citations = cast('Iterable[nodes.citation]', node)
|
|
2111
|
+
labels = (cast('nodes.label', citation[0]) for citation in citations)
|
|
2097
2112
|
longest_label = max((label.astext() for label in labels), key=len)
|
|
2098
2113
|
if len(longest_label) > MAX_CITATION_LABEL_LENGTH:
|
|
2099
2114
|
# adjust max width of citation labels not to break the layout
|
|
@@ -2107,7 +2122,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2107
2122
|
self.body.append(r'\end{sphinxthebibliography}' + CR)
|
|
2108
2123
|
|
|
2109
2124
|
def visit_citation(self, node: Element) -> None:
|
|
2110
|
-
label = cast(nodes.label, node[0])
|
|
2125
|
+
label = cast('nodes.label', node[0])
|
|
2111
2126
|
self.body.append(
|
|
2112
2127
|
rf'\bibitem[{self.encode(label.astext())}]'
|
|
2113
2128
|
rf'{{{node["docname"]}:{node["ids"][0]}}}'
|
|
@@ -2160,7 +2175,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2160
2175
|
self.body.append(']')
|
|
2161
2176
|
|
|
2162
2177
|
def visit_footnotetext(self, node: Element) -> None:
|
|
2163
|
-
label = cast(nodes.label, node[0])
|
|
2178
|
+
label = cast('nodes.label', node[0])
|
|
2164
2179
|
self.body.append('%' + CR)
|
|
2165
2180
|
self.body.append(r'\begin{footnotetext}[%s]' % label.astext())
|
|
2166
2181
|
self.body.append(r'\sphinxAtStartFootnote' + CR)
|
|
@@ -2443,20 +2458,20 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2443
2458
|
def depart_system_message(self, node: Element) -> None:
|
|
2444
2459
|
self.body.append(CR)
|
|
2445
2460
|
|
|
2446
|
-
def visit_math(self, node:
|
|
2461
|
+
def visit_math(self, node: nodes.math) -> None:
|
|
2447
2462
|
if self.in_title:
|
|
2448
2463
|
self.body.append(r'\protect\(%s\protect\)' % node.astext())
|
|
2449
2464
|
else:
|
|
2450
2465
|
self.body.append(r'\(%s\)' % node.astext())
|
|
2451
2466
|
raise nodes.SkipNode
|
|
2452
2467
|
|
|
2453
|
-
def visit_math_block(self, node:
|
|
2468
|
+
def visit_math_block(self, node: nodes.math_block) -> None:
|
|
2454
2469
|
if node.get('label'):
|
|
2455
|
-
label = f
|
|
2470
|
+
label = f'equation:{node["docname"]}:{node["label"]}'
|
|
2456
2471
|
else:
|
|
2457
2472
|
label = None
|
|
2458
2473
|
|
|
2459
|
-
if node.get('nowrap'):
|
|
2474
|
+
if node.get('no-wrap', node.get('nowrap', False)):
|
|
2460
2475
|
if label:
|
|
2461
2476
|
self.body.append(r'\label{%s}' % label)
|
|
2462
2477
|
self.body.append(node.astext())
|
|
@@ -2469,7 +2484,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2469
2484
|
raise nodes.SkipNode
|
|
2470
2485
|
|
|
2471
2486
|
def visit_math_reference(self, node: Element) -> None:
|
|
2472
|
-
label = f
|
|
2487
|
+
label = f'equation:{node["docname"]}:{node["target"]}'
|
|
2473
2488
|
eqref_format = self.config.math_eqref_format
|
|
2474
2489
|
if eqref_format:
|
|
2475
2490
|
try:
|
|
@@ -2486,7 +2501,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2486
2501
|
|
|
2487
2502
|
|
|
2488
2503
|
# FIXME: Workaround to avoid circular import
|
|
2489
|
-
#
|
|
2504
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/5433
|
|
2490
2505
|
from sphinx.builders.latex.nodes import ( # NoQA: E402 # isort:skip
|
|
2491
2506
|
HYPERLINK_SUPPORT_NODES,
|
|
2492
2507
|
captioned_literal_block,
|