Add callback on domains for xrefs from fields.

Fixes sphinx-doc/sphinx#2607.
Fixes sphinx-doc/sphinx#2665.
This commit is contained in:
Jakob Lykke Andersen 2017-03-08 20:35:44 +09:00
parent 38b38d8aff
commit 9ca5d990f6
5 changed files with 33 additions and 19 deletions

View File

@ -25,6 +25,7 @@ Bugs fixed
are same without creation date. Thanks to Yoshiki Shibukawa.
* #3487: intersphinx: failed to refer options
* #3496: latex longtable's last column may be much wider than its contents
* #2665, #2607: Link names in C++ docfields, and make it possible for other domains.
Testing
--------

View File

@ -218,6 +218,12 @@ class Domain(object):
"""Process a document after it is read by the environment."""
pass
def process_field_xref(self, pnode):
"""Process a pending xref created in a doc field.
For example, attach information about the current scope.
"""
pass
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
"""Resolve the pending_xref *node* with the given *typ* and *target*.

View File

@ -4470,6 +4470,12 @@ class CPPDomain(Domain):
# print(self.data['root_symbol'].dump(0))
pass
def process_field_xref(self, pnode):
symbol = self.env.ref_context['cpp:parent_symbol']
key = symbol.get_lookup_key()
assert key
pnode['cpp:parent_key'] = key
def merge_domaindata(self, docnames, otherdata):
self.data['root_symbol'].merge_with(otherdata['root_symbol'],
docnames, self.env)

View File

@ -85,9 +85,9 @@ def _pseudo_parse_arglist(signode, arglist):
# This override allows our inline type specifiers to behave like :class: link
# when it comes to handling "." and "~" prefixes.
class PyXrefMixin(object):
def make_xref(self, rolename, domain, target, innernode=nodes.emphasis,
def make_xref(self, env, rolename, domain, target, innernode=nodes.emphasis,
contnode=None):
result = super(PyXrefMixin, self).make_xref(rolename, domain, target,
result = super(PyXrefMixin, self).make_xref(env, rolename, domain, target,
innernode, contnode)
result['refspecific'] = True
if target.startswith(('.', '~')):
@ -101,7 +101,7 @@ class PyXrefMixin(object):
break
return result
def make_xrefs(self, rolename, domain, target, innernode=nodes.emphasis,
def make_xrefs(self, env, rolename, domain, target, innernode=nodes.emphasis,
contnode=None):
delims = '(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
delims_re = re.compile(delims)
@ -117,7 +117,7 @@ class PyXrefMixin(object):
if delims_re.match(sub_target):
results.append(contnode or innernode(sub_target, sub_target))
else:
results.append(self.make_xref(rolename, domain, sub_target,
results.append(self.make_xref(env, rolename, domain, sub_target,
innernode, contnode))
return results

View File

@ -54,35 +54,36 @@ class Field(object):
self.rolename = rolename
self.bodyrolename = bodyrolename
def make_xref(self, rolename, domain, target,
def make_xref(self, env, rolename, domain, target,
innernode=addnodes.literal_emphasis, contnode=None):
if not rolename:
return contnode or innernode(target, target)
refnode = addnodes.pending_xref('', refdomain=domain, refexplicit=False,
reftype=rolename, reftarget=target)
refnode += contnode or innernode(target, target)
env.domains[domain].process_field_xref(refnode)
return refnode
def make_xrefs(self, rolename, domain, target,
def make_xrefs(self, env, rolename, domain, target,
innernode=addnodes.literal_emphasis, contnode=None):
return [self.make_xref(rolename, domain, target, innernode, contnode)]
return [self.make_xref(env, rolename, domain, target, innernode, contnode)]
def make_entry(self, fieldarg, content):
return (fieldarg, content)
def make_field(self, types, domain, item):
def make_field(self, env, types, domain, item):
fieldarg, content = item
fieldname = nodes.field_name('', self.label)
if fieldarg:
fieldname += nodes.Text(' ')
fieldname.extend(self.make_xrefs(self.rolename, domain,
fieldname.extend(self.make_xrefs(env, self.rolename, domain,
fieldarg, nodes.Text))
if len(content) == 1 and (
isinstance(content[0], nodes.Text) or
(isinstance(content[0], nodes.inline) and len(content[0]) == 1 and
isinstance(content[0][0], nodes.Text))):
content = self.make_xrefs(self.bodyrolename, domain,
content = self.make_xrefs(env, self.bodyrolename, domain,
content[0].astext(), contnode=content[0])
fieldbody = nodes.field_body('', nodes.paragraph('', '', *content))
return nodes.field('', fieldname, fieldbody)
@ -109,12 +110,12 @@ class GroupedField(Field):
Field.__init__(self, name, names, label, True, rolename)
self.can_collapse = can_collapse
def make_field(self, types, domain, items):
def make_field(self, env, types, domain, items):
fieldname = nodes.field_name('', self.label)
listnode = self.list_type()
for fieldarg, content in items:
par = nodes.paragraph()
par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
par.extend(self.make_xrefs(env, self.rolename, domain, fieldarg,
addnodes.literal_strong))
par += nodes.Text(' -- ')
par += content
@ -155,10 +156,10 @@ class TypedField(GroupedField):
self.typenames = typenames
self.typerolename = typerolename
def make_field(self, types, domain, items):
def make_field(self, env, types, domain, items):
def handle_item(fieldarg, content):
par = nodes.paragraph()
par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
par.extend(self.make_xrefs(env, self.rolename, domain, fieldarg,
addnodes.literal_strong))
if fieldarg in types:
par += nodes.Text(' (')
@ -168,8 +169,8 @@ class TypedField(GroupedField):
fieldtype = types.pop(fieldarg)
if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text):
typename = u''.join(n.astext() for n in fieldtype)
par.extend(self.make_xrefs(self.typerolename, domain, typename,
addnodes.literal_emphasis))
par.extend(self.make_xrefs(env, self.typerolename, domain,
typename, addnodes.literal_emphasis))
else:
par += fieldtype
par += nodes.Text(')')
@ -196,7 +197,7 @@ class DocFieldTransformer(object):
"""
def __init__(self, directive):
self.domain = directive.domain
self.directive = directive
if '_doc_field_type_map' not in directive.__class__.__dict__:
directive.__class__._doc_field_type_map = \
self.preprocess_fieldtypes(directive.__class__.doc_field_types)
@ -308,7 +309,7 @@ class DocFieldTransformer(object):
else:
fieldtype, content = entry
fieldtypes = types.get(fieldtype.name, {})
new_list += fieldtype.make_field(fieldtypes, self.domain,
content)
new_list += fieldtype.make_field(self.directive.env, fieldtypes,
self.directive.domain, content)
node.replace_self(new_list)