def process_doc(self, env, docname, document): labels, anonlabels = self.data["labels"], self.data["anonlabels"] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if name.isdigit() or "refuri" in node or node.tagname.startswith("desc_"): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn_node( "duplicate label %s, " % name + "other instance " "in " + env.doc2path(labels[name][0]), node ) anonlabels[name] = docname, labelid if node.tagname == "section": sectname = clean_astext(node[0]) # node[0] == title node elif node.tagname == "figure": for n in node: if n.tagname == "caption": sectname = clean_astext(n) break else: continue elif node.tagname == "image" and node.parent.tagname == "figure": for n in node.parent: if n.tagname == "caption": sectname = clean_astext(n) break else: continue elif node.tagname == "table": for n in node: if n.tagname == "title": sectname = clean_astext(n) break else: continue elif node.tagname == "container" and node.get("literal_block"): for n in node: if n.tagname == "caption": sectname = clean_astext(n) break else: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get("caption"): sectname = n["caption"] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def process_doc(self, env, docname, document): labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if name.isdigit() or 'refuri' in node or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn_node('duplicate label %s, ' % name + 'other instance ' 'in ' + env.doc2path(labels[name][0]), node) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif node.tagname == 'figure': for n in node: if n.tagname == 'caption': sectname = clean_astext(n) break else: continue elif node.tagname == 'image' and node.parent.tagname == 'figure': for n in node.parent: if n.tagname == 'caption': sectname = clean_astext(n) break else: continue elif node.tagname == 'table': for n in node: if n.tagname == 'title': sectname = clean_astext(n) break else: continue elif node.tagname == 'container' and node.get('literal_block'): for n in node: if n.tagname == 'caption': sectname = clean_astext(n) break else: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def test_clean_astext(): node = nodes.paragraph(text='hello world') assert 'hello world' == clean_astext(node) node = nodes.image(alt='hello world') assert '' == clean_astext(node) node = nodes.paragraph(text='hello world') node += nodes.raw('', 'raw text', format='html') assert 'hello world' == clean_astext(node)
def add_kernel_figure_to_std_domain(app, doctree): """Add kernel-figure anchors to 'std' domain. The ``StandardDomain.process_doc(..)`` method does not know how to resolve the caption (label) of ``kernel-figure`` directive (it only knows about standard nodes, e.g. table, figure etc.). Without any additional handling this will result in a 'undefined label' for kernel-figures. This handle adds labels of kernel-figure to the 'std' domain labels. """ std = app.env.domains["std"] docname = app.env.docname labels = std.data["labels"] for name, explicit in iteritems(doctree.nametypes): if not explicit: continue labelid = doctree.nameids[name] if labelid is None: continue node = doctree.ids[labelid] if node.tagname == 'kernel_figure': for n in node.next_node(): if n.tagname == 'caption': sectname = clean_astext(n) # add label to std domain labels[name] = docname, labelid, sectname break
def get_numfig_title(self, node): """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): _, title_getter = self.enumerable_nodes.get(node.__class__, (None, None)) if title_getter: return title_getter(node) else: for subnode in node: if subnode.tagname in ('caption', 'title'): return clean_astext(subnode) return None
def process_doc(self, env, docname, document): labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in document.nametypes.iteritems(): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if name.isdigit() or node.has_key('refuri') or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn(docname, 'duplicate label %s, ' % name + 'other instance in ' + env.doc2path(labels[name][0]), node.line) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif node.tagname == 'figure': for n in node: if n.tagname == 'caption': sectname = clean_astext(n) break else: continue elif node.tagname == 'table': for n in node: if n.tagname == 'title': sectname = clean_astext(n) break else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def get_numfig_title(self, node: Node) -> str: """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): elem = cast(Element, node) _, title_getter = self.enumerable_nodes.get( elem.__class__, (None, None)) if title_getter: return title_getter(elem) else: for subnode in elem: if isinstance(subnode, (nodes.caption, nodes.title)): return clean_astext(subnode) return None
def get_numfig_title(self, node): # type: (nodes.Node) -> unicode """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): _, title_getter = self.enumerable_nodes.get( node.__class__, (None, None)) if title_getter: return title_getter(node) else: for subnode in node: if subnode.tagname in ('caption', 'title'): return clean_astext(subnode) return None
def doctree_read(app, doctree): """ 为了sec-开头标签能正常工作需要将其添加进: env.domains["std"].data["labels"] sec-test: 文章名, 标签名, 章节名, """ labels = app.env.domains["std"].data["labels"] for name, _ in doctree.nametypes.iteritems(): if not name.startswith("sec-"): continue labelid = doctree.nameids[name] node = doctree.ids[labelid].parent if node.tagname == 'section': sectname = clean_astext(node[0]) labels[name] = app.env.docname, labelid, sectname
def make_dlist_items_named(app, document): labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.definition_list_item): if node == node.parent.children[0]: node_labels = node.parent['ids'] else: node_labels = node['ids'] if node_labels: docname = app.env.docname term = clean_astext(node.children[0]) for label in node_labels: labels[label] = (docname, label, term)
def has_toc_yaml(self, subnode: nodes.Element, tocdict: Dict[str, nodes.Element], depth: int) -> None: """constructs toc nodes from globaltoc dict :param subnode: node to which toc constructed here is appended to :param tocdict: dictionary of toc entries :param depth: current toclevel depth """ depth += 1 for key, val in tocdict.items(): if key in ["file", "url"]: internal = False if "title" in tocdict: title = tocdict["title"] else: if val not in self.env.titles: continue title = clean_astext(self.env.titles[val]) if "url" in tocdict: if "http" in tocdict["url"]: internal = False else: continue else: val = "%" + val internal = True reference = nodes.reference( "", "", internal=internal, refuri=val, anchorname="", *[nodes.Text(title)], ) para = addnodes.compact_paragraph("", "", reference) item = nodes.list_item("", para) item["classes"].append("tableofcontents-l%d" % (depth)) subnode.append(item) if key in ["sections"]: sectionlist = nodes.bullet_list().deepcopy() sectionheader = None for item in val: if "part" in item: sectionheader = handle_toc_header(item["part"]) sectionlist.append(sectionheader) del item["part"] has_toc_yaml(self, sectionlist, item, depth) else: has_toc_yaml(self, sectionlist, item, depth) subnode.append(sectionlist)
def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA # directly reference to document by source name; can be absolute or relative refdoc = node.get('refdoc', fromdocname) docname = docname_join(refdoc, node['reftarget']) if docname not in env.all_docs: return None else: if node['refexplicit']: # reference with explicit title caption = node.astext() else: caption = clean_astext(env.titles[docname]) innernode = nodes.inline(caption, caption, classes=['doc']) return make_refnode(builder, fromdocname, docname, None, innernode)
def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA # directly reference to document by source name; can be absolute or relative refdoc = node.get('refdoc', fromdocname) docname = docname_join(refdoc, node['reftarget']) if docname not in env.all_docs: return None else: if node['refexplicit']: # reference with explicit title caption = node.astext() else: caption = clean_astext(env.titles[docname]) innernode = nodes.inline(caption, caption, classes=['doc']) return make_refnode(builder, fromdocname, docname, None, innernode)
def get_objects(self): # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), "doc", doc, "", -1) for (prog, option), info in iteritems(self.data["progoptions"]): yield (option, option, "option", info[0], info[1], 1) for (type, name), info in iteritems(self.data["objects"]): yield (name, name, type, info[0], info[1], self.object_types[type].attrs["searchprio"]) for name, info in iteritems(self.data["labels"]): yield (name, info[2], "label", info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data["labels"]) for name, info in iteritems(self.data["anonlabels"]): if name not in non_anon_labels: yield (name, name, "label", info[0], info[1], -1)
def register_sections_as_label(app, document): labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): name = nodes.fully_normalize_name(node[0].astext()) labelid = node['ids'][0] docname = app.env.docname sectname = clean_astext(node[0]) if name in labels: app.env.warn_node('duplicate label %s, ' % name + 'other instance ' 'in ' + app.env.doc2path(labels[name][0]), node) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname
def _resolve_doc_reference(self, builder, refdoc, node, contnode): # directly reference to document by source name; # can be absolute or relative docname = docname_join(refdoc, node['reftarget']) if docname in self.all_docs: if node['refexplicit']: # reference with explicit title caption = node.astext() else: caption = clean_astext(self.titles[docname]) innernode = nodes.inline(caption, caption) innernode['classes'].append('doc') newnode = nodes.reference('', '', internal=True) newnode['refuri'] = builder.get_relative_uri(refdoc, docname) newnode.append(innernode) return newnode
def get_objects(self): # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in iteritems(self.data['progoptions']): yield (option, option, 'cmdoption', info[0], info[1], 1) for (type, name), info in iteritems(self.data['objects']): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in iteritems(self.data['labels']): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in iteritems(self.data['anonlabels']): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1)
def _resolve_doc_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", typ: str, target: str, node: pending_xref, contnode: Element) -> Element: # directly reference to document by source name; can be absolute or relative refdoc = node.get('refdoc', fromdocname) docname = docname_join(refdoc, node['reftarget']) if docname not in env.all_docs: return None else: if node['refexplicit']: # reference with explicit title caption = node.astext() else: caption = clean_astext(env.titles[docname]) innernode = nodes.inline(caption, caption, classes=['doc']) return make_refnode(builder, fromdocname, docname, None, innernode)
def get_objects(self): # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in iteritems(self.data['progoptions']): yield (option, option, 'option', info[0], info[1], 1) for (type, name), info in iteritems(self.data['objects']): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in iteritems(self.data['labels']): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in iteritems(self.data['anonlabels']): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1)
def _handle_toc_header(self, subnode, val, depth): """ Constructs node for the headers in globaltoc """ if val in self.env.titles: title = clean_astext(self.env.titles[val]) val = "/" + val + self.env.app.builder.out_suffix reference = nodes.reference("", "", internal=False, refuri=val, anchorname="", *[nodes.Text(title)]) para = addnodes.compact_paragraph("", "", reference) else: para = addnodes.compact_paragraph("", "", nodes.Text(val)) item = nodes.list_item("", para) item["classes"].append("fs-1-2") return item
def register_sections_as_label(app, document): labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): labelid = node['ids'][0] docname = app.env.docname if app.config.autosectionlabel_prefix_document: name = nodes.fully_normalize_name(docname + ':' + node[0].astext()) else: name = nodes.fully_normalize_name(node[0].astext()) sectname = clean_astext(node[0]) if name in labels: logger.warning('duplicate label %s, ' % name + 'other instance ' 'in ' + app.env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname
def note_labels(self, env, docname, document): # type: (BuildEnvironment, str, nodes.document) -> None labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in document.nametypes.items(): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if isinstance(node, nodes.target) and 'refid' in node: # indirect hyperlink targets node = document.ids.get(node['refid']) labelid = node['names'][0] if (node.tagname == 'footnote' or 'refuri' in node or node.tagname.startswith('desc_')): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: logger.warning(__('duplicate label %s, other instance in %s'), name, env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid if node.tagname in ('section', 'rubric'): title = cast(nodes.title, node[0]) sectname = clean_astext(title) elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if not sectname: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in self.progoptions.items(): if prog: fullname = ".".join([prog, option]) yield (fullname, fullname, 'cmdoption', info[0], info[1], 1) else: yield (option, option, 'cmdoption', info[0], info[1], 1) for (type, name), info in self.objects.items(): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, (docname, labelid, sectionname) in self.labels.items(): yield (name, sectionname, 'label', docname, labelid, -1) # add anonymous-only labels as well non_anon_labels = set(self.labels) for name, (docname, labelid) in self.anonlabels.items(): if name not in non_anon_labels: yield (name, name, 'label', docname, labelid, -1)
def register_sections_as_label(app, document): # type: (Sphinx, nodes.Node) -> None labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): labelid = node['ids'][0] docname = app.env.docname if app.config.autosectionlabel_prefix_document: name = nodes.fully_normalize_name(docname + ':' + node[0].astext()) else: name = nodes.fully_normalize_name(node[0].astext()) sectname = clean_astext(node[0]) if name in labels: logger.warning('duplicate label %s, ' % name + 'other instance ' 'in ' + app.env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname
def register_sections_as_label(app, document): # type: (Sphinx, nodes.Node) -> None labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): labelid = node['ids'][0] docname = app.env.docname ref_name = getattr(node[0], 'rawsource', node[0].astext()) if app.config.autosectionlabel_prefix_document: name = nodes.fully_normalize_name(docname + ':' + ref_name) print('{} + {} => {}'.format(docname, ref_name, name)) else: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(node[0]) if name in labels: logger.warning(__('duplicate label %s, other instance in %s'), name, app.env.doc2path(labels[name][0])) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname
def get_objects(self): # type: () -> Iterator[Tuple[str, str, str, str, str, int]] # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in self.data['progoptions'].items(): if prog: fullname = ".".join([prog, option]) yield (fullname, fullname, 'cmdoption', info[0], info[1], 1) else: yield (option, option, 'cmdoption', info[0], info[1], 1) for (type, name), info in self.data['objects'].items(): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in self.data['labels'].items(): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in self.data['anonlabels'].items(): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1)
def get_objects(self): # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]] # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in self.data['progoptions'].items(): if prog: fullname = ".".join([prog, option]) yield (fullname, fullname, 'cmdoption', info[0], info[1], 1) else: yield (option, option, 'cmdoption', info[0], info[1], 1) for (type, name), info in self.data['objects'].items(): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in self.data['labels'].items(): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in self.data['anonlabels'].items(): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1)
def render_heading(self, token: SyntaxTreeNode) -> None: """This extends the docutils method, to allow for the addition of heading ids. These ids are computed by the ``markdown-it-py`` ``anchors_plugin`` as "slugs" which are unique to a document. The approach is similar to ``sphinx.ext.autosectionlabel`` """ super().render_heading(token) if not isinstance(self.current_node, nodes.section): return # create the slug string slug = cast(str, token.attrGet("id")) if slug is None: return section = self.current_node doc_slug = self.doc_env.doc2path(self.doc_env.docname, base=False) + "#" + slug # save the reference in the standard domain, so that it can be handled properly domain = cast(StandardDomain, self.doc_env.get_domain("std")) if doc_slug in domain.labels: other_doc = self.doc_env.doc2path(domain.labels[doc_slug][0]) self.create_warning( f"duplicate label {doc_slug}, other instance in {other_doc}", line=section.line, subtype="anchor", ) labelid = section["ids"][0] domain.anonlabels[doc_slug] = self.doc_env.docname, labelid domain.labels[doc_slug] = ( self.doc_env.docname, labelid, clean_astext(section[0]), ) self.doc_env.metadata[self.doc_env.docname]["myst_anchors"] = True section["myst-anchor"] = doc_slug
def note_labels(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if node.tagname == 'target' and 'refid' in node: # indirect hyperlink targets node = document.ids.get(node['refid']) labelid = node['names'][0] if name.isdigit() or 'refuri' in node or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: logger.warning('duplicate label %s, ' % name + 'other instance ' 'in ' + env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if not sectname: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def render_heading_open(self, token): """This extends the docutils method, to allow for the addition of heading ids. These ids are computed by the ``markdown-it-py`` ``anchors_plugin`` as "slugs" which are unique document. The approach is similar to ``sphinx.ext.autosectionlabel`` """ super().render_heading_open(token) slug = token.attrGet("id") if slug is None: return section = self.current_node doc_slug = self.doc_env.doc2path(self.doc_env.docname, base=None) + "#" + slug # save the reference in the standard domain, so that it can be handled properly domain = self.doc_env.get_domain("std") if doc_slug in domain.labels: LOGGER.warning( __("duplicate label %s, other instance in %s"), doc_slug, self.doc_env.doc2path(domain.labels[doc_slug][0]), location=section, type="myst-anchor", subtype=self.doc_env.docname, ) labelid = section["ids"][0] domain.anonlabels[doc_slug] = self.doc_env.docname, labelid domain.labels[doc_slug] = ( self.doc_env.docname, labelid, clean_astext(section[0]), ) # for debugging if not hasattr(self.doc_env, "myst_anchors"): self.doc_env.myst_anchors = True section["myst-anchor"] = doc_slug
def register_sections_as_label(app, document): # type: (Sphinx, nodes.Node) -> None labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): labelid = node['ids'][0] docname = app.env.docname title = cast(nodes.title, node[0]) ref_name = getattr(title, 'rawsource', title.astext()) if app.config.autosectionlabel_prefix_document: name = nodes.fully_normalize_name(docname + ':' + ref_name) else: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(title) if name in labels: logger.warning(__('duplicate label %s, other instance in %s'), name, app.env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname
def note_labels(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if node.tagname == 'target' and 'refid' in node: # indirect hyperlink targets node = document.ids.get(node['refid']) labelid = node['names'][0] if name.isdigit() or 'refuri' in node or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn_node('duplicate label %s, ' % name + 'other instance ' 'in ' + env.doc2path(labels[name][0]), node) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if not sectname: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname
def register_sections_as_label(app: Sphinx, document: Node) -> None: domain = cast(StandardDomain, app.env.get_domain('std')) for node in document.findall(nodes.section): if (app.config.autosectionlabel_maxdepth and get_node_depth(node) >= app.config.autosectionlabel_maxdepth): continue labelid = node['ids'][0] docname = app.env.docname title = cast(nodes.title, node[0]) ref_name = getattr(title, 'rawsource', title.astext()) if app.config.autosectionlabel_prefix_document: name = nodes.fully_normalize_name(docname + ':' + ref_name) else: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(title) if name in domain.labels: logger.warning(__('duplicate label %s, other instance in %s'), name, app.env.doc2path(domain.labels[name][0]), location=node, type='autosectionlabel', subtype=docname) domain.anonlabels[name] = docname, labelid domain.labels[name] = docname, labelid, sectname
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 _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 title_getter(node): """Return the title of a node (or "").""" for elem in node: if isinstance(elem, _TitleNode): return clean_astext(elem) return ""
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 _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(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 _has_toc_yaml(self, subnode, tocdict, depth): """ constructs toc nodes from globaltoc dict """ depth += 1 for key, val in tocdict.items(): if key == "header": header = self._handle_toc_header(subnode, val, depth) subnode["classes"].append("ls-none") subnode.append(header) if key in ["file", "url"]: if "title" in tocdict: title = tocdict["title"] else: if val not in self.env.titles: continue title = clean_astext(self.env.titles[val]) if key == "url": if "http" in val: val = val internal = False else: # since "file" key will be anyways for each "url" key continue else: if self.config.master_doc: subpath = str(Path(self.config.master_doc).parent) # taking paths relative to master_doc if subpath in val: val = str(Path(val).relative_to(subpath)) val = val + self.env.app.builder.out_suffix internal = True reference = nodes.reference("", "", internal=internal, refuri=val, anchorname="", *[nodes.Text(title)]) para = addnodes.compact_paragraph("", "", reference) item = nodes.list_item("", para) item["classes"].append("tableofcontents-l%d" % (depth)) subnode.append(item) if key == "sections": sectionlist = nodes.bullet_list().deepcopy() sectionheader = None headerlist = None for item in val: if "header" in item: if headerlist: sectionlist["classes"].append("ls-none") sectionlist.append(sectionheader) sectionlist.append(headerlist) headerlist = nodes.bullet_list().deepcopy() sectionheader = self._handle_toc_header( sectionlist, item["header"], depth) else: if headerlist: self._has_toc_yaml(headerlist, item, depth) else: self._has_toc_yaml(sectionlist, item, depth) # handling for last header in the section if headerlist: sectionlist["classes"].append("ls-none") sectionlist.append(sectionheader) sectionlist.append(headerlist) subnode.append(sectionlist)