mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Move :ref: labels over to std domain.
This commit is contained in:
parent
981f134e15
commit
77b3c15049
@ -199,6 +199,12 @@ class Domain(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
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,
|
def resolve_xref(self, env, fromdocname, builder,
|
||||||
typ, target, node, contnode):
|
typ, target, node, contnode):
|
||||||
"""
|
"""
|
||||||
|
@ -20,7 +20,7 @@ from sphinx.locale import l_, _
|
|||||||
from sphinx.domains import Domain, ObjType
|
from sphinx.domains import Domain, ObjType
|
||||||
from sphinx.directives import ObjectDescription
|
from sphinx.directives import ObjectDescription
|
||||||
from sphinx.util import ws_re
|
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
|
from sphinx.util.compat import Directive
|
||||||
|
|
||||||
|
|
||||||
@ -327,6 +327,7 @@ class StandardDomain(Domain):
|
|||||||
object_types = {
|
object_types = {
|
||||||
'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
|
'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
|
||||||
'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
|
'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
|
||||||
|
'label': ObjType(l_('reference label'), 'ref', searchprio=-1),
|
||||||
'envvar': ObjType(l_('environment variable'), 'envvar'),
|
'envvar': ObjType(l_('environment variable'), 'envvar'),
|
||||||
'cmdoption': ObjType(l_('program option'), 'option'),
|
'cmdoption': ObjType(l_('program option'), 'option'),
|
||||||
}
|
}
|
||||||
@ -340,15 +341,31 @@ class StandardDomain(Domain):
|
|||||||
'productionlist': ProductionList,
|
'productionlist': ProductionList,
|
||||||
}
|
}
|
||||||
roles = {
|
roles = {
|
||||||
'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
|
'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
|
||||||
'envvar': EnvVarXRefRole(),
|
'envvar': EnvVarXRefRole(),
|
||||||
'token': XRefRole(),
|
# links to tokens in grammar productions
|
||||||
'term': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
'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 = {
|
initial_data = {
|
||||||
'progoptions': {}, # (program, name) -> docname, labelid
|
'progoptions': {}, # (program, name) -> docname, labelid
|
||||||
'objects': {}, # (type, 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):
|
def clear_doc(self, docname):
|
||||||
@ -358,10 +375,97 @@ class StandardDomain(Domain):
|
|||||||
for key, (fn, _) in self.data['objects'].items():
|
for key, (fn, _) in self.data['objects'].items():
|
||||||
if fn == docname:
|
if fn == docname:
|
||||||
del self.data['objects'][key]
|
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,
|
def resolve_xref(self, env, fromdocname, builder,
|
||||||
typ, target, node, contnode):
|
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']
|
progname = node['refprogram']
|
||||||
docname, labelid = self.data['progoptions'].get((progname, target),
|
docname, labelid = self.data['progoptions'].get((progname, target),
|
||||||
('', ''))
|
('', ''))
|
||||||
@ -387,3 +491,5 @@ class StandardDomain(Domain):
|
|||||||
for (type, name), info in self.data['objects'].iteritems():
|
for (type, name), info in self.data['objects'].iteritems():
|
||||||
yield (name, type, info[0], info[1],
|
yield (name, type, info[0], info[1],
|
||||||
self.object_types[type].attrs['searchprio'])
|
self.object_types[type].attrs['searchprio'])
|
||||||
|
for name, info in self.data['labels'].iteritems():
|
||||||
|
yield (name, 'label', info[0], info[1], -1)
|
||||||
|
@ -304,12 +304,8 @@ class BuildEnvironment:
|
|||||||
# domain-specific inventories, here to be pickled
|
# domain-specific inventories, here to be pickled
|
||||||
self.domaindata = {} # domainname -> domain-specific dict
|
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
|
# Other inventories
|
||||||
|
self.citations = {} # citation name -> docname, labelid
|
||||||
self.indexentries = {} # docname -> list of
|
self.indexentries = {} # docname -> list of
|
||||||
# (type, string, target, aliasname)
|
# (type, string, target, aliasname)
|
||||||
self.versionchanges = {} # version -> list of (type, docname,
|
self.versionchanges = {} # version -> list of (type, docname,
|
||||||
@ -322,16 +318,6 @@ class BuildEnvironment:
|
|||||||
# temporary data storage while reading a document
|
# temporary data storage while reading a document
|
||||||
self.temp_data = {}
|
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):
|
def set_warnfunc(self, func):
|
||||||
self._warnfunc = func
|
self._warnfunc = func
|
||||||
self.settings['warning_stream'] = WarningStream(func)
|
self.settings['warning_stream'] = WarningStream(func)
|
||||||
@ -366,9 +352,6 @@ class BuildEnvironment:
|
|||||||
fnset.discard(docname)
|
fnset.discard(docname)
|
||||||
if not fnset:
|
if not fnset:
|
||||||
del self.files_to_rebuild[subfn]
|
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():
|
for key, (fn, _) in self.citations.items():
|
||||||
if fn == docname:
|
if fn == docname:
|
||||||
del self.citations[key]
|
del self.citations[key]
|
||||||
@ -669,10 +652,11 @@ class BuildEnvironment:
|
|||||||
self.process_metadata(docname, doctree)
|
self.process_metadata(docname, doctree)
|
||||||
self.process_refonly_bullet_lists(docname, doctree)
|
self.process_refonly_bullet_lists(docname, doctree)
|
||||||
self.create_title_from(docname, doctree)
|
self.create_title_from(docname, doctree)
|
||||||
self.note_labels_from(docname, doctree)
|
|
||||||
self.note_indexentries_from(docname, doctree)
|
self.note_indexentries_from(docname, doctree)
|
||||||
self.note_citations_from(docname, doctree)
|
self.note_citations_from(docname, doctree)
|
||||||
self.build_toc_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
|
# allow extension-specific post-processing
|
||||||
if app:
|
if app:
|
||||||
@ -949,39 +933,6 @@ class BuildEnvironment:
|
|||||||
self.titles[docname] = titlenode
|
self.titles[docname] = titlenode
|
||||||
self.longtitles[docname] = longtitlenode
|
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):
|
def note_indexentries_from(self, docname, document):
|
||||||
entries = self.indexentries[docname] = []
|
entries = self.indexentries[docname] = []
|
||||||
for node in document.traverse(addnodes.index):
|
for node in document.traverse(addnodes.index):
|
||||||
@ -1309,44 +1260,6 @@ class BuildEnvironment:
|
|||||||
newnode = domain.resolve_xref(self, fromdocname, builder,
|
newnode = domain.resolve_xref(self, fromdocname, builder,
|
||||||
typ, target, node, contnode)
|
typ, target, node, contnode)
|
||||||
# really hardwired reference types
|
# 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':
|
elif typ == 'doc':
|
||||||
# directly reference to document by source name;
|
# directly reference to document by source name;
|
||||||
# can be absolute or relative
|
# can be absolute or relative
|
||||||
@ -1375,16 +1288,6 @@ class BuildEnvironment:
|
|||||||
else:
|
else:
|
||||||
newnode = make_refnode(builder, fromdocname, docname,
|
newnode = make_refnode(builder, fromdocname, docname,
|
||||||
labelid, contnode)
|
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
|
# no new node found? try the missing-reference event
|
||||||
if newnode is None:
|
if newnode is None:
|
||||||
newnode = builder.app.emit_firstresult(
|
newnode = builder.app.emit_firstresult(
|
||||||
|
@ -244,12 +244,8 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
|||||||
specific_docroles = {
|
specific_docroles = {
|
||||||
# links to download references
|
# links to download references
|
||||||
'download': XRefRole(nodeclass=addnodes.download_reference),
|
'download': XRefRole(nodeclass=addnodes.download_reference),
|
||||||
# links to headings or arbitrary labels
|
|
||||||
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
|
||||||
# links to documents
|
# links to documents
|
||||||
'doc': XRefRole(),
|
'doc': XRefRole(),
|
||||||
# links to labels, without a different title
|
|
||||||
'keyword': XRefRole(),
|
|
||||||
|
|
||||||
'pep': indexmarkup_role,
|
'pep': indexmarkup_role,
|
||||||
'rfc': indexmarkup_role,
|
'rfc': indexmarkup_role,
|
||||||
|
Loading…
Reference in New Issue
Block a user