Move :ref: labels over to std domain.

This commit is contained in:
Georg Brandl 2010-05-23 11:59:20 +02:00
parent 981f134e15
commit 77b3c15049
4 changed files with 121 additions and 110 deletions

View File

@ -199,6 +199,12 @@ class Domain(object):
"""
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):
"""

View File

@ -20,7 +20,7 @@ from sphinx.locale import l_, _
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
@ -327,6 +327,7 @@ class StandardDomain(Domain):
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'),
}
@ -340,15 +341,31 @@ class StandardDomain(Domain):
'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):
@ -358,10 +375,97 @@ class StandardDomain(Domain):
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),
('', ''))
@ -387,3 +491,5 @@ class StandardDomain(Domain):
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)

View File

@ -304,12 +304,8 @@ class BuildEnvironment:
# 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
self.citations = {} # citation name -> docname, labelid
# Other inventories
self.citations = {} # citation name -> docname, labelid
self.indexentries = {} # docname -> list of
# (type, string, target, aliasname)
self.versionchanges = {} # version -> list of (type, docname,
@ -322,16 +318,6 @@ class BuildEnvironment:
# 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)
@ -366,9 +352,6 @@ class BuildEnvironment:
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]
@ -669,10 +652,11 @@ class BuildEnvironment:
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:
@ -949,39 +933,6 @@ class BuildEnvironment:
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):
@ -1309,44 +1260,6 @@ class BuildEnvironment:
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
@ -1375,16 +1288,6 @@ class BuildEnvironment:
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(

View File

@ -244,12 +244,8 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
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,