"""Toctree adapter for sphinx.environment. """ from typing import TYPE_CHECKING, Any, Iterable, List, Optional, cast from docutils import nodes from docutils.nodes import Element, Node from sphinx import addnodes from sphinx.locale import __ from sphinx.util import logging, url_re from sphinx.util.matching import Matcher from sphinx.util.nodes import clean_astext, process_only_nodes if TYPE_CHECKING: from sphinx.builders import Builder from sphinx.environment import BuildEnvironment logger = logging.getLogger(__name__) class TocTree: def __init__(self, env: "BuildEnvironment") -> None: self.env = env def note(self, docname: str, toctreenode: addnodes.toctree) -> None: """Note a TOC tree directive in a document and gather information about file relations from it. """ if toctreenode['glob']: self.env.glob_toctrees.add(docname) if toctreenode.get('numbered'): self.env.numbered_toctrees.add(docname) includefiles = toctreenode['includefiles'] for includefile in includefiles: # note that if the included file is rebuilt, this one must be # too (since the TOC of the included file could have changed) self.env.files_to_rebuild.setdefault(includefile, set()).add(docname) self.env.toctree_includes.setdefault(docname, []).extend(includefiles) def resolve(self, docname: str, builder: "Builder", toctree: addnodes.toctree, prune: bool = True, maxdepth: int = 0, titles_only: bool = False, collapse: bool = False, includehidden: bool = False) -> Optional[Element]: """Resolve a *toctree* node into individual bullet lists with titles as items, returning None (if no containing titles are found) or a new node. If *prune* is True, the tree is pruned to *maxdepth*, or if that is 0, to the value of the *maxdepth* option on the *toctree* node. If *titles_only* is True, only toplevel document titles will be in the resulting tree. If *collapse* is True, all branches not containing docname will be collapsed. """ if toctree.get('hidden', False) and not includehidden: return None # For reading the following two helper function, it is useful to keep # in mind the node structure of a toctree (using HTML-like node names # for brevity): # # # # The transformation is made in two passes in order to avoid # interactions between marking and pruning the tree (see bug #1046). toctree_ancestors = self.get_toctree_ancestors(docname) excluded = Matcher(self.env.config.exclude_patterns) def _toctree_add_classes(node: Element, depth: int) -> None: """Add 'toctree-l%d' and 'current' classes to the toctree.""" for subnode in node.children: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for

and

  • , indicate the depth level and recurse subnode['classes'].append('toctree-l%d' % (depth - 1)) _toctree_add_classes(subnode, depth) elif isinstance(subnode, nodes.bullet_list): # for