From 11cab438b82b807757687dbcfe47be4fdff96a5d Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 15 Aug 2007 18:05:01 +0000 Subject: [PATCH] Allow a leading dot in x-reference roles, marking reversed search order for targets. --- sphinx/directives.py | 16 ++++++++++----- sphinx/environment.py | 48 ++++++++++++++++++++++++++++--------------- sphinx/roles.py | 6 ++++++ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/sphinx/directives.py b/sphinx/directives.py index 0fc04a879..41ed3baef 100644 --- a/sphinx/directives.py +++ b/sphinx/directives.py @@ -116,7 +116,7 @@ py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ',' def parse_py_signature(signode, sig, desctype, env): """ Transform a python signature into RST nodes. - Return the fully qualified name of the thing. + Return (fully qualified name of the thing, classname if any). If inside a class, the current class name is handled intelligently: * it is stripped from the displayed name if present @@ -153,7 +153,7 @@ def parse_py_signature(signode, sig, desctype, env): if desctype in ('function', 'method'): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() - return fullname + return fullname, classname signode += addnodes.desc_parameterlist() stack = [signode[-1]] @@ -171,7 +171,7 @@ def parse_py_signature(signode, sig, desctype, env): token = token.strip() stack[-1] += addnodes.desc_parameter(token, token) if len(stack) != 1: raise ValueError - return fullname + return fullname, classname c_sig_re = re.compile( @@ -280,6 +280,7 @@ def desc_directive(desctype, arguments, options, content, lineno, noindex = ('noindex' in options) signatures = map(lambda s: s.strip(), arguments[0].split('\n')) names = [] + clsname = None for i, sig in enumerate(signatures): # add a signature node for each signature in the current unit # and add a reference target for it @@ -290,7 +291,7 @@ def desc_directive(desctype, arguments, options, content, lineno, try: if desctype in ('function', 'data', 'class', 'exception', 'method', 'attribute'): - name = parse_py_signature(signode, sig, desctype, env) + name, clsname = parse_py_signature(signode, sig, desctype, env) elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype', 'cvar'): name = parse_c_signature(signode, sig, desctype) elif desctype == 'opcode': @@ -323,13 +324,18 @@ def desc_directive(desctype, arguments, options, content, lineno, if desctype == 'cfunction': add_refcount_annotation(env, subnode, name) # needed for automatic qualification of members + clsname_set = False if desctype == 'class' and names: env.currclass = names[0] + clsname_set = True + elif desctype in ('method', 'attribute') and clsname and not env.currclass: + env.currclass = clsname.strip('.') + clsname_set = True # needed for association of version{added,changed} directives if names: env.currdesc = names[0] state.nested_parse(content, content_offset, subnode) - if desctype == 'class': + if clsname_set: env.currclass = None env.currdesc = None node.append(subnode) diff --git a/sphinx/environment.py b/sphinx/environment.py index 8530ceb2b..07be441f8 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -621,7 +621,8 @@ class BuildEnvironment: builder.get_relative_uri(docfilename, filename) + anchor) newnode.append(contnode) else: - name, desc = self.find_desc(modname, clsname, target, typ) + searchorder = 1 if node.hasattr('refspecific') else 0 + name, desc = self.find_desc(modname, clsname, target, typ, searchorder) if not desc: newnode = contnode else: @@ -742,13 +743,16 @@ class BuildEnvironment: # --------- QUERYING ------------------------------------------------------- - def find_desc(self, modname, classname, name, type): + def find_desc(self, modname, classname, name, type, searchorder=0): """Find a description node matching "name", perhaps using the given module and/or classname.""" # skip parens if name[-2:] == '()': name = name[:-2] + if not name: + return None, None + # don't add module and class names for C things if type[0] == 'c' and type not in ('class', 'const'): # skip trailing star and whitespace @@ -757,22 +761,32 @@ class BuildEnvironment: return name, self.descrefs[name] return None, None - if name in self.descrefs: - newname = name - elif modname and modname + '.' + name in self.descrefs: - newname = modname + '.' + name - elif modname and classname and \ - modname + '.' + classname + '.' + name in self.descrefs: - newname = modname + '.' + classname + '.' + name - # special case: builtin exceptions have module "exceptions" set - elif type == 'exc' and '.' not in name and \ - 'exceptions.' + name in self.descrefs: - newname = 'exceptions.' + name - # special case: object methods - elif type in ('func', 'meth') and '.' not in name and \ - 'object.' + name in self.descrefs: - newname = 'object.' + name + newname = None + if searchorder == 1: + if modname and classname and \ + modname + '.' + classname + '.' + name in self.descrefs: + newname = modname + '.' + classname + '.' + name + elif modname and modname + '.' + name in self.descrefs: + newname = modname + '.' + name + elif name in self.descrefs: + newname = name else: + if name in self.descrefs: + newname = name + elif modname and modname + '.' + name in self.descrefs: + newname = modname + '.' + name + elif modname and classname and \ + modname + '.' + classname + '.' + name in self.descrefs: + newname = modname + '.' + classname + '.' + name + # special case: builtin exceptions have module "exceptions" set + elif type == 'exc' and '.' not in name and \ + 'exceptions.' + name in self.descrefs: + newname = 'exceptions.' + name + # special case: object methods + elif type in ('func', 'meth') and '.' not in name and \ + 'object.' + name in self.descrefs: + newname = 'object.' + name + if newname is None: return None, None return newname, self.descrefs[newname] diff --git a/sphinx/roles.py b/sphinx/roles.py index 622764311..2f5dc6bb8 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -100,6 +100,12 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text += '()' pnode = addnodes.pending_xref(rawtext) pnode['reftype'] = typ + # if the first character is a dot, search more specific namespaces first + # else search builtins first + if text[0:1] == '.' and \ + typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'): + text = text[1:] + pnode['refspecific'] = True pnode['reftarget'] = ws_re.sub('', text) pnode['modname'] = env.currmodule pnode['classname'] = env.currclass