mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-10-13 17:02:12 -05:00
Move domain-specific code around a bit; builtin domains are now completely in sphinx.domains. Test suite does not pass yet.
This commit is contained in:
1 parent
9199b21f85
commit
c02b7149aa
7 files changed
+573
-614
No files matched your search
+2
-2
@@ -119,8 +119,8 @@ The directives are:
|
||||
Describes a "simple" C macro. Simple macros are macros which are used
|
||||
for code expansion, but which do not take arguments so cannot be described as
|
||||
functions. This is not to be used for simple constant definitions. Examples
|
||||
of its use in the Python documentation include :cmacro:`PyObject_HEAD` and
|
||||
:cmacro:`Py_BEGIN_ALLOW_THREADS`.
|
||||
of its use in the Python documentation include :c:macro:`PyObject_HEAD` and
|
||||
:c:macro:`Py_BEGIN_ALLOW_THREADS`.
|
||||
|
||||
.. directive:: .. ctype:: name
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from docutils import nodes
|
||||
from docutils.parsers.rst import directives, roles
|
||||
|
||||
import sphinx
|
||||
from sphinx.roles import make_xref_role, simple_link_func
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import SphinxError, SphinxWarning, ExtensionError
|
||||
from sphinx.domains import domains
|
||||
@@ -310,14 +310,16 @@ class Sphinx(object):
|
||||
parse_node)
|
||||
directives.register_directive(directivename,
|
||||
directive_dwim(GenericDesc))
|
||||
role_func = make_xref_role(simple_link_func, innernodeclass=ref_nodeclass)
|
||||
# XXX support more options?
|
||||
role_func = XRefRole('', innernodeclass=ref_nodeclass)
|
||||
roles.register_local_role(rolename, role_func)
|
||||
|
||||
def add_crossref_type(self, directivename, rolename, indextemplate='',
|
||||
ref_nodeclass=None):
|
||||
additional_xref_types[directivename] = (rolename, indextemplate, None)
|
||||
directives.register_directive(directivename, directive_dwim(Target))
|
||||
role_func = make_xref_role(simple_link_func, innernodeclass=ref_nodeclass)
|
||||
# XXX support more options
|
||||
role_func = XRefRole('', innernodeclass=ref_nodeclass)
|
||||
roles.register_local_role(rolename, role_func)
|
||||
|
||||
def add_transform(self, transform):
|
||||
|
||||
@@ -14,7 +14,6 @@ from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.domains import Domain, domains
|
||||
from sphinx.locale import l_
|
||||
from sphinx.util import ws_re
|
||||
from sphinx.util.compat import Directive, directive_dwim
|
||||
@@ -33,39 +32,10 @@ def _is_only_paragraph(node):
|
||||
return False
|
||||
|
||||
|
||||
# REs for Python signatures
|
||||
py_sig_re = re.compile(
|
||||
r'''^ ([\w.]*\.)? # class name(s)
|
||||
(\w+) \s* # thing name
|
||||
(?: \((.*)\) # optional: arguments
|
||||
(?:\s* -> \s* (.*))? # return annotation
|
||||
)? $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
|
||||
|
||||
# REs for C signatures
|
||||
c_sig_re = re.compile(
|
||||
r'''^([^(]*?) # return type
|
||||
([\w:]+) \s* # thing name (colon allowed for C++ class names)
|
||||
(?: \((.*)\) )? # optionally arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_sig_re = re.compile(
|
||||
r'''^([^(]+?) # return type
|
||||
(\( [^()]+ \)) \s* # name in parentheses
|
||||
\( (.*) \) # arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
|
||||
|
||||
# RE for option descriptions
|
||||
option_desc_re = re.compile(
|
||||
r'((?:/|-|--)[-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
|
||||
|
||||
# RE to split at word boundaries
|
||||
wsplit_re = re.compile(r'(\W+)')
|
||||
|
||||
# RE to strip backslash escapes
|
||||
strip_backslash_re = re.compile(r'\\(?=[^\\])')
|
||||
|
||||
@@ -278,360 +248,6 @@ class DescDirective(Directive):
|
||||
return [self.indexnode, node]
|
||||
|
||||
|
||||
class PythonDesc(DescDirective):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
"""
|
||||
May return a prefix to put before the object name in the signature.
|
||||
"""
|
||||
return ''
|
||||
|
||||
def needs_arglist(self):
|
||||
"""
|
||||
May return true if an empty argument list is to be generated even if
|
||||
the document contains none.
|
||||
"""
|
||||
return False
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Transform a Python signature into RST nodes.
|
||||
Returns (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
|
||||
* it is added to the full name (return value) if not present
|
||||
"""
|
||||
m = py_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError
|
||||
classname, name, arglist, retann = m.groups()
|
||||
|
||||
if self.env.currclass:
|
||||
add_module = False
|
||||
if classname and classname.startswith(self.env.currclass):
|
||||
fullname = classname + name
|
||||
# class name is given again in the signature
|
||||
classname = classname[len(self.env.currclass):].lstrip('.')
|
||||
elif classname:
|
||||
# class name is given in the signature, but different
|
||||
# (shouldn't happen)
|
||||
fullname = self.env.currclass + '.' + classname + name
|
||||
else:
|
||||
# class name is not given in the signature
|
||||
fullname = self.env.currclass + '.' + name
|
||||
else:
|
||||
add_module = True
|
||||
fullname = classname and classname + name or name
|
||||
|
||||
prefix = self.get_signature_prefix(sig)
|
||||
if prefix:
|
||||
signode += addnodes.desc_annotation(prefix, prefix)
|
||||
|
||||
if classname:
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
# exceptions are a special case, since they are documented in the
|
||||
# 'exceptions' module.
|
||||
elif add_module and self.env.config.add_module_names:
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
if modname and modname != 'exceptions':
|
||||
nodetext = modname + '.'
|
||||
signode += addnodes.desc_addname(nodetext, nodetext)
|
||||
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if not arglist:
|
||||
if self.needs_arglist():
|
||||
# for callables, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
signode += addnodes.desc_parameterlist()
|
||||
|
||||
stack = [signode[-1]]
|
||||
for token in py_paramlist_re.split(arglist):
|
||||
if token == '[':
|
||||
opt = addnodes.desc_optional()
|
||||
stack[-1] += opt
|
||||
stack.append(opt)
|
||||
elif token == ']':
|
||||
try:
|
||||
stack.pop()
|
||||
except IndexError:
|
||||
raise ValueError
|
||||
elif not token or token == ',' or token.isspace():
|
||||
pass
|
||||
else:
|
||||
token = token.strip()
|
||||
stack[-1] += addnodes.desc_parameter(token, token)
|
||||
if len(stack) != 1:
|
||||
raise ValueError
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
|
||||
def get_index_text(self, modname, name):
|
||||
"""
|
||||
Return the text for the index entry of the object.
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def add_target_and_index(self, name_cls, sig, signode):
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
fullname = (modname and modname + '.' or '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(fullname, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname, fullname))
|
||||
|
||||
def before_content(self):
|
||||
# needed for automatic qualification of members (reset in subclasses)
|
||||
self.clsname_set = False
|
||||
|
||||
def after_content(self):
|
||||
if self.clsname_set:
|
||||
self.env.currclass = None
|
||||
|
||||
|
||||
class ModulelevelDesc(PythonDesc):
|
||||
"""
|
||||
Description of an object on module level (functions, data).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype == 'function'
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'function':
|
||||
if not modname:
|
||||
return _('%s() (built-in function)') % name_cls[0]
|
||||
return _('%s() (in module %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'data':
|
||||
if not modname:
|
||||
return _('%s (built-in variable)') % name_cls[0]
|
||||
return _('%s (in module %s)') % (name_cls[0], modname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class ClasslikeDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
return self.desctype + ' '
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'class':
|
||||
if not modname:
|
||||
return _('%s (built-in class)') % name_cls[0]
|
||||
return _('%s (class in %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'exception':
|
||||
return name_cls[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names:
|
||||
self.env.currclass = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class ClassmemberDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class member (methods, attributes).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype.endswith('method')
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
if self.desctype == 'staticmethod':
|
||||
return 'static '
|
||||
elif self.desctype == 'classmethod':
|
||||
return 'classmethod '
|
||||
return ''
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
name, cls = name_cls
|
||||
add_modules = self.env.config.add_module_names
|
||||
if self.desctype == 'method':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s method)') % (methname, modname, clsname)
|
||||
else:
|
||||
return _('%s() (%s method)') % (methname, clsname)
|
||||
elif self.desctype == 'staticmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s static method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s static method)') % (methname, clsname)
|
||||
elif self.desctype == 'classmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname:
|
||||
return _('%s() (%s.%s class method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s class method)') % (methname, clsname)
|
||||
elif self.desctype == 'attribute':
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
if modname and add_modules:
|
||||
return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
|
||||
else:
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names and self.names[-1][1] and not self.env.currclass:
|
||||
self.env.currclass = self.names[-1][1].strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class CDesc(DescDirective):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
|
||||
# These C types aren't described anywhere, so don't try to create
|
||||
# a cross-reference to them
|
||||
stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
|
||||
|
||||
def _parse_type(self, node, ctype):
|
||||
# add cross-ref nodes for all words
|
||||
for part in filter(None, wsplit_re.split(ctype)):
|
||||
tnode = nodes.Text(part, part)
|
||||
if part[0] in string.ascii_letters+'_' and \
|
||||
part not in self.stopwords:
|
||||
pnode = addnodes.pending_xref(
|
||||
'', reftype='ctype', reftarget=part,
|
||||
modname=None, classname=None)
|
||||
pnode += tnode
|
||||
node += pnode
|
||||
else:
|
||||
node += tnode
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform a C (or C++) signature into RST nodes."""
|
||||
# first try the function pointer signature regex, it's more specific
|
||||
m = c_funcptr_sig_re.match(sig)
|
||||
if m is None:
|
||||
m = c_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError('no match')
|
||||
rettype, name, arglist, const = m.groups()
|
||||
|
||||
signode += addnodes.desc_type('', '')
|
||||
self._parse_type(signode[-1], rettype)
|
||||
try:
|
||||
classname, funcname = name.split('::', 1)
|
||||
classname += '::'
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
signode += addnodes.desc_name(funcname, funcname)
|
||||
# name (the full name) is still both parts
|
||||
except ValueError:
|
||||
signode += addnodes.desc_name(name, name)
|
||||
# clean up parentheses from canonical name
|
||||
m = c_funcptr_name_re.match(name)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
if not arglist:
|
||||
if self.desctype == 'cfunction':
|
||||
# for functions, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
|
||||
# this messes up function pointer types, but not too badly ;)
|
||||
args = arglist.split(',')
|
||||
for arg in args:
|
||||
arg = arg.strip()
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
try:
|
||||
ctype, argname = arg.rsplit(' ', 1)
|
||||
except ValueError:
|
||||
# no argument name given, only the type
|
||||
self._parse_type(param, arg)
|
||||
else:
|
||||
self._parse_type(param, ctype)
|
||||
param += nodes.emphasis(' '+argname, ' '+argname)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
def get_index_text(self, name):
|
||||
if self.desctype == 'cfunction':
|
||||
return _('%s (C function)') % name
|
||||
elif self.desctype == 'cmember':
|
||||
return _('%s (C member)') % name
|
||||
elif self.desctype == 'cmacro':
|
||||
return _('%s (C macro)') % name
|
||||
elif self.desctype == 'ctype':
|
||||
return _('%s (C type)') % name
|
||||
elif self.desctype == 'cvar':
|
||||
return _('%s (C variable)') % name
|
||||
else:
|
||||
return ''
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
# note target
|
||||
if name not in self.state.document.ids:
|
||||
signode['names'].append(name)
|
||||
signode['ids'].append(name)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(name, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(name)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext, name, name))
|
||||
|
||||
|
||||
class CmdoptionDesc(DescDirective):
|
||||
"""
|
||||
Description of a command-line option (.. cmdoption).
|
||||
@@ -768,33 +384,3 @@ directives.register_directive('default-domain', directive_dwim(DefaultDomain))
|
||||
directives.register_directive('describe', directive_dwim(DescDirective))
|
||||
directives.register_directive('cmdoption', directive_dwim(CmdoptionDesc))
|
||||
directives.register_directive('envvar', directive_dwim(GenericDesc))
|
||||
|
||||
|
||||
class PythonDomain(Domain):
|
||||
name = 'py'
|
||||
label = 'Python'
|
||||
directives = {
|
||||
'function': ModulelevelDesc,
|
||||
'data': ModulelevelDesc,
|
||||
'class': ClasslikeDesc,
|
||||
'exception': ClasslikeDesc,
|
||||
'method': ClassmemberDesc,
|
||||
'classmethod': ClassmemberDesc,
|
||||
'staticmethod': ClassmemberDesc,
|
||||
'attribute': ClassmemberDesc,
|
||||
}
|
||||
|
||||
class CDomain(Domain):
|
||||
name = 'c'
|
||||
label = 'C'
|
||||
directives = {
|
||||
'function': CDesc,
|
||||
'member': CDesc,
|
||||
'macro': CDesc,
|
||||
'type': CDesc,
|
||||
'var': CDesc,
|
||||
}
|
||||
|
||||
|
||||
domains['py'] = PythonDomain
|
||||
domains['c'] = CDomain
|
||||
+466
-1
@@ -10,11 +10,476 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.directives import DescDirective
|
||||
|
||||
|
||||
class Domain(object):
|
||||
name = ''
|
||||
directives = {}
|
||||
roles = {}
|
||||
label = ''
|
||||
|
||||
|
||||
# REs for Python signatures
|
||||
py_sig_re = re.compile(
|
||||
r'''^ ([\w.]*\.)? # class name(s)
|
||||
(\w+) \s* # thing name
|
||||
(?: \((.*)\) # optional: arguments
|
||||
(?:\s* -> \s* (.*))? # return annotation
|
||||
)? $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
|
||||
|
||||
|
||||
class PythonDesc(DescDirective):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
"""
|
||||
May return a prefix to put before the object name in the signature.
|
||||
"""
|
||||
return ''
|
||||
|
||||
def needs_arglist(self):
|
||||
"""
|
||||
May return true if an empty argument list is to be generated even if
|
||||
the document contains none.
|
||||
"""
|
||||
return False
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Transform a Python signature into RST nodes.
|
||||
Returns (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
|
||||
* it is added to the full name (return value) if not present
|
||||
"""
|
||||
m = py_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError
|
||||
classname, name, arglist, retann = m.groups()
|
||||
|
||||
if self.env.currclass:
|
||||
add_module = False
|
||||
if classname and classname.startswith(self.env.currclass):
|
||||
fullname = classname + name
|
||||
# class name is given again in the signature
|
||||
classname = classname[len(self.env.currclass):].lstrip('.')
|
||||
elif classname:
|
||||
# class name is given in the signature, but different
|
||||
# (shouldn't happen)
|
||||
fullname = self.env.currclass + '.' + classname + name
|
||||
else:
|
||||
# class name is not given in the signature
|
||||
fullname = self.env.currclass + '.' + name
|
||||
else:
|
||||
add_module = True
|
||||
fullname = classname and classname + name or name
|
||||
|
||||
prefix = self.get_signature_prefix(sig)
|
||||
if prefix:
|
||||
signode += addnodes.desc_annotation(prefix, prefix)
|
||||
|
||||
if classname:
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
# exceptions are a special case, since they are documented in the
|
||||
# 'exceptions' module.
|
||||
elif add_module and self.env.config.add_module_names:
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
if modname and modname != 'exceptions':
|
||||
nodetext = modname + '.'
|
||||
signode += addnodes.desc_addname(nodetext, nodetext)
|
||||
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if not arglist:
|
||||
if self.needs_arglist():
|
||||
# for callables, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
signode += addnodes.desc_parameterlist()
|
||||
|
||||
stack = [signode[-1]]
|
||||
for token in py_paramlist_re.split(arglist):
|
||||
if token == '[':
|
||||
opt = addnodes.desc_optional()
|
||||
stack[-1] += opt
|
||||
stack.append(opt)
|
||||
elif token == ']':
|
||||
try:
|
||||
stack.pop()
|
||||
except IndexError:
|
||||
raise ValueError
|
||||
elif not token or token == ',' or token.isspace():
|
||||
pass
|
||||
else:
|
||||
token = token.strip()
|
||||
stack[-1] += addnodes.desc_parameter(token, token)
|
||||
if len(stack) != 1:
|
||||
raise ValueError
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
|
||||
def get_index_text(self, modname, name):
|
||||
"""
|
||||
Return the text for the index entry of the object.
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def add_target_and_index(self, name_cls, sig, signode):
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
fullname = (modname and modname + '.' or '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(fullname, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname, fullname))
|
||||
|
||||
def before_content(self):
|
||||
# needed for automatic qualification of members (reset in subclasses)
|
||||
self.clsname_set = False
|
||||
|
||||
def after_content(self):
|
||||
if self.clsname_set:
|
||||
self.env.currclass = None
|
||||
|
||||
|
||||
class ModulelevelDesc(PythonDesc):
|
||||
"""
|
||||
Description of an object on module level (functions, data).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype == 'function'
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'function':
|
||||
if not modname:
|
||||
return _('%s() (built-in function)') % name_cls[0]
|
||||
return _('%s() (in module %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'data':
|
||||
if not modname:
|
||||
return _('%s (built-in variable)') % name_cls[0]
|
||||
return _('%s (in module %s)') % (name_cls[0], modname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class ClasslikeDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
return self.desctype + ' '
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'class':
|
||||
if not modname:
|
||||
return _('%s (built-in class)') % name_cls[0]
|
||||
return _('%s (class in %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'exception':
|
||||
return name_cls[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names:
|
||||
self.env.currclass = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class ClassmemberDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class member (methods, attributes).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype.endswith('method')
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
if self.desctype == 'staticmethod':
|
||||
return 'static '
|
||||
elif self.desctype == 'classmethod':
|
||||
return 'classmethod '
|
||||
return ''
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
name, cls = name_cls
|
||||
add_modules = self.env.config.add_module_names
|
||||
if self.desctype == 'method':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s method)') % (methname, modname, clsname)
|
||||
else:
|
||||
return _('%s() (%s method)') % (methname, clsname)
|
||||
elif self.desctype == 'staticmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s static method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s static method)') % (methname, clsname)
|
||||
elif self.desctype == 'classmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname:
|
||||
return _('%s() (%s.%s class method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s class method)') % (methname, clsname)
|
||||
elif self.desctype == 'attribute':
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
if modname and add_modules:
|
||||
return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
|
||||
else:
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names and self.names[-1][1] and not self.env.currclass:
|
||||
self.env.currclass = self.names[-1][1].strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyXRefRole(XRefRole):
|
||||
def process_link(self, env, pnode, has_explicit_title, title, target):
|
||||
pnode['modname'] = env.currmodule
|
||||
pnode['classname'] = env.currclass
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.') # only has a meaning for the target
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
# if the first character is a tilde, don't display the module/class
|
||||
# parts of the contents
|
||||
if title[0:1] == '~':
|
||||
title = title[1:]
|
||||
dot = title.rfind('.')
|
||||
if dot != -1:
|
||||
title = title[dot+1:]
|
||||
# if the first character is a dot, search more specific namespaces first
|
||||
# else search builtins first
|
||||
if target[0:1] == '.':
|
||||
target = target[1:]
|
||||
pnode['refspecific'] = True
|
||||
return title, target
|
||||
|
||||
|
||||
class PythonDomain(Domain):
|
||||
"""Python language domain."""
|
||||
name = 'py'
|
||||
label = 'Python'
|
||||
directives = {
|
||||
'function': ModulelevelDesc,
|
||||
'data': ModulelevelDesc,
|
||||
'class': ClasslikeDesc,
|
||||
'exception': ClasslikeDesc,
|
||||
'method': ClassmemberDesc,
|
||||
'classmethod': ClassmemberDesc,
|
||||
'staticmethod': ClassmemberDesc,
|
||||
'attribute': ClassmemberDesc,
|
||||
}
|
||||
roles = {
|
||||
'data': PyXRefRole('py'),
|
||||
'exc': PyXRefRole('py'),
|
||||
'func': PyXRefRole('py', True),
|
||||
'class': PyXRefRole('py'),
|
||||
'const': PyXRefRole('py'),
|
||||
'attr': PyXRefRole('py'),
|
||||
'meth': PyXRefRole('py', True),
|
||||
'mod': PyXRefRole('py'),
|
||||
'obj': PyXRefRole('py'),
|
||||
}
|
||||
|
||||
|
||||
# RE to split at word boundaries
|
||||
wsplit_re = re.compile(r'(\W+)')
|
||||
|
||||
# REs for C signatures
|
||||
c_sig_re = re.compile(
|
||||
r'''^([^(]*?) # return type
|
||||
([\w:]+) \s* # thing name (colon allowed for C++ class names)
|
||||
(?: \((.*)\) )? # optionally arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_sig_re = re.compile(
|
||||
r'''^([^(]+?) # return type
|
||||
(\( [^()]+ \)) \s* # name in parentheses
|
||||
\( (.*) \) # arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
|
||||
|
||||
|
||||
class CDesc(DescDirective):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
|
||||
# These C types aren't described anywhere, so don't try to create
|
||||
# a cross-reference to them
|
||||
stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
|
||||
|
||||
def _parse_type(self, node, ctype):
|
||||
# add cross-ref nodes for all words
|
||||
for part in filter(None, wsplit_re.split(ctype)):
|
||||
tnode = nodes.Text(part, part)
|
||||
if part[0] in string.ascii_letters+'_' and \
|
||||
part not in self.stopwords:
|
||||
pnode = addnodes.pending_xref(
|
||||
'', reftype='ctype', reftarget=part,
|
||||
modname=None, classname=None)
|
||||
pnode += tnode
|
||||
node += pnode
|
||||
else:
|
||||
node += tnode
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform a C (or C++) signature into RST nodes."""
|
||||
# first try the function pointer signature regex, it's more specific
|
||||
m = c_funcptr_sig_re.match(sig)
|
||||
if m is None:
|
||||
m = c_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError('no match')
|
||||
rettype, name, arglist, const = m.groups()
|
||||
|
||||
signode += addnodes.desc_type('', '')
|
||||
self._parse_type(signode[-1], rettype)
|
||||
try:
|
||||
classname, funcname = name.split('::', 1)
|
||||
classname += '::'
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
signode += addnodes.desc_name(funcname, funcname)
|
||||
# name (the full name) is still both parts
|
||||
except ValueError:
|
||||
signode += addnodes.desc_name(name, name)
|
||||
# clean up parentheses from canonical name
|
||||
m = c_funcptr_name_re.match(name)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
if not arglist:
|
||||
if self.desctype == 'cfunction':
|
||||
# for functions, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
|
||||
# this messes up function pointer types, but not too badly ;)
|
||||
args = arglist.split(',')
|
||||
for arg in args:
|
||||
arg = arg.strip()
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
try:
|
||||
ctype, argname = arg.rsplit(' ', 1)
|
||||
except ValueError:
|
||||
# no argument name given, only the type
|
||||
self._parse_type(param, arg)
|
||||
else:
|
||||
self._parse_type(param, ctype)
|
||||
param += nodes.emphasis(' '+argname, ' '+argname)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
def get_index_text(self, name):
|
||||
if self.desctype == 'cfunction':
|
||||
return _('%s (C function)') % name
|
||||
elif self.desctype == 'cmember':
|
||||
return _('%s (C member)') % name
|
||||
elif self.desctype == 'cmacro':
|
||||
return _('%s (C macro)') % name
|
||||
elif self.desctype == 'ctype':
|
||||
return _('%s (C type)') % name
|
||||
elif self.desctype == 'cvar':
|
||||
return _('%s (C variable)') % name
|
||||
else:
|
||||
return ''
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
# note target
|
||||
if name not in self.state.document.ids:
|
||||
signode['names'].append(name)
|
||||
signode['ids'].append(name)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(name, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(name)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext, name, name))
|
||||
|
||||
|
||||
class CDomain(Domain):
|
||||
"""C language domain."""
|
||||
name = 'c'
|
||||
label = 'C'
|
||||
directives = {
|
||||
'function': CDesc,
|
||||
'member': CDesc,
|
||||
'macro': CDesc,
|
||||
'type': CDesc,
|
||||
'var': CDesc,
|
||||
}
|
||||
roles = {
|
||||
'member': XRefRole('c'),
|
||||
'macro': XRefRole('c'),
|
||||
'func' : XRefRole('c', True),
|
||||
'data': XRefRole('c'),
|
||||
'type': XRefRole('c'),
|
||||
}
|
||||
|
||||
|
||||
# this contains all registered domains
|
||||
domains = {}
|
||||
domains = {
|
||||
'py': PythonDomain,
|
||||
'c': CDomain,
|
||||
}
|
||||
+16
-64
@@ -48,6 +48,7 @@ from sphinx.errors import SphinxError
|
||||
from sphinx.domains import domains
|
||||
from sphinx.directives import additional_xref_types
|
||||
|
||||
orig_role_function = roles.role
|
||||
orig_directive_function = directives.directive
|
||||
|
||||
default_settings = {
|
||||
@@ -617,6 +618,21 @@ class BuildEnvironment:
|
||||
document)
|
||||
directives.directive = directive
|
||||
|
||||
def role(role_name, language_module, lineno, reporter):
|
||||
if ':' in role_name:
|
||||
domain_name, role_name = role_name.split(':', 1)
|
||||
if domain_name in domains:
|
||||
domain = domains[domain_name]
|
||||
if role_name in domain.roles:
|
||||
return domain.roles[role_name], []
|
||||
elif self.default_domain is not None:
|
||||
role = self.default_domain.roles.get(role_name)
|
||||
if role is not None:
|
||||
return role, []
|
||||
return orig_role_function(role_name, language_module,
|
||||
lineno, reporter)
|
||||
roles.role = role
|
||||
|
||||
# publish manually
|
||||
pub = Publisher(reader=SphinxStandaloneReader(),
|
||||
writer=SphinxDummyWriter(),
|
||||
@@ -1625,67 +1641,3 @@ class BuildEnvironment:
|
||||
if newname is None:
|
||||
return None, None
|
||||
return newname, self.descrefs[newname]
|
||||
|
||||
def find_keyword(self, keyword, avoid_fuzzy=False, cutoff=0.6, n=20):
|
||||
"""
|
||||
Find keyword matches for a keyword. If there's an exact match,
|
||||
just return it, else return a list of fuzzy matches if avoid_fuzzy
|
||||
isn't True.
|
||||
|
||||
Keywords searched are: first modules, then descrefs.
|
||||
|
||||
Returns: None if nothing found
|
||||
(type, docname, anchorname) if exact match found
|
||||
list of (quality, type, docname, anchorname, description)
|
||||
if fuzzy
|
||||
"""
|
||||
|
||||
if keyword in self.modules:
|
||||
docname, title, system, deprecated = self.modules[keyword]
|
||||
return 'module', docname, 'module-' + keyword
|
||||
if keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs[keyword]
|
||||
return ref_type, docname, keyword
|
||||
# special cases
|
||||
if '.' not in keyword:
|
||||
# exceptions are documented in the exceptions module
|
||||
if 'exceptions.'+keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs['exceptions.'+keyword]
|
||||
return ref_type, docname, 'exceptions.'+keyword
|
||||
# special methods are documented as object methods
|
||||
if 'object.'+keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs['object.'+keyword]
|
||||
return ref_type, docname, 'object.'+keyword
|
||||
|
||||
if avoid_fuzzy:
|
||||
return
|
||||
|
||||
# find fuzzy matches
|
||||
s = difflib.SequenceMatcher()
|
||||
s.set_seq2(keyword.lower())
|
||||
|
||||
def possibilities():
|
||||
for title, (fn, desc, _, _) in self.modules.iteritems():
|
||||
yield ('module', fn, 'module-'+title, desc)
|
||||
for title, (fn, desctype) in self.descrefs.iteritems():
|
||||
yield (desctype, fn, title, '')
|
||||
|
||||
def dotsearch(string):
|
||||
parts = string.lower().split('.')
|
||||
for idx in xrange(0, len(parts)):
|
||||
yield '.'.join(parts[idx:])
|
||||
|
||||
result = []
|
||||
for type, docname, title, desc in possibilities():
|
||||
best_res = 0
|
||||
for part in dotsearch(title):
|
||||
s.set_seq1(part)
|
||||
if s.real_quick_ratio() >= cutoff and \
|
||||
s.quick_ratio() >= cutoff and \
|
||||
s.ratio() >= cutoff and \
|
||||
s.ratio() > best_res:
|
||||
best_res = s.ratio()
|
||||
if best_res:
|
||||
result.append((best_res, type, docname, title, desc))
|
||||
|
||||
return heapq.nlargest(n, result)
|
||||
+81
-129
@@ -94,36 +94,6 @@ roles.register_local_role('pep', indexmarkup_role)
|
||||
roles.register_local_role('rfc', indexmarkup_role)
|
||||
|
||||
|
||||
def make_xref_role(link_func, nodeclass=None, innernodeclass=None):
|
||||
if nodeclass is None:
|
||||
nodeclass = addnodes.pending_xref
|
||||
if innernodeclass is None:
|
||||
innernodeclass = nodes.literal
|
||||
|
||||
def func(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
env = inliner.document.settings.env
|
||||
if not typ:
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
text = utils.unescape(text)
|
||||
# if the first character is a bang, don't cross-reference at all
|
||||
if text[0:1] == '!':
|
||||
text = _fix_parens(typ, text[1:], env)
|
||||
return [innernodeclass(rawtext, text, classes=['xref'])], []
|
||||
# we want a cross-reference, create the reference node
|
||||
pnode = nodeclass(rawtext, reftype=typ, refcaption=False,
|
||||
modname=env.currmodule, classname=env.currclass)
|
||||
# we may need the line number for warnings
|
||||
pnode.line = lineno
|
||||
has_explicit_title, title, target = split_explicit_title(text)
|
||||
target, title = link_func(env, pnode, has_explicit_title, title, target)
|
||||
pnode['reftarget'] = target
|
||||
pnode += innernodeclass(rawtext, title, classes=['xref'])
|
||||
return [pnode], []
|
||||
return func
|
||||
|
||||
|
||||
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [nodes.emphasis(
|
||||
rawtext,
|
||||
@@ -161,112 +131,92 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [addnodes.abbreviation(abbr, abbr, explanation=expl)], []
|
||||
|
||||
|
||||
def normalize_func_parens(env, has_explicit_title, title, target):
|
||||
if has_explicit_title:
|
||||
if title.endswith('()'):
|
||||
# remove parentheses
|
||||
title = title[:-2]
|
||||
if env.config.add_function_parentheses:
|
||||
# add them back to all occurrences if configured
|
||||
title += '()'
|
||||
# remove parentheses from the target too
|
||||
if target.endswith('()'):
|
||||
target = target[:-2]
|
||||
return target, title
|
||||
# -- generic cross-reference roles ---------------------------------------------
|
||||
|
||||
class XRefRole(object):
|
||||
nodeclass = addnodes.pending_xref
|
||||
innernodeclass = nodes.literal
|
||||
|
||||
def __init__(self, domain_name, fix_parens=False, lowercase=False,
|
||||
nodeclass=None, innernodeclass=None):
|
||||
self.domain_name = domain_name
|
||||
self.fix_parens = fix_parens
|
||||
if nodeclass is not None:
|
||||
self.nodeclass = nodeclass
|
||||
if innernodeclass is not None:
|
||||
self.innernodeclass = innernodeclass
|
||||
|
||||
def process_link(self, env, pnode, has_explicit_title, title, target):
|
||||
return title, ws_re.sub(' ', target)
|
||||
|
||||
def normalize_func_parens(self, env, has_explicit_title, title, target):
|
||||
if not has_explicit_title:
|
||||
if title.endswith('()'):
|
||||
# remove parentheses
|
||||
title = title[:-2]
|
||||
if env.config.add_function_parentheses:
|
||||
# add them back to all occurrences if configured
|
||||
title += '()'
|
||||
# remove parentheses from the target too
|
||||
if target.endswith('()'):
|
||||
target = target[:-2]
|
||||
return title, target
|
||||
|
||||
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
env = inliner.document.settings.env
|
||||
if not typ:
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
if ":" in typ:
|
||||
domain, role = typ.split(":", 1)
|
||||
else:
|
||||
domain, role = self.domain_name, typ
|
||||
text = utils.unescape(text)
|
||||
# if the first character is a bang, don't cross-reference at all
|
||||
if text[0:1] == '!':
|
||||
if self.fix_parens:
|
||||
text, _ = self.normalize_func_parens(env, False, text[1:], "")
|
||||
return [self.innernodeclass(rawtext, text, classes=['xref'])], []
|
||||
# split title and target in role content
|
||||
has_explicit_title, title, target = split_explicit_title(text)
|
||||
# we want a cross-reference, create the reference node
|
||||
pnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
|
||||
refcaption=has_explicit_title)
|
||||
# we may need the line number for warnings
|
||||
pnode.line = lineno
|
||||
title, target = self.process_link(env, pnode, has_explicit_title, title, target)
|
||||
pnode['reftarget'] = target
|
||||
pnode += self.innernodeclass(rawtext, title, classes=['xref'])
|
||||
return [pnode], []
|
||||
|
||||
|
||||
def generic_link_func(env, pnode, has_explicit_title, title, target):
|
||||
if has_explicit_title:
|
||||
pnode['refcaption'] = True
|
||||
return target, title
|
||||
class OptionXRefRole(XRefRole):
|
||||
innernodeclass = addnodes.literal_emphasis
|
||||
|
||||
|
||||
def pyref_link_func(env, pnode, has_explicit_title, title, target):
|
||||
if has_explicit_title:
|
||||
pnode['refcaption'] = True
|
||||
# fix-up parentheses in link title
|
||||
else:
|
||||
title = title.lstrip('.') # only has a meaning for the target
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
# if the first character is a tilde, don't display the module/class
|
||||
# parts of the contents
|
||||
if title[0:1] == '~':
|
||||
title = title[1:]
|
||||
dot = title.rfind('.')
|
||||
if dot != -1:
|
||||
title = title[dot+1:]
|
||||
# if the first character is a dot, search more specific namespaces first
|
||||
# else search builtins first
|
||||
if target[0:1] == '.':
|
||||
target = target[1:]
|
||||
pnode['refspecific'] = True
|
||||
return target, title
|
||||
|
||||
|
||||
def pyref_callable_link_func(env, pnode, has_explicit_title, title, target):
|
||||
target, title = pyref_link_func(env, pnode, has_explicit_title, title, target)
|
||||
target, title = normalize_func_parens(env, has_explicit_title, title, target)
|
||||
return target, title
|
||||
|
||||
|
||||
def option_link_func(env, pnode, has_explicit_title, title, target):
|
||||
program = env.currprogram
|
||||
if not has_explicit_title:
|
||||
if ' ' in title and not (title.startswith('/') or
|
||||
title.startswith('-')):
|
||||
program, target = re.split(' (?=-|--|/)', title, 1)
|
||||
def process_link(self, env, pnode, has_explicit_title, title, target):
|
||||
program = env.currprogram
|
||||
if not has_explicit_title:
|
||||
if ' ' in title and not (title.startswith('/') or
|
||||
title.startswith('-')):
|
||||
program, target = re.split(' (?=-|--|/)', title, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
target = target.strip()
|
||||
elif ' ' in target:
|
||||
program, target = re.split(' (?=-|--|/)', target, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
target = target.strip()
|
||||
elif ' ' in target:
|
||||
program, target = re.split(' (?=-|--|/)', target, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
pnode['refprogram'] = program
|
||||
return target, title
|
||||
pnode['refprogram'] = program
|
||||
return title, target
|
||||
|
||||
|
||||
def simple_link_func(env, pnode, has_explicit_title, title, target):
|
||||
# normalize all whitespace to avoid referencing problems
|
||||
target = ws_re.sub(' ', target)
|
||||
return target, title
|
||||
|
||||
|
||||
def lowercase_link_func(env, pnode, has_explicit_title, title, target):
|
||||
target, title = simple_link_func(env, pnode, has_explicit_title, title, target)
|
||||
return target.lower(), title
|
||||
|
||||
|
||||
def cfunc_link_func(env, pnode, has_explicit_title, title, target):
|
||||
return normalize_func_parens(env, has_explicit_title, title, target)
|
||||
|
||||
|
||||
generic_pyref_role = make_xref_role(pyref_link_func)
|
||||
callable_pyref_role = make_xref_role(pyref_callable_link_func)
|
||||
simple_xref_role = make_xref_role(simple_link_func)
|
||||
|
||||
specific_docroles = {
|
||||
'data': generic_pyref_role,
|
||||
'exc': generic_pyref_role,
|
||||
'func': callable_pyref_role,
|
||||
'class': generic_pyref_role,
|
||||
'const': generic_pyref_role,
|
||||
'attr': generic_pyref_role,
|
||||
'meth': callable_pyref_role,
|
||||
'mod': generic_pyref_role,
|
||||
'obj': generic_pyref_role,
|
||||
|
||||
'keyword': simple_xref_role,
|
||||
'ref': make_xref_role(lowercase_link_func, None, nodes.emphasis),
|
||||
'token': simple_xref_role,
|
||||
'term': make_xref_role(lowercase_link_func, None, nodes.emphasis),
|
||||
'option': make_xref_role(option_link_func, None, addnodes.literal_emphasis),
|
||||
'doc': simple_xref_role,
|
||||
'download': make_xref_role(simple_link_func, addnodes.download_reference),
|
||||
|
||||
'cmember': simple_xref_role,
|
||||
'cmacro': simple_xref_role,
|
||||
'cfunc' : make_xref_role(cfunc_link_func),
|
||||
'cdata': simple_xref_role,
|
||||
'ctype': simple_xref_role,
|
||||
'keyword': XRefRole(''),
|
||||
'ref': XRefRole('', lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'token': XRefRole(''),
|
||||
'term': XRefRole('', lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'option': OptionXRefRole('', innernodeclass=addnodes.literal_emphasis),
|
||||
'doc': XRefRole(''),
|
||||
'download': XRefRole('', nodeclass=addnodes.download_reference),
|
||||
|
||||
'menuselection': menusel_role,
|
||||
'file': emph_literal_role,
|
||||
@@ -276,3 +226,5 @@ specific_docroles = {
|
||||
|
||||
for rolename, func in specific_docroles.iteritems():
|
||||
roles.register_local_role(rolename, func)
|
||||
|
||||
|
||||
@@ -182,7 +182,8 @@ Testing öäü...
|
||||
Object markup
|
||||
-------------
|
||||
|
||||
:cfunc:`CFunction`.
|
||||
:c:func:`CFunction`. :c:func:`!malloc`.
|
||||
|
||||
|
||||
Only directive
|
||||
--------------
|
||||
@@ -207,3 +208,4 @@ Only directive
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#] Like footnotes.
|
||||
|
||||
Reference in new issue
Block a user