diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index d283398f0..11a9bbbc4 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -14,7 +14,7 @@ import posixpath import sys import warnings from typing import cast -from typing import Iterable +from typing import Iterable, Tuple from docutils import nodes from docutils.nodes import Element, Node, Text @@ -272,10 +272,9 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_seealso(self, node: Element) -> None: self.depart_admonition(node) - def add_secnumber(self, node: Element) -> None: + def get_secnumber(self, node: Element) -> Tuple[int, ...]: if node.get('secnumber'): - self.body.append('.'.join(map(str, node['secnumber'])) + - self.secnumber_suffix) + return node['secnumber'] elif isinstance(node.parent, nodes.section): if self.builder.name == 'singlehtml': docname = self.docnames[-1] @@ -286,10 +285,17 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): anchorname = '#' + node.parent['ids'][0] if anchorname not in self.builder.secnumbers: anchorname = '' # try first heading which has no anchor + if self.builder.secnumbers.get(anchorname): - numbers = self.builder.secnumbers[anchorname] - self.body.append('.'.join(map(str, numbers)) + - self.secnumber_suffix) + return self.builder.secnumbers[anchorname] + + return None + + def add_secnumber(self, node: Element) -> None: + secnumber = self.get_secnumber(node) + if secnumber: + self.body.append('%s' % + ('.'.join(map(str, secnumber)) + self.secnumber_suffix)) def add_fignumber(self, node: Element) -> None: def append_fignumber(figtype: str, figure_id: str) -> None: diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 26dc2e816..5ace8572f 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -13,7 +13,7 @@ import posixpath import sys import warnings from typing import cast -from typing import Iterable +from typing import Iterable, Tuple from docutils import nodes from docutils.nodes import Element, Node, Text @@ -243,11 +243,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_seealso(self, node: Element) -> None: self.depart_admonition(node) - def add_secnumber(self, node: Element) -> None: + def get_secnumber(self, node: Element) -> Tuple[int, ...]: if node.get('secnumber'): - self.body.append('.'.join(map(str, node['secnumber'])) + - self.secnumber_suffix) - elif isinstance(node.parent, nodes.section): + return node['secnumber'] + + if isinstance(node.parent, nodes.section): if self.builder.name == 'singlehtml': docname = self.docnames[-1] anchorname = "%s/#%s" % (docname, node.parent['ids'][0]) @@ -257,10 +257,17 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): anchorname = '#' + node.parent['ids'][0] if anchorname not in self.builder.secnumbers: anchorname = '' # try first heading which has no anchor + if self.builder.secnumbers.get(anchorname): - numbers = self.builder.secnumbers[anchorname] - self.body.append('.'.join(map(str, numbers)) + - self.secnumber_suffix) + return self.builder.secnumbers[anchorname] + + return None + + def add_secnumber(self, node: Element) -> None: + secnumber = self.get_secnumber(node) + if secnumber: + self.body.append('%s' % + ('.'.join(map(str, secnumber)) + self.secnumber_suffix)) def add_fignumber(self, node: Element) -> None: def append_fignumber(figtype: str, figure_id: str) -> None: diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 3255bb71e..66164dd1c 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -97,14 +97,11 @@ def check_xpath(etree, fname, path, check, be_found=True): else: def get_text(node): if node.text is not None: + # the node has only one text return node.text else: - # Since pygments-2.1.1, empty tag is inserted at top of - # highlighting block - if len(node) == 1 and node[0].tag == 'span' and node[0].text is None: - if node[0].tail is not None: - return node[0].tail - return '' + # the node has tags and text; gather texts just under the node + return ''.join(n.tail or '' for n in node) rex = re.compile(check) if be_found: @@ -491,28 +488,40 @@ def test_html_translator(app): (".//li[@class='toctree-l3']/a", '2.2.1. Bar B1', False), ], 'foo.html': [ - (".//h1", '1. Foo', True), - (".//h2", '1.1. Foo A', True), - (".//h3", '1.1.1. Foo A1', True), - (".//h2", '1.2. Foo B', True), - (".//h3", '1.2.1. Foo B1', True), + (".//h1", 'Foo', True), + (".//h2", 'Foo A', True), + (".//h3", 'Foo A1', True), + (".//h2", 'Foo B', True), + (".//h3", 'Foo B1', True), + + (".//h1//span[@class='section-number']", '1. ', True), + (".//h2//span[@class='section-number']", '1.1. ', True), + (".//h3//span[@class='section-number']", '1.1.1. ', True), + (".//h2//span[@class='section-number']", '1.2. ', True), + (".//h3//span[@class='section-number']", '1.2.1. ', True), + (".//div[@class='sphinxsidebarwrapper']//li/a", '1.1. Foo A', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '1.1.1. Foo A1', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '1.2. Foo B', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '1.2.1. Foo B1', True), ], 'bar.html': [ - (".//h1", '2. Bar', True), - (".//h2", '2.1. Bar A', True), - (".//h2", '2.2. Bar B', True), - (".//h3", '2.2.1. Bar B1', True), + (".//h1", 'Bar', True), + (".//h2", 'Bar A', True), + (".//h2", 'Bar B', True), + (".//h3", 'Bar B1', True), + (".//h1//span[@class='section-number']", '2. ', True), + (".//h2//span[@class='section-number']", '2.1. ', True), + (".//h2//span[@class='section-number']", '2.2. ', True), + (".//h3//span[@class='section-number']", '2.2.1. ', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '2. Bar', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '2.1. Bar A', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '2.2. Bar B', True), (".//div[@class='sphinxsidebarwrapper']//li/a", '2.2.1. Bar B1', False), ], 'baz.html': [ - (".//h1", '2.1.1. Baz A', True), + (".//h1", 'Baz A', True), + (".//h1//span[@class='section-number']", '2.1.1. ', True), ], })) @pytest.mark.skipif(docutils.__version_info__ < (0, 13), @@ -536,20 +545,30 @@ def test_tocdepth(app, cached_etree_parse, fname, expect): (".//h1", 'test-tocdepth', True), # foo.rst - (".//h2", '1. Foo', True), - (".//h3", '1.1. Foo A', True), - (".//h4", '1.1.1. Foo A1', True), - (".//h3", '1.2. Foo B', True), - (".//h4", '1.2.1. Foo B1', True), + (".//h2", 'Foo', True), + (".//h3", 'Foo A', True), + (".//h4", 'Foo A1', True), + (".//h3", 'Foo B', True), + (".//h4", 'Foo B1', True), + (".//h2//span[@class='section-number']", '1. ', True), + (".//h3//span[@class='section-number']", '1.1. ', True), + (".//h4//span[@class='section-number']", '1.1.1. ', True), + (".//h3//span[@class='section-number']", '1.2. ', True), + (".//h4//span[@class='section-number']", '1.2.1. ', True), # bar.rst - (".//h2", '2. Bar', True), - (".//h3", '2.1. Bar A', True), - (".//h3", '2.2. Bar B', True), - (".//h4", '2.2.1. Bar B1', True), + (".//h2", 'Bar', True), + (".//h3", 'Bar A', True), + (".//h3", 'Bar B', True), + (".//h4", 'Bar B1', True), + (".//h2//span[@class='section-number']", '2. ', True), + (".//h3//span[@class='section-number']", '2.1. ', True), + (".//h3//span[@class='section-number']", '2.2. ', True), + (".//h4//span[@class='section-number']", '2.2.1. ', True), # baz.rst - (".//h4", '2.1.1. Baz A', True), + (".//h4", 'Baz A', True), + (".//h4//span[@class='section-number']", '2.1.1. ', True), ], })) @pytest.mark.skipif(docutils.__version_info__ < (0, 13),