diff options
Diffstat (limited to 'sphinx/transforms/compact_bullet_list.py')
-rw-r--r-- | sphinx/transforms/compact_bullet_list.py | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py new file mode 100644 index 0000000..149b5e0 --- /dev/null +++ b/sphinx/transforms/compact_bullet_list.py @@ -0,0 +1,91 @@ +"""Docutils transforms used by Sphinx when reading documents.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, cast + +from docutils import nodes + +from sphinx import addnodes +from sphinx.transforms import SphinxTransform + +if TYPE_CHECKING: + from docutils.nodes import Node + + from sphinx.application import Sphinx + + +class RefOnlyListChecker(nodes.GenericNodeVisitor): + """Raise `nodes.NodeFound` if non-simple list item is encountered. + + Here 'simple' means a list item containing only a paragraph with a + single reference in it. + """ + + def default_visit(self, node: Node) -> None: + raise nodes.NodeFound + + def visit_bullet_list(self, node: nodes.bullet_list) -> None: + pass + + def visit_list_item(self, node: nodes.list_item) -> None: + children: list[Node] = [] + for child in node.children: + if not isinstance(child, nodes.Invisible): + children.append(child) + if len(children) != 1: + raise nodes.NodeFound + if not isinstance(children[0], nodes.paragraph): + raise nodes.NodeFound + para = children[0] + if len(para) != 1: + raise nodes.NodeFound + if not isinstance(para[0], addnodes.pending_xref): + raise nodes.NodeFound + raise nodes.SkipChildren + + def invisible_visit(self, node: Node) -> None: + """Invisible nodes should be ignored.""" + pass + + +class RefOnlyBulletListTransform(SphinxTransform): + """Change refonly bullet lists to use compact_paragraphs. + + Specifically implemented for 'Indices and Tables' section, which looks + odd when html_compact_lists is false. + """ + default_priority = 100 + + def apply(self, **kwargs: Any) -> None: + if self.config.html_compact_lists: + return + + def check_refonly_list(node: Node) -> bool: + """Check for list with only references in it.""" + visitor = RefOnlyListChecker(self.document) + try: + node.walk(visitor) + except nodes.NodeFound: + return False + else: + return True + + for node in self.document.findall(nodes.bullet_list): + if check_refonly_list(node): + for item in node.findall(nodes.list_item): + para = cast(nodes.paragraph, item[0]) + ref = cast(nodes.reference, para[0]) + compact_para = addnodes.compact_paragraph() + compact_para += ref + item.replace(para, compact_para) + + +def setup(app: Sphinx) -> dict[str, Any]: + app.add_transform(RefOnlyBulletListTransform) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } |