Commits

Georg Brandl  committed b6a041f

Move :ref: labels over to std domain.

  • Participants
  • Parent commits 2a9958d

Comments (0)

Files changed (4)

File sphinx/domains/__init__.py

         """
         pass
 
+    def process_doc(self, env, docname, document):
+        """
+        Process a document after it is read by the environment.
+        """
+        pass
+
     def resolve_xref(self, env, fromdocname, builder,
                      typ, target, node, contnode):
         """

File sphinx/domains/std.py

 from sphinx.domains import Domain, ObjType
 from sphinx.directives import ObjectDescription
 from sphinx.util import ws_re
-from sphinx.util.nodes import make_refnode
+from sphinx.util.nodes import clean_astext, make_refnode
 from sphinx.util.compat import Directive
 
 
     object_types = {
         'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
         'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
+        'label': ObjType(l_('reference label'), 'ref', searchprio=-1),
         'envvar': ObjType(l_('environment variable'), 'envvar'),
         'cmdoption': ObjType(l_('program option'), 'option'),
     }
         'productionlist': ProductionList,
     }
     roles = {
-        'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
-        'envvar': EnvVarXRefRole(),
-        'token':  XRefRole(),
-        'term':   XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
+        'option':  OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
+        'envvar':  EnvVarXRefRole(),
+        # links to tokens in grammar productions
+        'token':   XRefRole(),
+        # links to terms in glossary
+        'term':    XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
+        # links to headings or arbitrary labels
+        'ref':     XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
+        # links to labels, without a different title
+        'keyword': XRefRole(),
     }
 
     initial_data = {
         'progoptions': {},  # (program, name) -> docname, labelid
         'objects': {},      # (type, name) -> docname, labelid
+        'labels': {         # labelname -> docname, labelid, sectionname
+            'genindex': ('genindex', '', l_('Index')),
+            'modindex': ('py-modindex', '', l_('Module Index')),
+            'search':   ('search', '', l_('Search Page')),
+        },
+        'anonlabels': {     # labelname -> docname, labelid
+            'genindex': ('genindex', ''),
+            'modindex': ('py-modindex', ''),
+            'search':   ('search', ''),
+        },
     }
 
     def clear_doc(self, docname):
         for key, (fn, _) in self.data['objects'].items():
             if fn == docname:
                 del self.data['objects'][key]
+        for key, (fn, _, _) in self.data['labels'].items():
+            if fn == docname:
+                del self.data['labels'][key]
+        for key, (fn, _) in self.data['anonlabels'].items():
+            if fn == docname:
+                del self.data['anonlabels'][key]
+
+    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
+            else:
+                # anonymous-only labels
+                continue
+            labels[name] = docname, labelid, sectname
 
     def resolve_xref(self, env, fromdocname, builder,
                      typ, target, node, contnode):
-        if typ == 'option':
+        if typ == 'ref':
+            refdoc = node.get('refdoc', fromdocname)
+            if node['refexplicit']:
+                # reference to anonymous label; the reference uses
+                # the supplied link caption
+                docname, labelid = self.data['anonlabels'].get(target, ('',''))
+                sectname = node.astext()
+                if not docname:
+                    env.warn(refdoc, 'undefined label: %s' %
+                              target, node.line)
+            else:
+                # reference to named label; the final node will
+                # contain the section name after the label
+                docname, labelid, sectname = self.data['labels'].get(target,
+                                                                     ('','',''))
+                if not docname:
+                    env.warn(refdoc,
+                        'undefined label: %s' % target + ' -- if you '
+                        'don\'t give a link caption the label must '
+                        'precede a section header.', node.line)
+            if not docname:
+                return None
+            newnode = nodes.reference('', '')
+            innernode = nodes.emphasis(sectname, sectname)
+            if docname == fromdocname:
+                newnode['refid'] = labelid
+            else:
+                # set more info in contnode; in case the
+                # get_relative_uri call raises NoUri,
+                # the builder will then have to resolve these
+                contnode = addnodes.pending_xref('')
+                contnode['refdocname'] = docname
+                contnode['refsectname'] = sectname
+                newnode['refuri'] = builder.get_relative_uri(
+                    fromdocname, docname)
+                if labelid:
+                    newnode['refuri'] += '#' + labelid
+            newnode.append(innernode)
+            return newnode
+        elif typ == 'keyword':
+            # keywords are oddballs: they are referenced by named labels
+            docname, labelid, _ = self.data['labels'].get(target, ('','',''))
+            if not docname:
+                #env.warn(refdoc, 'unknown keyword: %s' % target)
+                return None
+            else:
+                return make_refnode(builder, fromdocname, docname,
+                                    labelid, contnode)
+        elif typ == 'option':
             progname = node['refprogram']
             docname, labelid = self.data['progoptions'].get((progname, target),
                                                             ('', ''))
         for (type, name), info in self.data['objects'].iteritems():
             yield (name, type, info[0], info[1],
                    self.object_types[type].attrs['searchprio'])
+        for name, info in self.data['labels'].iteritems():
+            yield (name, 'label', info[0], info[1], -1)

File sphinx/environment.py

         # domain-specific inventories, here to be pickled
         self.domaindata = {}        # domainname -> domain-specific dict
 
-        # X-ref target inventory
-        self.labels = {}            # labelname -> docname, labelid, sectionname
-        self.anonlabels = {}        # labelname -> docname, labelid
+        # Other inventories
         self.citations = {}         # citation name -> docname, labelid
-
-        # Other inventories
         self.indexentries = {}      # docname -> list of
                                     # (type, string, target, aliasname)
         self.versionchanges = {}    # version -> list of (type, docname,
         # temporary data storage while reading a document
         self.temp_data = {}
 
-        # Some magically present labels
-        def add_magic_label(name, description, target=None):
-            self.labels[name] = (target or name, '', description)
-            self.anonlabels[name] = (target or name, '')
-        add_magic_label('genindex', _('Index'))
-        # XXX add per domain?
-        # compatibility alias
-        add_magic_label('modindex', _('Module Index'), 'py-modindex')
-        add_magic_label('search', _('Search Page'))
-
     def set_warnfunc(self, func):
         self._warnfunc = func
         self.settings['warning_stream'] = WarningStream(func)
                 fnset.discard(docname)
                 if not fnset:
                     del self.files_to_rebuild[subfn]
-            for labelname, (fn, _, _) in self.labels.items():
-                if fn == docname:
-                    del self.labels[labelname]
             for key, (fn, _) in self.citations.items():
                 if fn == docname:
                     del self.citations[key]
         self.process_metadata(docname, doctree)
         self.process_refonly_bullet_lists(docname, doctree)
         self.create_title_from(docname, doctree)
-        self.note_labels_from(docname, doctree)
         self.note_indexentries_from(docname, doctree)
         self.note_citations_from(docname, doctree)
         self.build_toc_from(docname, doctree)
+        for domain in self.domains.itervalues():
+            domain.process_doc(self, docname, doctree)
 
         # allow extension-specific post-processing
         if app:
         self.titles[docname] = titlenode
         self.longtitles[docname] = longtitlenode
 
-    def note_labels_from(self, docname, document):
-        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 self.labels:
-                self.warn(docname, 'duplicate label %s, ' % name +
-                          'other instance in ' +
-                          self.doc2path(self.labels[name][0]),
-                          node.line)
-            self.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
-            else:
-                # anonymous-only labels
-                continue
-            self.labels[name] = docname, labelid, sectname
-
     def note_indexentries_from(self, docname, document):
         entries = self.indexentries[docname] = []
         for node in document.traverse(addnodes.index):
                     newnode = domain.resolve_xref(self, fromdocname, builder,
                                                   typ, target, node, contnode)
                 # really hardwired reference types
-                elif typ == 'ref':
-                    if node['refexplicit']:
-                        # reference to anonymous label; the reference uses
-                        # the supplied link caption
-                        docname, labelid = self.anonlabels.get(target, ('',''))
-                        sectname = node.astext()
-                        if not docname:
-                            self.warn(refdoc, 'undefined label: %s' %
-                                      target, node.line)
-                            warned = True
-                    else:
-                        # reference to named label; the final node will
-                        # contain the section name after the label
-                        docname, labelid, sectname = self.labels.get(target,
-                                                                     ('','',''))
-                        if not docname:
-                            self.warn(refdoc,
-                                'undefined label: %s' % target + ' -- if you '
-                                'don\'t give a link caption the label must '
-                                'precede a section header.', node.line)
-                            warned = True
-                    if docname:
-                        newnode = nodes.reference('', '')
-                        innernode = nodes.emphasis(sectname, sectname)
-                        if docname == fromdocname:
-                            newnode['refid'] = labelid
-                        else:
-                            # set more info in contnode; in case the
-                            # get_relative_uri call raises NoUri,
-                            # the builder will then have to resolve these
-                            contnode = addnodes.pending_xref('')
-                            contnode['refdocname'] = docname
-                            contnode['refsectname'] = sectname
-                            newnode['refuri'] = builder.get_relative_uri(
-                                fromdocname, docname)
-                            if labelid:
-                                newnode['refuri'] += '#' + labelid
-                        newnode.append(innernode)
                 elif typ == 'doc':
                     # directly reference to document by source name;
                     # can be absolute or relative
                     else:
                         newnode = make_refnode(builder, fromdocname, docname,
                                                labelid, contnode)
-                elif typ == 'keyword':
-                    # keywords are oddballs: they are referenced by named labels
-                    docname, labelid, _ = self.labels.get(target, ('','',''))
-                    if not docname:
-                        #self.warn(refdoc, 'unknown keyword: %s' % target)
-                        pass
-                    else:
-                        newnode = make_refnode(builder, fromdocname, docname,
-                                               labelid, contnode)
-
                 # no new node found? try the missing-reference event
                 if newnode is None:
                     newnode = builder.app.emit_firstresult(

File sphinx/roles.py

 specific_docroles = {
     # links to download references
     'download': XRefRole(nodeclass=addnodes.download_reference),
-    # links to headings or arbitrary labels
-    'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
     # links to documents
     'doc': XRefRole(),
-    # links to labels, without a different title
-    'keyword': XRefRole(),
 
     'pep': indexmarkup_role,
     'rfc': indexmarkup_role,