From 675e7e576f0aa8ed48a8645d6809fd5b700304f0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 24 Feb 2020 01:23:07 +0900 Subject: [PATCH] Add desc_sig_element and inherited nodes --- sphinx/addnodes.py | 30 +++++++++++++++- sphinx/transforms/post_transforms/__init__.py | 35 ++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 15d5fc46be2..fa04e9344a3 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -12,7 +12,7 @@ from typing import Any, Dict, List, Sequence from docutils import nodes -from docutils.nodes import Node +from docutils.nodes import Element, Node from sphinx.deprecation import RemovedInSphinx40Warning @@ -174,6 +174,31 @@ class desc_content(nodes.General, nodes.Element): """ +class desc_sig_element(nodes.inline): + """Common parent class of nodes for inline text of a signature.""" + classes = [] # type: List[str] + + def __init__(self, rawsource: str = '', text: str = '', + *children: Element, **attributes: Any) -> None: + super().__init__(rawsource, text, *children, **attributes) + self['classes'].extend(self.classes) + + +class desc_sig_name(desc_sig_element): + """Node for a name in a signature.""" + classes = ["n"] + + +class desc_sig_operator(desc_sig_element): + """Node for an operator in a signature.""" + classes = ["o"] + + +class desc_sig_punctuation(desc_sig_element): + """Node for a punctuation in a signature.""" + classes = ["p"] + + # new admonition-like constructs class versionmodified(nodes.Admonition, nodes.TextElement): @@ -332,6 +357,9 @@ def setup(app: "Sphinx") -> Dict[str, Any]: app.add_node(desc_optional) app.add_node(desc_annotation) app.add_node(desc_content) + app.add_node(desc_sig_name) + app.add_node(desc_sig_operator) + app.add_node(desc_sig_punctuation) app.add_node(versionmodified) app.add_node(seealso) app.add_node(productionlist) diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 6d7c3b0eb0f..48f5dc24821 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -8,7 +8,7 @@ :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Tuple, Type from typing import cast from docutils import nodes @@ -22,6 +22,7 @@ from sphinx.locale import __ from sphinx.transforms import SphinxTransform from sphinx.util import logging +from sphinx.util.docutils import SphinxTranslator from sphinx.util.nodes import process_only_nodes @@ -186,9 +187,41 @@ def run(self, **kwargs: Any) -> None: process_only_nodes(self.document, self.app.builder.tags) +class SigElementFallbackTransform(SphinxPostTransform): + """Fallback desc_sig_element nodes to inline if translator does not supported them.""" + default_priority = 200 + + SIG_ELEMENTS = [addnodes.desc_sig_name, + addnodes.desc_sig_operator, + addnodes.desc_sig_punctuation] + + def run(self, **kwargs: Any) -> None: + def has_visitor(translator: Type[nodes.NodeVisitor], node: Type[Element]) -> bool: + return hasattr(translator, "visit_%s" % node.__name__) + + translator = self.app.builder.get_translator_class() + if isinstance(translator, SphinxTranslator): + # subclass of SphinxTranslator supports desc_sig_element nodes automatically. + return + + if all(has_visitor(translator, node) for node in self.SIG_ELEMENTS): + # the translator supports all desc_sig_element nodes + return + else: + self.fallback() + + def fallback(self): + for node in self.document.traverse(addnodes.desc_sig_element): + newnode = nodes.inline() + newnode.update_all_atts(node) + newnode.extend(node) + node.replace_self(newnode) + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(ReferencesResolver) app.add_post_transform(OnlyNodeTransform) + app.add_post_transform(SigElementFallbackTransform) return { 'version': 'builtin',