def parse_content(self, toctree): env = self.state.document.settings.env suffixes = env.config.source_suffix # glob target documents all_docnames = env.found_docs.copy() all_docnames.remove(env.docname) # remove current document ret = [] for entry in self.content: if not entry: continue # look for explicit titles ("Some Title <document>") explicit = explicit_title_re.match(entry) if (toctree['glob'] and glob_re.match(entry) and not explicit and not url_re.match(entry)): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: if explicit: ref = explicit.group(2) title = explicit.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': toctree['entries'].append((title, ref)) elif docname not in env.found_docs: ret.append(self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) toctree['entries'].append((title, docname)) toctree['includefiles'].append(docname) # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: toctree['entries'] = list(reversed(toctree['entries'])) return ret
def parse_content(self, toctree): suffixes = self.config.source_suffix # glob target documents all_docnames = self.env.found_docs.copy() all_docnames.remove(self.env.docname) # remove current document ret = [] for entry in self.content: if not entry: continue # look for explicit titles ("Some Title <document>") explicit = explicit_title_re.match(entry) if (toctree['glob'] and glob_re.match(entry) and not explicit and not url_re.match(entry)): patname = docname_join(self.env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: if explicit: ref = explicit.group(2) title = explicit.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(self.env.docname, docname) if url_re.match(ref) or ref == 'self': toctree['entries'].append((title, ref)) elif docname not in self.env.found_docs: ret.append(self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) self.env.note_reread() else: all_docnames.discard(docname) toctree['entries'].append((title, docname)) toctree['includefiles'].append(docname) # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: toctree['entries'] = list(reversed(toctree['entries'])) return ret
def _walk_doctree(docname, doctree, secnum): for subnode in doctree.children: if isinstance(subnode, nodes.section): next_secnum = get_section_number(docname, subnode) if next_secnum: _walk_doctree(docname, subnode, next_secnum) else: _walk_doctree(docname, subnode, secnum) continue elif isinstance(subnode, addnodes.toctree): for title, subdocname in subnode['entries']: if url_re.match(subdocname) or subdocname == 'self': # don't mess with those continue _walk_doc(subdocname, secnum) continue figtype = self.env.get_domain('std').get_figtype( subnode) # type: ignore if figtype and subnode['ids']: register_fignumber(docname, secnum, figtype, subnode) _walk_doctree(docname, subnode, secnum)
def _walk_doctree(docname, doctree, secnum): # type: (unicode, nodes.Node, Tuple[int, ...]) -> None for subnode in doctree.children: if isinstance(subnode, nodes.section): next_secnum = get_section_number(docname, subnode) if next_secnum: _walk_doctree(docname, subnode, next_secnum) else: _walk_doctree(docname, subnode, secnum) continue elif isinstance(subnode, addnodes.toctree): for title, subdocname in subnode['entries']: if url_re.match(subdocname) or subdocname == 'self': # don't mess with those continue _walk_doc(subdocname, secnum) continue figtype = get_figtype(subnode) if figtype and subnode['ids']: register_fignumber(docname, secnum, figtype, subnode) _walk_doctree(docname, subnode, secnum)
def _walk_toctree(toctreenode, depth): if depth == 0: return for (title, ref) in toctreenode['entries']: if url_re.match(ref) or ref == 'self' or ref in assigned: # don't mess with those continue if ref in self.tocs: secnums = self.toc_secnumbers[ref] = {} assigned.add(ref) _walk_toc(self.tocs[ref], secnums, depth, self.env.titles.get(ref)) if secnums != old_secnumbers.get(ref): rewrite_needed.append(ref)
def _walk_toctree(toctreenode, depth): if depth == 0: return for (title, ref) in toctreenode['entries']: if url_re.match(ref) or ref == 'self': # don't mess with those continue elif ref in assigned: self.env.warn_node('%s is already assigned section numbers ' '(nested numbered toctree?)' % ref, toctreenode, type='toc', subtype='secnum') elif ref in self.tocs: secnums = self.toc_secnumbers[ref] = {} assigned.add(ref) _walk_toc(self.tocs[ref], secnums, depth, self.env.titles.get(ref)) if secnums != old_secnumbers.get(ref): rewrite_needed.append(ref)
def _walk_toctree(toctreenode: addnodes.toctree, depth: int) -> None: if depth == 0: return for (title, ref) in toctreenode['entries']: if url_re.match(ref) or ref == 'self': # don't mess with those continue elif ref in assigned: logger.warning(__('%s is already assigned section numbers ' '(nested numbered toctree?)'), ref, location=toctreenode, type='toc', subtype='secnum') elif ref in env.tocs: secnums = {} # type: Dict[str, Tuple[int, ...]] env.toc_secnumbers[ref] = secnums assigned.add(ref) _walk_toc(env.tocs[ref], secnums, depth, env.titles.get(ref)) if secnums != old_secnumbers.get(ref): rewrite_needed.append(ref)
def _walk_toctree(toctreenode, depth): if depth == 0: return for (title, ref) in toctreenode['entries']: if url_re.match(ref) or ref == 'self': # don't mess with those continue elif ref in assigned: logger.warning('%s is already assigned section numbers ' '(nested numbered toctree?)', ref, location=toctreenode, type='toc', subtype='secnum') elif ref in env.tocs: secnums = env.toc_secnumbers[ref] = {} assigned.add(ref) _walk_toc(env.tocs[ref], secnums, depth, env.titles.get(ref)) if secnums != old_secnumbers.get(ref): rewrite_needed.append(ref)
def make_entry(self, title, ref, toctree, all_docnames, warnings): """Make a single toctree entry. Args: title: The optional title of the entry to be displayed. If None, the title will be extracted from the referred document ref: A reference to the linked document; a filename or URL toctree: The toctree to which the entry will be added all_docnames: A sequence of all docnames excluding the document containing this directive. warnings: A sequence of warnings to which additional warnings may be appended """ docname = ref suffixes = self.config.source_suffix excluded = Matcher(self.config.exclude_patterns) # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(self.env.docname, docname) if url_re.match(ref) or ref == 'self': toctree['entries'].append((title, ref)) elif docname not in self.env.found_docs: if excluded(self.env.doc2path(docname, None)): message = 'toctree contains reference to excluded document %r' else: message = 'toctree contains reference to nonexisting document %r' warnings.append( self.state.document.reporter.warning(message % docname, line=self.lineno)) self.env.note_reread() else: all_docnames.discard(docname) toctree['entries'].append((title, docname)) toctree['includefiles'].append(docname)
def parse_iterable(self, references, toctree): """Build a TOC from a series of document links. Args: references: An iterable series of document links toctree: The toctree node. """ # glob target documents all_docnames = self.env.found_docs.copy() all_docnames.remove(self.env.docname) # remove current document warnings = [] for ref in references: if not ref: continue if toctree['glob'] and glob_re.match( ref) and not url_re.match(ref): patname = docname_join(self.env.docname, ref) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: warnings.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % ref, line=self.lineno)) else: self.make_entry(title=None, ref=ref, toctree=toctree, all_docnames=all_docnames, warnings=warnings) return warnings
def _walk_doctree(docname, doctree, secnum): for subnode in doctree.children: if isinstance(subnode, nodes.section): next_secnum = get_section_number(docname, subnode) if next_secnum: _walk_doctree(docname, subnode, next_secnum) else: _walk_doctree(docname, subnode, secnum) continue elif isinstance(subnode, addnodes.toctree): for title, subdocname in subnode['entries']: if url_re.match(subdocname) or subdocname == 'self': # don't mess with those continue _walk_doc(subdocname, secnum) continue figtype = self.env.get_domain('std').get_figtype(subnode) # type: ignore if figtype and subnode['ids']: register_fignumber(docname, secnum, figtype, subnode) _walk_doctree(docname, subnode, secnum)
def my_toctree_run(self): """Show non existing entries of toctree :param sphinx.directives.other.TocTree self: The instance object :rtype: list :return: list of the nodes made in this method Defined to replace the method :meth:`sphinx.directives.other.TocTree.run` Only :code:`%r` following are replaced with :code:`%s` to avoid unreadable string. """ env = self.state.document.settings.env suffixes = env.config.source_suffix glob = 'glob' in self.options caption = self.options.get('caption') if caption: self.options.setdefault('name', nodes.fully_normalize_name(caption)) ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if glob and ('*' in entry or '?' in entry or '[' in entry): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( u'toctree contains reference to nonexisting ' u'document %s' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = caption subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret
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. """ 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): # # <ul> # <li> # <p><a></p> # <p><a></p> # ... # <ul> # ... # </ul> # </li> # </ul> # # 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) def _toctree_add_classes(node, depth): """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 <p> and <li>, 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 <ul>, just recurse _toctree_add_classes(subnode, depth + 1) elif isinstance(subnode, nodes.reference): # for <a>, identify which entries point to the current # document and therefore may not be collapsed if subnode['refuri'] == docname: if not subnode['anchorname']: # give the whole branch a 'current' class # (useful for styling it differently) branchnode = subnode while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent # mark the list_item as "on current page" if subnode.parent.parent.get('iscurrent'): # but only if it's not already done return while subnode: subnode['iscurrent'] = True subnode = subnode.parent def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.env.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: logger.warning( 'circular toctree references ' 'detected, ignoring: %s <- %s', ref, ' <- '.join(parents), location=ref) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree logger.warning( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated', ref, location=toctreenode) except KeyError: # this is raised if the included file does not exist logger.warning( 'toctree contains reference to nonexisting document %r', ref, location=toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries maxdepth = maxdepth or toctree.get('maxdepth', -1) if not titles_only and toctree.get('titlesonly', False): titles_only = True if not includehidden and toctree.get('includehidden', False): includehidden = True # NOTE: previously, this was separate=True, but that leads to artificial # separation when two or more toctree entries form a logical unit, so # separating mode is no longer used -- it's kept here for history's sake tocentries = _entries_from_toctree(toctree, [], separate=False) if not tocentries: return None newnode = addnodes.compact_paragraph('', '') caption = toctree.attributes.get('caption') if caption: caption_node = nodes.caption(caption, '', *[nodes.Text(caption)]) caption_node.line = toctree.line caption_node.source = toctree.source caption_node.rawsource = toctree['rawcaption'] if hasattr(toctree, 'uid'): # move uid to caption_node to translate it caption_node.uid = toctree.uid del toctree.uid newnode += caption_node newnode.extend(tocentries) newnode['toctree'] = True # prune the tree to maxdepth, also set toc depth and current classes _toctree_add_classes(newnode, 1) self._toctree_prune(newnode, 1, prune and maxdepth or 0, collapse) if len(newnode[-1]) == 0: # No titles found return None # set the target paths in the toctrees (they are not known at TOC # generation time) for refnode in newnode.traverse(nodes.reference): if not url_re.match(refnode['refuri']): refnode['refuri'] = builder.get_relative_uri( docname, refnode['refuri']) + refnode['anchorname'] return newnode
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options limit = 'limit' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) sorted_entries = {} for entry in entries: metadata = env.metadata.get(entry[1], {}) if 'date' not in metadata: continue try: pub_date = parse_date(metadata['date']) env.metadata.get(entry[1], {}) except ValueError, exc: continue sorted_entries[pub_date.isoformat()] = entry
def parse_content(self, toctree: addnodes.toctree) -> List[Node]: suffixes = self.config.source_suffix # glob target documents all_docnames = self.env.found_docs.copy() all_docnames.remove(self.env.docname) # remove current document ret: List[Node] = [] excluded = Matcher(self.config.exclude_patterns) for entry in self.content: if not entry: continue # look for explicit titles ("Some Title <document>") explicit = explicit_title_re.match(entry) if (toctree['glob'] and glob_re.match(entry) and not explicit and not url_re.match(entry)): patname = docname_join(self.env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: logger.warning(__( 'toctree glob pattern %r didn\'t match any documents'), entry, location=toctree) else: if explicit: ref = explicit.group(2) title = explicit.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(self.env.docname, docname) if url_re.match(ref) or ref == 'self': toctree['entries'].append((title, ref)) elif docname not in self.env.found_docs: if excluded(self.env.doc2path(docname, None)): message = __( 'toctree contains reference to excluded document %r' ) subtype = 'excluded' else: message = __( 'toctree contains reference to nonexisting document %r' ) subtype = 'not_readable' logger.warning(message, docname, type='toc', subtype=subtype, location=toctree) self.env.note_reread() else: if docname in all_docnames: all_docnames.remove(docname) else: logger.warning( __('duplicated entry found in toctree: %s'), docname, location=toctree) toctree['entries'].append((title, docname)) toctree['includefiles'].append(docname) # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: toctree['entries'] = list(reversed(toctree['entries'])) toctree['includefiles'] = list(reversed(toctree['includefiles'])) return ret
def new_resolve_toctree_v122(self, docname, builder, toctree, prune=True, maxdepth=0, titles_only=False, collapse=False, includehidden=False): """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 # photron: prepare reverse toctree lookup to avoid expaning the whole # tree every time. only expand the path to the current document if not hasattr(self, 'monkey_reverse_toctree'): self.monkey_reverse_toctree = self.monkey_get_reverse_toctree() # photron: end # 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): # # <ul> # <li> # <p><a></p> # <p><a></p> # ... # <ul> # ... # </ul> # </li> # </ul> # # The transformation is made in two passes in order to avoid # interactions between marking and pruning the tree (see bug #1046). def _toctree_prune_v122(node, depth, maxdepth): """Utility: Cut a TOC at a specified depth.""" for subnode in node.children[:]: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for <p> and <li>, just recurse _toctree_prune_v122(subnode, depth, maxdepth) elif isinstance(subnode, nodes.bullet_list): # for <ul>, determine if the depth is too large or if the # entry is to be collapsed if maxdepth > 0 and depth > maxdepth: subnode.parent.replace(subnode, []) else: mindepth = 2 # photron: keep the first level expanded, was set to 1 before # cull sub-entries whose parents aren't 'current' if (collapse and depth > mindepth and 'iscurrent' not in subnode.parent): subnode.parent.remove(subnode) else: # recurse on visible children _toctree_prune_v122(subnode, depth+1, maxdepth) def _toctree_add_classes_v122(node, depth): """Add 'toctree-l%d' and 'current' classes to the toctree.""" # photron: start if not hasattr(self, 'monkey_breadcrumbs'): self.monkey_breadcrumbs = {} # photron: end for subnode in node.children: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for <p> and <li>, indicate the depth level and recurse subnode['classes'].append('toctree-l%d' % (depth-1)) _toctree_add_classes_v122(subnode, depth) elif isinstance(subnode, nodes.bullet_list): # for <ul>, just recurse _toctree_add_classes_v122(subnode, depth+1) elif isinstance(subnode, nodes.reference): # for <a>, identify which entries point to the current # document and therefore may not be collapsed if subnode['refuri'] == docname: if not subnode['anchorname']: # photron: start breadcrumbs = [] # photron: end # give the whole branch a 'current' class # (useful for styling it differently) branchnode = subnode while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent # photron: collect current path in toctree as breadcrumbs if branchnode and isinstance(branchnode, nodes.list_item): for c in branchnode.traverse(nodes.reference): if len(c.children) == 0: raise Exception('Missing reference text node id breadcrumbs for ' + docname) breadcrumbs = [(c['refuri'], c['anchorname'], c.children[0].astext())] + breadcrumbs break # photron: end # photron: sanity check if docname in self.monkey_breadcrumbs and self.monkey_breadcrumbs[docname] != breadcrumbs: raise Exception('Different breadcrumbs for ' + docname) self.monkey_breadcrumbs[docname] = breadcrumbs # photron: end # mark the list_item as "on current page" if subnode.parent.parent.get('iscurrent'): # but only if it's not already done return while subnode: subnode['iscurrent'] = True subnode = subnode.parent def _entries_from_toctree_v122(toctreenode, parents, separate=False, subtree=False, # photron: add forced_expand option to force expansion # one sublevel below the path to the current document forced_expand=False): # photron: end """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: if title != None and title.startswith('~'): continue try: refdoc = None if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.warn(ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): if not (toctreenode.get('hidden', False) and not includehidden): # photron: use the reverse toctree lookup to only expand # nodes along the way to the current document if docname != 'index': if docname not in self.monkey_reverse_toctree: continue if not forced_expand and refdoc not in self.monkey_reverse_toctree[docname]: continue # photron: end # photron: force sublevel for the index and other toplevel documents, # also force it for one sublevel below the path to the current document next_forced_expand = \ docname == 'index' or \ len(self.monkey_reverse_toctree[docname]) == 0 or \ refdoc == self.monkey_reverse_toctree[docname][-1] # photron: end i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree_v122( toctreenode, [refdoc] + parents, subtree=True, # photron: start forced_expand=next_forced_expand): # photron: end toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries maxdepth = maxdepth or toctree.get('maxdepth', -1) if not titles_only and toctree.get('titlesonly', False): titles_only = True if not includehidden and toctree.get('includehidden', False): includehidden = True # NOTE: previously, this was separate=True, but that leads to artificial # separation when two or more toctree entries form a logical unit, so # separating mode is no longer used -- it's kept here for history's sake tocentries = _entries_from_toctree_v122(toctree, [], separate=False, # photron: add forced_expand option to force expansion forced_expand=True) # photron: end if not tocentries: return None newnode = addnodes.compact_paragraph('', '', *tocentries) newnode['toctree'] = True # prune the tree to maxdepth, also set toc depth and current classes _toctree_add_classes_v122(newnode, 1) _toctree_prune_v122(newnode, 1, prune and maxdepth or 0) # set the target paths in the toctrees (they are not known at TOC # generation time) for refnode in newnode.traverse(nodes.reference): if not url_re.match(refnode['refuri']): refnode['refuri'] = builder.get_relative_uri( docname, refnode['refuri']) + refnode['anchorname'] # photron: empty refuri doesn't work in IE, use a # instead if len(refnode['refuri']) == 0: refnode['refuri'] = '#' # photron: end return newnode
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options # (title, ref) pairs, where ref may only be a document # external links are forbidden, since we have no way of dating them # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) ret = [] for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = patfilter(all_docnames, patname) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'latest list glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) subnode = latest() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['glob'] = glob subnode['titlesonly'] = 'titlesonly' in self.options #what does this do? set_source_info(self, subnode) wrappernode = nodes.compound(classes=['feed-latest-wrapper']) wrappernode.append(subnode) ret.append(wrappernode) return ret
def my_toctree_run(self): """Show non existing entries of toctree Used to replace the function -> sphinx.directives.other.TocTree.run Only %r following are replaced %s to avoid unreadable string. """ env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append(self.state.document.reporter.warning( u'toctree contains reference to nonexisting ' u'document %s' % docname, line=self.lineno)) env.note_reread() else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %s didn\'t match any documents' % entry, line=self.lineno)) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['numbered'] = 'numbered' in self.options subnode['titlesonly'] = 'titlesonly' in self.options wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) ret.append(wrappernode) return ret
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. """ 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): # # <ul> # <li> # <p><a></p> # <p><a></p> # ... # <ul> # ... # </ul> # </li> # </ul> # # 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) def _toctree_add_classes(node, depth): """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 <p> and <li>, 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 <ul>, just recurse _toctree_add_classes(subnode, depth+1) elif isinstance(subnode, nodes.reference): # for <a>, identify which entries point to the current # document and therefore may not be collapsed if subnode['refuri'] == docname: if not subnode['anchorname']: # give the whole branch a 'current' class # (useful for styling it differently) branchnode = subnode while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent # mark the list_item as "on current page" if subnode.parent.parent.get('iscurrent'): # but only if it's not already done return while subnode: subnode['iscurrent'] = True subnode = subnode.parent def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.env.warn(ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.env.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.env.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries maxdepth = maxdepth or toctree.get('maxdepth', -1) if not titles_only and toctree.get('titlesonly', False): titles_only = True if not includehidden and toctree.get('includehidden', False): includehidden = True # NOTE: previously, this was separate=True, but that leads to artificial # separation when two or more toctree entries form a logical unit, so # separating mode is no longer used -- it's kept here for history's sake tocentries = _entries_from_toctree(toctree, [], separate=False) if not tocentries: return None newnode = addnodes.compact_paragraph('', '') caption = toctree.attributes.get('caption') if caption: caption_node = nodes.caption(caption, '', *[nodes.Text(caption)]) caption_node.line = toctree.line caption_node.source = toctree.source caption_node.rawsource = toctree['rawcaption'] if hasattr(toctree, 'uid'): # move uid to caption_node to translate it caption_node.uid = toctree.uid del toctree.uid newnode += caption_node newnode.extend(tocentries) newnode['toctree'] = True # prune the tree to maxdepth, also set toc depth and current classes _toctree_add_classes(newnode, 1) self._toctree_prune(newnode, 1, prune and maxdepth or 0, collapse) if len(newnode[-1]) == 0: # No titles found return None # set the target paths in the toctrees (they are not known at TOC # generation time) for refnode in newnode.traverse(nodes.reference): if not url_re.match(refnode['refuri']): refnode['refuri'] = builder.get_relative_uri( docname, refnode['refuri']) + refnode['anchorname'] return newnode
def run(self): env = self.state.document.settings.env suffixes = env.config.source_suffix glob = 'glob' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns try: all_docnames.remove(env.docname) except KeyError: if env.docname == "<<string>>": # This comes from rst2html. pass else: logger = logging.getLogger("CustomTocTreeCollector") logger.warning( "[CustomTocTreeCollector] unable to remove document '{0}' from {1}" .format(env.docname, ", ".join(all_docnames))) for entry in self.content: if not entry: continue if glob and ('*' in entry or '?' in entry or '[' in entry): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( '[CustomTocTree] glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( '[CustomTocTree] contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: entries.reverse() subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = self.options.get('caption') subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] includetitles = {} all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = caption_ref_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) # elif docname not in env.found_docs: # ret.append(self.state.document.reporter.warning( # 'toctree references unknown document %r' % docname, # line=self.lineno)) else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['numbered'] = 'numbered' in self.options ret.append(subnode) return ret
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options # (title, ref) pairs, where ref may only be a document # external links are forbidden, since we have no way of dating them # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) ret = [] for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append(self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = patfilter(all_docnames, patname) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'latest list glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) subnode = latest() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['glob'] = glob subnode['titlesonly'] = 'titlesonly' in self.options #what does this do? set_source_info(self, subnode) wrappernode = nodes.compound(classes=['feed-latest-wrapper']) wrappernode.append(subnode) ret.append(wrappernode) return ret
def run(self): # type: () -> List[nodes.Node] suffixes = self.config.source_suffix glob = 'glob' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] # type: List[Tuple[unicode, unicode]] includefiles = [] all_docnames = self.env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(self.env.docname) for entry in self.content: if not entry: continue # look for explicit titles ("Some Title <document>") explicit = explicit_title_re.match(entry) if glob and ('*' in entry or '?' in entry or '[' in entry) and not explicit: patname = docname_join(self.env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) # type: ignore for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: if explicit: ref = explicit.group(2) title = explicit.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(self.env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in self.env.found_docs: ret.append( self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) self.env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = self.env.docname # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: entries.reverse() subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = self.options.get('caption') subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret
def run(self): # type: () -> List[nodes.Node] env = self.state.document.settings.env suffixes = env.config.source_suffix glob = 'glob' in self.options ret = [] # Children of the internal toctree node; these will be rewritten by # traversals (and so having other references into these will also # get rewritten) but, nicely, are not rendered directly due to the # way that the environment code deals with toctrees. others = [] # (title, ref) pairs, where ref may be a document, or an external link, # or a node. title may be None if the document's title is to be used # and must be None if a node is given as a ref. entries = [] # type: List[Tuple[unicode, Union[unicode,nodes.Node]]] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if entry.startswith("_ "): node = nodes.paragraph() self.state.nested_parse(ViewList([entry[2:]]), 0, node) others.append(node) entries.append((None, node)) elif glob and ('*' in entry or '?' in entry or '[' in entry): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: entries.reverse() subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = self.options.get('caption') subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options subnode.children = others set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret
def _entries_from_toctree(toctreenode, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], to_unicode(e[1])) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) # added 1.1 if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn(docname, 'toctree contains reference to document ' '%r that doesn\'t have a title: no link ' 'will be generated' % ref, toctreenode.line) except KeyError: # this is raised if the included file does not exist self.warn(docname, 'toctree contains reference to ' 'nonexisting document %r' % ref, toctreenode.line) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree(toctreenode, subtree=True): toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def _entries_from_toctree_v122(toctreenode, parents, separate=False, subtree=False, # photron: add forced_expand option to force expansion # one sublevel below the path to the current document forced_expand=False): # photron: end """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: if title != None and title.startswith('~'): continue try: refdoc = None if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.warn(ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): if not (toctreenode.get('hidden', False) and not includehidden): # photron: use the reverse toctree lookup to only expand # nodes along the way to the current document if docname != 'index': if docname not in self.monkey_reverse_toctree: continue if not forced_expand and refdoc not in self.monkey_reverse_toctree[docname]: continue # photron: end # photron: force sublevel for the index and other toplevel documents, # also force it for one sublevel below the path to the current document next_forced_expand = \ docname == 'index' or \ len(self.monkey_reverse_toctree[docname]) == 0 or \ refdoc == self.monkey_reverse_toctree[docname][-1] # photron: end i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree_v122( toctreenode, [refdoc] + parents, subtree=True, # photron: start forced_expand=next_forced_expand): # photron: end toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def my_resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0, titles_only=False, collapse=False, includehidden=False): """alter 'sphinx.environment.BuildEnvironment.resolve_toctree'. Very long copied function but only to replace one str() with unicode() :-( Note: Difference of this function between 1.0.7 and 1.1pre is only 1 line. search to see "added 1.1". Original description is following: 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 def _walk_depth(node, depth, maxdepth): """Utility: Cut a TOC at a specified depth.""" # For reading this function, it is useful to keep in mind the node # structure of a toctree (using HTML-like node names for brevity): # # <ul> # <li> # <p><a></p> # <p><a></p> # ... # <ul> # ... # </ul> # </li> # </ul> for subnode in node.children[:]: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for <p> and <li>, just indicate the depth level and # recurse to children subnode['classes'].append('toctree-l%d' % (depth-1)) _walk_depth(subnode, depth, maxdepth) elif isinstance(subnode, nodes.bullet_list): # for <ul>, determine if the depth is too large or if the # entry is to be collapsed if maxdepth > 0 and depth > maxdepth: subnode.parent.replace(subnode, []) else: # to find out what to collapse, *first* walk subitems, # since that determines which children point to the # current page _walk_depth(subnode, depth+1, maxdepth) # cull sub-entries whose parents aren't 'current' if (collapse and depth > 1 and 'iscurrent' not in subnode.parent): subnode.parent.remove(subnode) elif isinstance(subnode, nodes.reference): # for <a>, identify which entries point to the current # document and therefore may not be collapsed if subnode['refuri'] == docname: if not subnode['anchorname']: # give the whole branch a 'current' class # (useful for styling it differently) branchnode = subnode while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent # mark the list_item as "on current page" if subnode.parent.parent.get('iscurrent'): # but only if it's not already done return while subnode: subnode['iscurrent'] = True subnode = subnode.parent def _entries_from_toctree(toctreenode, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], to_unicode(e[1])) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) # added 1.1 if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn(docname, 'toctree contains reference to document ' '%r that doesn\'t have a title: no link ' 'will be generated' % ref, toctreenode.line) except KeyError: # this is raised if the included file does not exist self.warn(docname, 'toctree contains reference to ' 'nonexisting document %r' % ref, toctreenode.line) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree(toctreenode, subtree=True): toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries maxdepth = maxdepth or toctree.get('maxdepth', -1) if not titles_only and toctree.get('titlesonly', False): titles_only = True # NOTE: previously, this was separate=True, but that leads to artificial # separation when two or more toctree entries form a logical unit, so # separating mode is no longer used -- it's kept here for history's sake tocentries = _entries_from_toctree(toctree, separate=False) if not tocentries: return None newnode = addnodes.compact_paragraph('', '', *tocentries) newnode['toctree'] = True # prune the tree to maxdepth and replace titles, also set level classes _walk_depth(newnode, 1, prune and maxdepth or 0) # set the target paths in the toctrees (they are not known at TOC # generation time) for refnode in newnode.traverse(nodes.reference): if not url_re.match(refnode['refuri']): refnode['refuri'] = builder.get_relative_uri( docname, refnode['refuri']) + refnode['anchorname'] return newnode
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = "glob" in self.options limit = "limit" in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[: -len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == "self": entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( "toctree contains reference to nonexisting " "document %r" % docname, line=self.lineno ) ) env.note_reread() else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( "toctree glob pattern %r didn't match any documents" % entry, line=self.lineno ) ) sorted_entries = {} for entry in entries: metadata = env.metadata.get(entry[1], {}) if "date" not in metadata: continue try: pub_date = parse_date(metadata["date"]) env.metadata.get(entry[1], {}) except ValueError, exc: continue sorted_entries[pub_date.isoformat()] = entry
def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.env.warn(ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.env.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.env.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def new_resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0, titles_only=False, collapse=False, includehidden=False): """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 # photron: prepare reverse toctree lookup to avoid expaning the whole # tree every time. only expand the path to the current document if not hasattr(self, 'monkey_reverse_toctree'): self.monkey_reverse_toctree = self.monkey_get_reverse_toctree() # photron: end # 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): # # <ul> # <li> # <p><a></p> # <p><a></p> # ... # <ul> # ... # </ul> # </li> # </ul> # # The transformation is made in two passes in order to avoid # interactions between marking and pruning the tree (see bug #1046). def _toctree_prune(node, depth, maxdepth): """Utility: Cut a TOC at a specified depth.""" for subnode in node.children[:]: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for <p> and <li>, just recurse _toctree_prune(subnode, depth, maxdepth) elif isinstance(subnode, nodes.bullet_list): # for <ul>, determine if the depth is too large or if the # entry is to be collapsed if maxdepth > 0 and depth > maxdepth: subnode.parent.replace(subnode, []) else: mindepth = 2 # photron: keep the first level expanded, was set to 1 before # cull sub-entries whose parents aren't 'current' if (collapse and depth > mindepth and 'iscurrent' not in subnode.parent): subnode.parent.remove(subnode) else: # recurse on visible children _toctree_prune(subnode, depth + 1, maxdepth) def _toctree_add_classes(node, depth): """Add 'toctree-l%d' and 'current' classes to the toctree.""" # photron: start if not hasattr(self, 'monkey_breadcrumbs'): self.monkey_breadcrumbs = {} # photron: end for subnode in node.children: if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)): # for <p> and <li>, 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 <ul>, just recurse _toctree_add_classes(subnode, depth + 1) elif isinstance(subnode, nodes.reference): # for <a>, identify which entries point to the current # document and therefore may not be collapsed if subnode['refuri'] == docname: if not subnode['anchorname']: # photron: start breadcrumbs = [] # photron: end # give the whole branch a 'current' class # (useful for styling it differently) branchnode = subnode while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent # photron: collect current path in toctree as breadcrumbs if branchnode and isinstance( branchnode, nodes.list_item): for c in branchnode.traverse( nodes.reference): if len(c.children) == 0: raise Exception( 'Missing reference text node id breadcrumbs for ' + docname) breadcrumbs = [ (c['refuri'], c['anchorname'], c.children[0].astext()) ] + breadcrumbs break # photron: end # photron: sanity check if docname in self.monkey_breadcrumbs and self.monkey_breadcrumbs[ docname] != breadcrumbs: raise Exception('Different breadcrumbs for ' + docname) self.monkey_breadcrumbs[docname] = breadcrumbs # photron: end # mark the list_item as "on current page" if subnode.parent.parent.get('iscurrent'): # but only if it's not already done return while subnode: subnode['iscurrent'] = True subnode = subnode.parent def _entries_from_toctree( toctreenode, parents, separate=False, subtree=False, # photron: add forced_expand option to force expansion # one sublevel below the path to the current document forced_expand=False): # photron: end """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.warn( ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): if not (toctreenode.get('hidden', False) and not includehidden): # photron: use the reverse toctree lookup to only expand # nodes along the way to the current document if docname != 'index': if docname not in self.monkey_reverse_toctree: continue if not forced_expand and refdoc not in self.monkey_reverse_toctree[ docname]: continue # photron: end # photron: force sublevel for the index and other toplevel documents, # also force it for one sublevel below the path to the current document next_forced_expand = \ docname == 'index' or \ len(self.monkey_reverse_toctree[docname]) == 0 or \ refdoc == self.monkey_reverse_toctree[docname][-1] # photron: end i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree( toctreenode, [refdoc] + parents, subtree=True, # photron: start forced_expand=next_forced_expand): # photron: end toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries maxdepth = maxdepth or toctree.get('maxdepth', -1) if not titles_only and toctree.get('titlesonly', False): titles_only = True if not includehidden and toctree.get('includehidden', False): includehidden = True # NOTE: previously, this was separate=True, but that leads to artificial # separation when two or more toctree entries form a logical unit, so # separating mode is no longer used -- it's kept here for history's sake tocentries = _entries_from_toctree(toctree, [], separate=False, forced_expand=True) if not tocentries: return None newnode = addnodes.compact_paragraph('', '', *tocentries) newnode['toctree'] = True # prune the tree to maxdepth, also set toc depth and current classes _toctree_add_classes(newnode, 1) _toctree_prune(newnode, 1, prune and maxdepth or 0) # set the target paths in the toctrees (they are not known at TOC # generation time) for refnode in newnode.traverse(nodes.reference): if not url_re.match(refnode['refuri']): refnode['refuri'] = builder.get_relative_uri( docname, refnode['refuri']) + refnode['anchorname'] # photron: empty refuri doesn't work in IE, use a # instead if len(refnode['refuri']) == 0: refnode['refuri'] = '#' # photron: end return newnode
def _entries_from_toctree( toctreenode, parents, separate=False, subtree=False, # photron: add forced_expand option to force expansion # one sublevel below the path to the current document forced_expand=False): # photron: end """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: self.warn( ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() self.process_only_nodes(toc, builder, ref) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): if not (toctreenode.get('hidden', False) and not includehidden): # photron: use the reverse toctree lookup to only expand # nodes along the way to the current document if docname != 'index': if docname not in self.monkey_reverse_toctree: continue if not forced_expand and refdoc not in self.monkey_reverse_toctree[ docname]: continue # photron: end # photron: force sublevel for the index and other toplevel documents, # also force it for one sublevel below the path to the current document next_forced_expand = \ docname == 'index' or \ len(self.monkey_reverse_toctree[docname]) == 0 or \ refdoc == self.monkey_reverse_toctree[docname][-1] # photron: end i = toctreenode.parent.index(toctreenode) + 1 for item in _entries_from_toctree( toctreenode, [refdoc] + parents, subtree=True, # photron: start forced_expand=next_forced_expand): # photron: end toctreenode.parent.insert(i, item) i += 1 toctreenode.parent.remove(toctreenode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def _entries_from_toctree(self, docname, toctreenode, separate=False, subtree=True): """ Copied from sphinx.environment. Modified to utilize list items instead of the old version which had an independent bullet_list for each entry. """ refs = [(e[0], str(e[1])) for e in toctreenode['entries']] # EV: instead of a [], use a bullet_list entries = nodes.bullet_list() for (title, ref) in refs: try: if url_re.match(ref): reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: # EV: get the tocs reference using self.env.main_tocs instead of just # self.tocs #toc = self.tocs[ref].deepcopy() toc = self.env.main_tocs[ref].deepcopy() if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.warn(docname, 'toctree contains reference to document ' '%r that doesn\'t have a title: no link ' 'will be generated' % ref) except KeyError: # this is raised if the included file does not exist self.warn(docname, 'toctree contains reference to ' 'nonexisting document %r' % ref) else: # EV: copied over from 0.6.3, but outside of Environment, we don't have the # titles_only var. # # if titles_only is given, only keep the main title and # # sub-toctrees # if titles_only: # # delete everything but the toplevel title(s) # # and toctrees # for toplevel in toc: # # nodes with length 1 don't have any children anyway # if len(toplevel) > 1: # subtrees = toplevel.traverse(addnodes.toctree) # toplevel[1][:] = subtrees # resolve all sub-toctrees for toctreenode in toc.traverse(addnodes.toctree): #i = toctreenode.parent.index(toctreenode) + 1 #for item in self._entries_from_toctree(toctreenode, subtree=True): # toctreenode.parent.insert(i, item) # i += 1 #toctreenode.parent.remove(toctreenode) toctreenode.parent.replace_self( self._entries_from_toctree(docname, toctreenode, subtree=True)) # EV: append each child as a list item in the bullet_list. #if separate: # entries.append(toc) #else: # entries.extend(toc.children) for child in toc.children: entries.append(child) # EV: pass the entries in as a single element instead of a list of elements. # if not subtree and not separate: # ret = nodes.bullet_list() # ret += entries # return [ret] # return entries return addnodes.compact_paragraph('', '', entries)
def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref reference = nodes.reference('', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) toc = nodes.bullet_list('', item) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.env.titles[ref]) reference = nodes.reference('', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # don't show subitems toc = nodes.bullet_list('', item) else: if ref in parents: logger.warning( 'circular toctree references ' 'detected, ignoring: %s <- %s', ref, ' <- '.join(parents), location=ref) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree logger.warning( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated', ref, location=toctreenode) except KeyError: # this is raised if the included file does not exist logger.warning( 'toctree contains reference to nonexisting document %r', ref, location=toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def run(self): env = self.state.document.settings.env suffix = env.config.source_suffix glob = 'glob' in self.options ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] includetitles = {} all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if not glob: # look for explicit titles ("Some Title <document>") m = caption_ref_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) if docname.endswith(suffix): docname = docname[:-len(suffix)] # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append( self.state.document.reporter.warning( 'toctree references unknown document %r' % docname, line=self.lineno)) else: entries.append((title, docname)) includefiles.append(docname) else: patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append( self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['numbered'] = 'numbered' in self.options ret.append(subnode) return ret
def run(self): env = self.state.document.settings.env suffixes = env.config.source_suffix glob = 'glob' in self.options caption = self.options.get('caption') if caption: self.options.setdefault('name', nodes.fully_normalize_name(caption)) ret = [] # (title, ref) pairs, where ref may be a document, or an external link, # and title may be None if the document's title is to be used entries = [] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if glob and ('*' in entry or '?' in entry or '[' in entry): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append(self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = caption subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret
def run(self): # type: () -> List[nodes.Node] env = self.state.document.settings.env suffixes = env.config.source_suffix glob = 'glob' in self.options ret = [] # Children of the internal toctree node; these will be rewritten by # traversals (and so having other references into these will also # get rewritten) but, nicely, are not rendered directly due to the # way that the environment code deals with toctrees. others = [] # (title, ref) pairs, where ref may be a document, or an external link, # or a node. title may be None if the document's title is to be used # and must be None if a node is given as a ref. entries = [] # type: List[Tuple[unicode, Union[unicode,nodes.Node]]] includefiles = [] all_docnames = env.found_docs.copy() # don't add the currently visited file in catch-all patterns all_docnames.remove(env.docname) for entry in self.content: if not entry: continue if entry.startswith("_ "): node = nodes.paragraph() self.state.nested_parse(ViewList([entry[2:]]), 0, node) others.append(node) entries.append((None, node)) elif glob and ('*' in entry or '?' in entry or '[' in entry): patname = docname_join(env.docname, entry) docnames = sorted(patfilter(all_docnames, patname)) for docname in docnames: all_docnames.remove(docname) # don't include it again entries.append((None, docname)) includefiles.append(docname) if not docnames: ret.append(self.state.document.reporter.warning( 'toctree glob pattern %r didn\'t match any documents' % entry, line=self.lineno)) else: # look for explicit titles ("Some Title <document>") m = explicit_title_re.match(entry) if m: ref = m.group(2) title = m.group(1) docname = ref else: ref = docname = entry title = None # remove suffixes (backwards compatibility) for suffix in suffixes: if docname.endswith(suffix): docname = docname[:-len(suffix)] break # absolutize filenames docname = docname_join(env.docname, docname) if url_re.match(ref) or ref == 'self': entries.append((title, ref)) elif docname not in env.found_docs: ret.append(self.state.document.reporter.warning( 'toctree contains reference to nonexisting ' 'document %r' % docname, line=self.lineno)) env.note_reread() else: all_docnames.discard(docname) entries.append((title, docname)) includefiles.append(docname) subnode = addnodes.toctree() subnode['parent'] = env.docname # entries contains all entries (self references, external links etc.) if 'reversed' in self.options: entries.reverse() subnode['entries'] = entries # includefiles only entries that are documents subnode['includefiles'] = includefiles subnode['maxdepth'] = self.options.get('maxdepth', -1) subnode['caption'] = self.options.get('caption') subnode['glob'] = glob subnode['hidden'] = 'hidden' in self.options subnode['includehidden'] = 'includehidden' in self.options subnode['numbered'] = self.options.get('numbered', 0) subnode['titlesonly'] = 'titlesonly' in self.options subnode.children = others set_source_info(self, subnode) wrappernode = nodes.compound(classes=['toctree-wrapper']) wrappernode.append(subnode) self.add_name(wrappernode) ret.append(wrappernode) return ret