def create_toc(app, pagename): tt = TocTree(app.env) toctree = tt.get_toc_for(pagename, app.builder) if toctree is not None: subtree = toctree[toctree.first_child_matching_class(nodes.list_item)] bl = subtree.first_child_matching_class(nodes.bullet_list) if bl is None: return # Empty ToC subtree = subtree[bl] for li in subtree.traverse(nodes.list_item): modify_li(li) subtree['ids'] = [ID] return '<style>' + CSS + '</style>' + app.builder.render_partial( subtree)['fragment']
def test_get_toctree_for_maxdepth(app): app.build() toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, maxdepth=3) assert_node(toctree, [ compact_paragraph, ([title, "Table of Contents"], bullet_list, bullet_list, bullet_list) ]) assert_node( toctree[1], ([list_item, ([compact_paragraph, reference, "foo"], bullet_list) ], [list_item, compact_paragraph, reference, "bar"], [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], [ list_item, compact_paragraph, reference, "Welcome to Sphinx Tests’s documentation!" ])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [ list_item, ([compact_paragraph, reference, "foo.1"], bullet_list) ], [list_item, compact_paragraph, reference, "foo.2"])) assert_node( toctree[1][0][1][1][1], [bullet_list, list_item, compact_paragraph, reference, "foo.1-1"]) assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1]) assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2]) assert_node(toctree[1][0][1][1][1][0][0][0], reference, refuri="foo#foo-1-1", secnumber=[1, 2, 1]) assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[1][3][0][0], reference, refuri="") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) assert_node(toctree[3], ([list_item, compact_paragraph, reference, "Latest reference" ], [list_item, compact_paragraph, reference, "Python"])) assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/") assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
def get_doc_context(self, docname: str, body: str, metatags: str) -> Dict[str, Any]: # no relation links... toctree = TocTree(self.env).get_toctree_for(self.config.root_doc, self, False) # if there is no toctree, toc is None if toctree: self.fix_refuris(toctree) toc = self.render_partial(toctree)['fragment'] display_toc = True else: toc = '' display_toc = False return { 'parents': [], 'prev': None, 'next': None, 'docstitle': None, 'title': self.config.html_title, 'meta': None, 'body': body, 'metatags': metatags, 'rellinks': [], 'sourcename': '', 'toc': toc, 'display_toc': display_toc, }
def _get_local_toctree(self, docname, collapse=True, **kwds): # type: (unicode, bool, Any) -> unicode if 'includehidden' not in kwds: kwds['includehidden'] = False partials = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwds) return self.render_partial(partials)['fragment']
def test_get_toctree_for_collapse(app): app.build() toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=True) assert_node(toctree, [ compact_paragraph, ([caption, "Table of Contents"], bullet_list, bullet_list, bullet_list) ]) assert_node( toctree[1], ([list_item, compact_paragraph, reference, "foo" ], [list_item, compact_paragraph, reference, "bar"], [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], [ list_item, compact_paragraph, reference, "Welcome to Sphinx Tests’s documentation!" ])) assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[1][3][0][0], reference, refuri="") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) assert_node(toctree[3], ([list_item, compact_paragraph, reference, "Latest reference" ], [list_item, compact_paragraph, reference, "Python"])) assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/") assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: if 'includehidden' not in kwargs: kwargs['includehidden'] = False toctree = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwargs) if toctree is not None: self.fix_refuris(toctree) return self.render_partial(toctree)['fragment']
def test_get_toctree_for_includehidden(app): app.build() toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, includehidden=False) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, bullet_list)]) assert_node(toctree[1], ([list_item, ([compact_paragraph, reference, "foo"], bullet_list)], [list_item, compact_paragraph, reference, "bar"], [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [list_item, compact_paragraph, reference, "foo.1"], [list_item, compact_paragraph, reference, "foo.2"])) assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1]) assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2]) assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"])
def test_get_toc_for_only(app): app.build() builder = StandaloneHTMLBuilder(app) toctree = TocTree(app.env).get_toc_for('index', builder) assert_node(toctree, [bullet_list, ([list_item, (compact_paragraph, # [0][0] [bullet_list, (addnodes.toctree, # [0][1][0] list_item, # [0][1][1] list_item)])], # [0][1][2] [list_item, (compact_paragraph, # [1][0] [bullet_list, (addnodes.toctree, addnodes.toctree)])], [list_item, compact_paragraph])]) # [2][0] assert_node(toctree[0][0], [compact_paragraph, reference, "Welcome to Sphinx Tests’s documentation!"]) assert_node(toctree[0][1][1], ([compact_paragraph, reference, "Section for HTML"], [bullet_list, addnodes.toctree])) assert_node(toctree[0][1][2], ([compact_paragraph, reference, "subsection"], [bullet_list, list_item, compact_paragraph, reference, "subsubsection"])) assert_node(toctree[1][0], [compact_paragraph, reference, "Test for issue #1157"]) assert_node(toctree[2][0], [compact_paragraph, reference, "Indices and tables"])
def get_and_resolve_doctree(self, docname: str, builder: "Builder", doctree: nodes.document = None, prune_toctrees: bool = True, includehidden: bool = False) -> nodes.document: """Read the doctree from the pickle, resolve cross-references and toctrees and return it. """ if doctree is None: doctree = self.get_doctree(docname) # resolve all pending cross-references self.apply_post_transforms(doctree, docname) # now, resolve all toctree nodes for toctreenode in doctree.findall(addnodes.toctree): result = TocTree(self).resolve(docname, builder, toctreenode, prune=prune_toctrees, includehidden=includehidden) if result is None: toctreenode.replace_self([]) else: toctreenode.replace_self(result) return doctree
def get_toctree_for(self, docname, builder, collapse, **kwds): # type: (unicode, Builder, bool, Any) -> addnodes.toctree """Return the global TOC nodetree.""" warnings.warn('env.get_toctree_for() is deprecated. ' 'Use sphinx.environment.adapters.toctre.TocTree instead.', RemovedInSphinx20Warning) return TocTree(self).get_toctree_for(docname, builder, collapse, **kwds)
def get_toc_for(self, docname, builder): # type: (unicode, Builder) -> Dict[unicode, nodes.Node] """Return a TOC nodetree -- for use on the same page only!""" warnings.warn('env.get_toc_for() is deprecated. ' 'Use sphinx.environment.adapters.toctre.TocTree instead.', RemovedInSphinx20Warning) return TocTree(self).get_toc_for(docname, builder)
def toctree(*args, **kwargs): try: # Sphinx >= 1.6 from sphinx.environment.adapters.toctree import TocTree get_toctree_for = TocTree(app.env).get_toctree_for except ImportError: # Sphinx < 1.6 get_toctree_for = app.env.get_toctree_for toc = get_toctree_for( app.config.notfound_pagename, app.builder, collapse=kwargs.pop('collapse', False), includehidden=kwargs.pop('includehidden', False), ** kwargs # not using trailing comma here makes this compatible with # Python2 syntax ) # If no TOC is found, just return ``None`` instead of failing here if not toc: return None replace_uris(app, toc, docutils.nodes.reference, 'refuri') return app.builder.render_partial(toc)['fragment']
def get_and_resolve_doctree(self, docname, builder, doctree=None, prune_toctrees=True, includehidden=False): # type: (unicode, Builder, nodes.Node, bool, bool) -> nodes.Node """Read the doctree from the pickle, resolve cross-references and toctrees and return it. """ if doctree is None: doctree = self.get_doctree(docname) # resolve all pending cross-references self.apply_post_transforms(doctree, docname) # now, resolve all toctree nodes for toctreenode in doctree.traverse(addnodes.toctree): result = TocTree(self).resolve(docname, builder, toctreenode, prune=prune_toctrees, includehidden=includehidden) if result is None: toctreenode.replace_self([]) else: toctreenode.replace_self(result) return doctree
def get_local_toc(self, current_page_name, apply_exact_top_anchor=False): """Return the equivalent of Sphinx "toc" with options for rendering.""" assert self.app.env is not None assert self.app.builder is not None # local toc tree. will be missing the actual anchor for top section toc_tree = TocTree(self.app.env) local_toc_tree = toc_tree.get_toc_for( current_page_name, self.app.builder ) # sphinx "toc" puts '#' as the anchor for the first section, meaning # if you click it, the page jumps to the top (unless you redefine # # which I'd rather not do). This was all fine and good for a sidebar # toc, but a toc at the top of the page this just takes you away # from where you want to go. The lead section of the content # has a real anchorname, so swap that into the toc if apply_exact_top_anchor: # get that top anchor name from the ids the_top_anchor = None sections = list( self.app.env.get_doctree(current_page_name).traverse( docutils_nodes.section ) ) if sections: first_section = sections[0] if first_section.attributes["ids"]: the_top_anchor = first_section.attributes["ids"][0] # have the top anchor and the toctree, put them together! if the_top_anchor: local_toc_tree = local_toc_tree.deepcopy() toc_tree_refs = list( local_toc_tree.traverse(docutils_nodes.reference) ) if toc_tree_refs: toc_tree_refs[0]["anchorname"] = toc_tree_refs[0][ "refuri" ] = f"#{the_top_anchor}" return cast(StandaloneHTMLBuilder, self.app.builder).render_partial( local_toc_tree )["fragment"]
def apply(self, **kwargs): assert 0 source = re.sub('\.[^\.]+$', '', self.document['source']) docname = os.path.relpath(source, self.app.srcdir) self_toc = TocTree(self.env).get_toc_for(docname, self.app.builder) if self_toc and len(self_toc.children) > 0: lt_node = local_toctree('', self_toc); self.document.children.insert(0, lt_node);
def get_page_toc_object(): self_toc = TocTree(self.env).get_toc_for(pagename, self) try: nav = convert_docutils_node(self_toc.children[0]) return nav except: return {}
def get_page_toc_object(): """Return a list of within-page TOC links that can be accessed from Jinja.""" self_toc = TocTree(self.env).get_toc_for(pagename, self) try: nav = convert_docutils_node(self_toc.children[0]) return nav except: return {}
def get_page_toc_object(): """Return a list of within-page TOC links that can be accessed from Jinja.""" self_toc = TocTree(app.env).get_toc_for(pagename, app.builder) try: nav = docutils_node_to_jinja(self_toc.children[0]) return nav except Exception: return {}
def note_toctree(self, docname, toctreenode): # type: (unicode, addnodes.toctree) -> None """Note a TOC tree directive in a document and gather information about file relations from it. """ warnings.warn('env.note_toctree() is deprecated. ' 'Use sphinx.environment.adapters.toctre.TocTree instead.', RemovedInSphinx20Warning) TocTree(self).note(docname, toctreenode)
def get_doc_context(self, docname, body, metatags): out_dict = super(JSONTOCHTMLBuilder, self).get_doc_context(docname, body, metatags) self_toctree = TocTree(self.env).get_toctree_for(docname, self, True) toctree = self.render_partial(self_toctree)['fragment'] out_dict['toctree'] = toctree return out_dict
def test_get_toc_for_tocdepth(app): app.build() toctree = TocTree(app.env).get_toc_for('tocdepth', app.builder) assert_node(toctree, [bullet_list, list_item, (compact_paragraph, # [0][0] bullet_list)]) # [0][1] assert_node(toctree[0][0], [compact_paragraph, reference, "level 1"]) assert_node(toctree[0][1], [bullet_list, list_item, compact_paragraph, reference, "level 2"])
def get_nav_object(**kwds): toctree = TocTree(self.env).get_toctree_for(pagename, self, collapse=True, **kwds) nav = [] for child in toctree.children[0].children: child_nav = convert_docutils_node(child, only_pages=True) nav.append(child_nav) return nav
def build_toc(node, depth=1): # type: (nodes.Node, int) -> List[nodes.Node] entries = [] for sectionnode in node: # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then # resolved in self.get_and_resolve_doctree) if isinstance(sectionnode, addnodes.only): onlynode = addnodes.only(expr=sectionnode['expr']) blist = build_toc(sectionnode, depth) if blist: onlynode += blist.children # type: ignore entries.append(onlynode) continue if not isinstance(sectionnode, nodes.section): for toctreenode in traverse_in_section( sectionnode, addnodes.toctree): item = toctreenode.copy() entries.append(item) # important: do the inventory stuff TocTree(app.env).note(docname, toctreenode) continue title = sectionnode[0] # copy the contents of the section title, but without references # and unnecessary stuff visitor = SphinxContentsFilter(doctree) title.walkabout(visitor) nodetext = visitor.get_entry_text() if not numentries[0]: # for the very first toc entry, don't add an anchor # as it is the file's title anyway anchorname = '' else: anchorname = '#' + sectionnode['ids'][0] numentries[0] += 1 # make these nodes: # list_item -> compact_paragraph -> reference reference = nodes.reference('', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) sub_item = build_toc(sectionnode, depth + 1) item += sub_item entries.append(item) if entries: return nodes.bullet_list('', *entries) return []
def index_toctree(app, pagename: str, startdepth: int, collapse: bool = True, **kwargs): """ Returns the "local" (starting at `startdepth`) TOC tree containing the current page, rendered as HTML bullet lists. This is the equivalent of `context["toctree"](**kwargs)` in sphinx templating, but using the startdepth-local instead of global TOC tree. """ # this is a variant of the function stored in `context["toctree"]`, which is # defined as `lambda **kwargs: self._get_local_toctree(pagename, **kwargs)` # with `self` being the HMTLBuilder and the `_get_local_toctree` basically # returning: # return self.render_partial(TocTree(self.env).get_toctree_for( # pagename, self, collapse, **kwargs))['fragment'] if "includehidden" not in kwargs: kwargs["includehidden"] = False if kwargs.get("maxdepth") == "": kwargs.pop("maxdepth") toctree = TocTree(app.env) ancestors = toctree.get_toctree_ancestors(pagename) try: indexname = ancestors[-startdepth] except IndexError: # eg for index.rst, but also special pages such as genindex, py-modindex, search # those pages don't have a "current" element in the toctree, so we can # directly return an emtpy string instead of using the default sphinx # toctree.get_toctree_for(pagename, app.builder, collapse, **kwargs) return "" toctree_element = _get_local_toctree_for(toctree, indexname, pagename, app.builder, collapse, **kwargs) return app.builder.render_partial(toctree_element)["fragment"]
def index_link_node(app, fromdocname, refs): toc = TocTree(app.env) par_nodes = [] labels = { 'DEF': 'Définitions:', 'USE': 'Usages:', } for type in ['DEF', 'USE']: relevant_refs = [ref for ref in refs if ref['type'] == type] if not relevant_refs: continue par_node = nodes.paragraph(classes=["glossary-refs"]) par_node += nodes.strong(labels[type], labels[type]) for ref in refs: if ref['type'] != type: continue ref_node = nodes.reference('', '') docnames = toc.get_toctree_ancestors(ref['docname']) if not docnames: docnames = [ref['docname']] for i, docname in enumerate(reversed(docnames)): if i < len(docnames) - 1: for child in app.env.titles[docname].children: ref_node.append(child) ref_node.append(nodes.Text('/', '/')) else: strong_node = nodes.strong('', '') for child in app.env.titles[docname].children: strong_node.append(child) ref_node.append(strong_node) ref_node['refdocname'] = ref['docname'] ref_node['refuri'] = app.builder.get_relative_uri( fromdocname, ref['docname']) ref_node['refuri'] += "#" + ref['target_id'] par_node += ref_node par_nodes.append(par_node) return par_nodes
def crawl_toc(node: Element, depth: int = 1) -> None: crawled[node] = True for j, subnode in enumerate(node): try: if (isinstance(subnode, autosummary_toc) and isinstance(subnode[0], addnodes.toctree)): TocTree(env).note(env.docname, subnode[0]) continue except IndexError: continue if not isinstance(subnode, nodes.section): continue if subnode not in crawled: crawl_toc(subnode, depth + 1)
def get_page_toc_object(): """Return a list of within-page TOC links that can be accessed from Jinja.""" self_toc = TocTree(app.env).get_toc_for(pagename, app.builder) try: # If there's only one child, assume we have a single "title" as top header # so start the TOC at the first item's children (AKA, level 2 headers) if len(self_toc.children) == 1: nav = docutils_node_to_jinja(self_toc.children[0]).get("children", []) else: nav = [docutils_node_to_jinja(item) for item in self_toc.children] return nav except Exception: return {}
def get_nav_object(**kwds): """Return a list of nav links that can be accessed from Jinja.""" toctree = TocTree(self.env).get_toctree_for( pagename, self, collapse=True, **kwds ) # Grab all TOC links from any toctrees on the page toc_items = [item for child in toctree.children for item in child if isinstance(item, docutils.nodes.list_item)] nav = [] for child in toc_items: child_nav = convert_docutils_node(child, only_pages=True) nav.append(child_nav) return nav
def glossary_page_id(app, doctree, docname): glossary_pages = [] index = app.env.config.master_doc doctree_index = app.env.get_doctree(index) for toctreenode in doctree_index.traverse(toctree): toctree_element = TocTree(app.env).resolve(index, app.builder, toctreenode, includehidden=True) if 'glossary_toc' in toctreenode.parent.attributes['names']: glossary_pages = toctreenode['includefiles'] if docname in glossary_pages: for glossary_section in doctree.children: glossary_section.attributes['ids'] = ['glossary-page']
def test_get_toctree_for(app): app.build() toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False) assert_node(toctree, [ compact_paragraph, ([caption, "Table of Contents"], bullet_list, bullet_list, bullet_list) ]) assert_node( toctree[1], ([list_item, ([compact_paragraph, reference, "foo"], bullet_list) ], [list_item, compact_paragraph, reference, "bar"], [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [ list_item, compact_paragraph, reference, "foo.1" ], [list_item, compact_paragraph, reference, "foo.2"])) assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1, )) assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1)) assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2)) assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3)) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2, )) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) assert_node(toctree[3], ([list_item, compact_paragraph, reference, "Latest reference" ], [list_item, compact_paragraph, reference, "Python"])) assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/") assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0, titles_only=False, collapse=False, includehidden=False): # type: (unicode, Builder, addnodes.toctree, bool, int, bool, bool, bool) -> nodes.Node """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. """ return TocTree(self).resolve(docname, builder, toctree, prune, maxdepth, titles_only, collapse, includehidden)