diff --git a/AUTHORS.rst b/AUTHORS.rst index d08f44875b4..7325c1bc407 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -71,6 +71,7 @@ Contributors * Joel Wurtz -- cellspanning support in LaTeX * John Waltman -- Texinfo builder * Jon Dufresne -- modernisation +* Jorge Marques -- singlehtml unique section ids * Josip Dzolonga -- coverage builder * Juan Luis Cano Rodríguez -- new tutorial (2021) * Julien Palard -- Colspan and rowspan in text builder diff --git a/CHANGES.rst b/CHANGES.rst index 791038e5e15..e753bbd040e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -97,6 +97,9 @@ Bugs fixed Patch by Bénédikt Tran. * #13712: intersphinx: Don't add "v" prefix to non-numeric versions. Patch by Szymon Karpinski. +* #13738: singlehtml builder: make section ids unique by appending the docname, + matching ``sphinx/environment/adapters/toctree.py``'s ``_resolve_toctree()`` + format. E.g., ``id3`` becomes ``document-path/to/doc#id3``. Testing ------- diff --git a/sphinx/builders/singlehtml.py b/sphinx/builders/singlehtml.py index 1888f6679d1..4fd04b05fc0 100644 --- a/sphinx/builders/singlehtml.py +++ b/sphinx/builders/singlehtml.py @@ -110,7 +110,7 @@ def assemble_toc_secnumbers(self) -> dict[str, dict[str, tuple[int, ...]]]: new_secnumbers: dict[str, tuple[int, ...]] = {} for docname, secnums in self.env.toc_secnumbers.items(): for id, secnum in secnums.items(): - alias = f'{docname}/{id}' + alias = f'{docname}{id}' new_secnumbers[alias] = secnum return {self.config.root_doc: new_secnumbers} diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 39d7ecea680..aabaaa9a0d1 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -17,7 +17,7 @@ from sphinx.util.images import get_image_size if TYPE_CHECKING: - from docutils.nodes import Element, Node, Text + from docutils.nodes import Element, Node, Text, section from sphinx.builders import Builder from sphinx.builders.html import StandaloneHTMLBuilder @@ -395,10 +395,11 @@ def get_secnumber(self, node: Element) -> tuple[int, ...] | None: if isinstance(node.parent, nodes.section): if self.builder.name == 'singlehtml': docname = self.docnames[-1] - anchorname = f'{docname}/#{node.parent["ids"][0]}' + # Remove document- + anchorname = node.parent['ids'][0][9:] if anchorname not in self.builder.secnumbers: # try first heading which has no anchor - anchorname = f'{docname}/' + anchorname = docname else: anchorname = '#' + node.parent['ids'][0] if anchorname not in self.builder.secnumbers: @@ -497,6 +498,15 @@ def depart_term(self, node: Element) -> None: self.body.append('') + def visit_section(self, node: section) -> None: + if self.builder.name == 'singlehtml' and node['ids']: + docname = self.docnames[-1] + node['ids'][0] = 'document-' + docname + '#' + node['ids'][0] + super().visit_section(node) + + def depart_section(self, node: section) -> None: + super().depart_section(node) + # overwritten def visit_title(self, node: nodes.title) -> None: if (