1. Georg Brandl
  2. sphinx

Source

sphinx / sphinx / roles.py

georg.brandl df246e3 






Georg Brandl 3a0071d 
Georg Brandl 4da052f 
georg.brandl df246e3 


Georg Brandl 640f7fa 
georg.brandl df246e3 



georg.brandl 60f4650 
Georg Brandl 2c2e7bb 
Georg Brandl 001ee05 
Georg Brandl 2b47372 

georg.brandl df246e3 


Georg Brandl 871d372 


georg.brandl b88cd9c 
Georg Brandl 871d372 
georg.brandl b88cd9c 


Georg Brandl 871d372 

georg.brandl df246e3 


Georg Brandl 62fe197 

Georg Brandl 4f2aaa4 
georg.brandl df246e3 
Georg Brandl d26043e 
mitsuhiko fef331c 
Georg Brandl 168a597 
Georg Brandl 87bd9b5 





















Georg Brandl 640f7fa 
Georg Brandl 168a597 

mitsuhiko fef331c 
Georg Brandl fcc58a0 
Georg Brandl 65c3dc1 
Georg Brandl 168a597 
Georg Brandl 4f74257 
Georg Brandl 65c3dc1 
Georg Brandl 168a597 



mitsuhiko fef331c 
Georg Brandl d26043e 
Georg Brandl 168a597 










mitsuhiko fef331c 
Georg Brandl ea68053 

Georg Brandl 168a597 




Georg Brandl fcc58a0 

Georg Brandl 65168aa 
Georg Brandl 168a597 
Georg Brandl fcc58a0 
Georg Brandl 65168aa 
Georg Brandl 168a597 

Georg Brandl 3d90480 
Georg Brandl 168a597 
Georg Brandl 3d90480 
Georg Brandl 62fe197 
Georg Brandl 8ca9a65 

Georg Brandl 168a597 

Georg Brandl 3a9bb82 
Georg Brandl 871d372 
Georg Brandl d26043e 
Georg Brandl 4f74257 


Georg Brandl 8ca9a65 
Georg Brandl d26043e 




Georg Brandl f23b936 
Georg Brandl d26043e 



Georg Brandl 62fe197 
Georg Brandl 7bf5d38 

Georg Brandl 65c3dc1 
Georg Brandl d26043e 
Georg Brandl 8ca9a65 
mitsuhiko fef331c 
Georg Brandl d26043e 
mitsuhiko fef331c 
Georg Brandl d26043e 
Georg Brandl d3456c0 



Georg Brandl 87bd9b5 
Georg Brandl d26043e 

Georg Brandl 8ca9a65 
Georg Brandl d3456c0 
Georg Brandl 87bd9b5 



Georg Brandl d26043e 

Georg Brandl e67c763 
Georg Brandl d833bd2 

Georg Brandl 87bd9b5 
georg.brandl df246e3 
georg.brandl 90e6d06 

georg.brandl 512a8d9 

georg.brandl fb8cc36 
Georg Brandl 7bed376 
georg.brandl c796bc4 
georg.brandl df246e3 

Georg Brandl d26043e 
Georg Brandl d833bd2 
Georg Brandl 3f5b9f7 

Georg Brandl b218e5c 



georg.brandl df246e3 


Georg Brandl d833bd2 

georg.brandl df246e3 



Georg Brandl b218e5c 

georg.brandl df246e3 
georg.brandl c796bc4 
georg.brandl df246e3 
Georg Brandl 3f5b9f7 
Georg Brandl b218e5c 



georg.brandl df246e3 


Georg Brandl d833bd2 

georg.brandl df246e3 



Georg Brandl b218e5c 

georg.brandl df246e3 
georg.brandl c796bc4 
georg.brandl df246e3 

Georg Brandl 494e382 
tpowers 90a4dec 
georg.brandl df246e3 
Georg Brandl b7a6f6a 
tpowers 90a4dec 
Georg Brandl b7a6f6a 
tpowers 90a4dec 
georg.brandl b2be57a 
Georg Brandl 494e382 
tpowers 90a4dec 






tpowers e443905 
tpowers 90a4dec 
tpowers e443905 


tpowers 90a4dec 




georg.brandl b2be57a 
georg.brandl 73e323e 
georg.brandl b2be57a 
Georg Brandl d833bd2 

georg.brandl b2be57a 

Georg Brandl 62fe197 
georg.brandl 73e323e 
georg.brandl b2be57a 

georg.brandl de96e31 

georg.brandl b2be57a 

georg.brandl de96e31 

georg.brandl df246e3 

Georg Brandl 06267ac 
Georg Brandl f69ec6d 










Georg Brandl a7aab8e 













Georg Brandl 3f5b9f7 






Georg Brandl a7aab8e 





georg.brandl df246e3 
Georg Brandl d26043e 


Georg Brandl 8df338a 
georg.brandl df246e3 
Georg Brandl e67c763 

tpowers 90a4dec 
Georg Brandl 4464818 


Georg Brandl f69ec6d 
Georg Brandl a7aab8e 
georg.brandl df246e3 


Georg Brandl 4f2aaa4 
Georg Brandl 168a597 

Georg Brandl 7bed376 
Georg Brandl 640f7fa 


# -*- coding: utf-8 -*-
"""
    sphinx.roles
    ~~~~~~~~~~~~

    Handlers for additional ReST roles.

    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

import re
import warnings

from docutils import nodes, utils
from docutils.parsers.rst import roles

from sphinx import addnodes
from sphinx.locale import _
from sphinx.util import ws_re
from sphinx.util.nodes import split_explicit_title, process_index_entry, \
     set_role_source_info


generic_docroles = {
    'command' : nodes.strong,
    'dfn' : nodes.emphasis,
    'kbd' : nodes.literal,
    'mailheader' : addnodes.literal_emphasis,
    'makevar' : nodes.strong,
    'manpage' : addnodes.literal_emphasis,
    'mimetype' : addnodes.literal_emphasis,
    'newsgroup' : addnodes.literal_emphasis,
    'program' : nodes.strong,  # XXX should be an x-ref
    'regexp' : nodes.literal,
}

for rolename, nodeclass in generic_docroles.iteritems():
    generic = roles.GenericRole(rolename, nodeclass)
    role = roles.CustomRole(rolename, generic, {'classes': [rolename]})
    roles.register_local_role(rolename, role)

# -- generic cross-reference role ----------------------------------------------

class XRefRole(object):
    """
    A generic cross-referencing role.  To create a callable that can be used as
    a role function, create an instance of this class.

    The general features of this role are:

    * Automatic creation of a reference and a content node.
    * Optional separation of title and target with `title <target>`.
    * The implementation is a class rather than a function to make
      customization easier.

    Customization can be done in two ways:

    * Supplying constructor parameters:
      * `fix_parens` to normalize parentheses (strip from target, and add to
        title if configured)
      * `lowercase` to lowercase the target
      * `nodeclass` and `innernodeclass` select the node classes for
        the reference and the content node

    * Subclassing and overwriting `process_link()` and/or `result_nodes()`.
    """

    nodeclass = addnodes.pending_xref
    innernodeclass = nodes.literal

    def __init__(self, fix_parens=False, lowercase=False,
                 nodeclass=None, innernodeclass=None, warn_dangling=False):
        self.fix_parens = fix_parens
        self.lowercase = lowercase
        self.warn_dangling = warn_dangling
        if nodeclass is not None:
            self.nodeclass = nodeclass
        if innernodeclass is not None:
            self.innernodeclass = innernodeclass

    def _fix_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 ':' not in typ:
            domain, role = '', typ
            classes = ['xref', role]
        else:
            domain, role = typ.split(':', 1)
            classes = ['xref', domain, '%s-%s' % (domain, role)]
        # if the first character is a bang, don't cross-reference at all
        if text[0:1] == '!':
            text = utils.unescape(text)[1:]
            if self.fix_parens:
                text, tgt = self._fix_parens(env, False, text, "")
            innernode = self.innernodeclass(rawtext, text, classes=classes)
            return self.result_nodes(inliner.document, env, innernode,
                                     is_ref=False)
        # split title and target in role content
        has_explicit_title, title, target = split_explicit_title(text)
        title = utils.unescape(title)
        target = utils.unescape(target)
        # fix-up title and target
        if self.lowercase:
            target = target.lower()
        if self.fix_parens:
            title, target = self._fix_parens(
                env, has_explicit_title, title, target)
        # create the reference node
        refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
                                 refexplicit=has_explicit_title)
        # we may need the line number for warnings
        set_role_source_info(inliner, lineno, refnode)
        title, target = self.process_link(
            env, refnode, has_explicit_title, title, target)
        # now that the target and title are finally determined, set them
        refnode['reftarget'] = target
        refnode += self.innernodeclass(rawtext, title, classes=classes)
        # we also need the source document
        refnode['refdoc'] = env.docname
        refnode['refwarn'] = self.warn_dangling
        # result_nodes allow further modification of return values
        return self.result_nodes(inliner.document, env, refnode, is_ref=True)

    # methods that can be overwritten

    def process_link(self, env, refnode, has_explicit_title, title, target):
        """Called after parsing title and target text, and creating the
        reference node (given in *refnode*).  This method can alter the
        reference node and must return a new (or the same) ``(title, target)``
        tuple.
        """
        return title, ws_re.sub(' ', target)

    def result_nodes(self, document, env, node, is_ref):
        """Called before returning the finished nodes.  *node* is the reference
        node if one was created (*is_ref* is then true), else the content node.
        This method can add other nodes and must return a ``(nodes, messages)``
        tuple (the usual return value of a role function).
        """
        return [node], []


def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
                     options={}, content=[]):
    """Role for PEP/RFC references that generate an index entry."""
    env = inliner.document.settings.env
    if not typ:
        typ = env.config.default_role
    else:
        typ = typ.lower()
    text = utils.unescape(etext)
    targetid = 'index-%s' % env.new_serialno('index')
    indexnode = addnodes.index()
    targetnode = nodes.target('', '', ids=[targetid])
    inliner.document.note_explicit_target(targetnode)
    if typ == 'pep':
        indexnode['entries'] = [
            ('single', _('Python Enhancement Proposals; PEP %s') % text,
             targetid, '')]
        anchor = ''
        anchorindex = text.find('#')
        if anchorindex > 0:
            text, anchor = text[:anchorindex], text[anchorindex:]
        try:
            pepnum = int(text)
        except ValueError:
            msg = inliner.reporter.error('invalid PEP number %s' % text,
                                         line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
        ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum
        sn = nodes.strong('PEP '+text, 'PEP '+text)
        rn = nodes.reference('', '', internal=False, refuri=ref+anchor,
                             classes=[typ])
        rn += sn
        return [indexnode, targetnode, rn], []
    elif typ == 'rfc':
        indexnode['entries'] = [('single', 'RFC; RFC %s' % text, targetid, '')]
        anchor = ''
        anchorindex = text.find('#')
        if anchorindex > 0:
            text, anchor = text[:anchorindex], text[anchorindex:]
        try:
            rfcnum = int(text)
        except ValueError:
            msg = inliner.reporter.error('invalid RFC number %s' % text,
                                         line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
        ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
        sn = nodes.strong('RFC '+text, 'RFC '+text)
        rn = nodes.reference('', '', internal=False, refuri=ref+anchor,
                             classes=[typ])
        rn += sn
        return [indexnode, targetnode, rn], []


_amp_re = re.compile(r'(?<!&)&(?![&\s])')

def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
    text = utils.unescape(text)
    if typ == 'menuselection':
        text = text.replace('-->', u'\N{TRIANGULAR BULLET}')
    spans = _amp_re.split(text)

    node = nodes.emphasis(rawtext=rawtext)
    for i, span in enumerate(spans):
        span = span.replace('&&', '&')
        if i == 0:
            if len(span) > 0:
                textnode = nodes.Text(span)
                node += textnode
            continue
        accel_node = nodes.inline()
        letter_node = nodes.Text(span[0])
        accel_node += letter_node
        accel_node['classes'].append('accelerator')
        node += accel_node
        textnode = nodes.Text(span[1:])
        node += textnode

    node['classes'].append(typ)
    return [node], []

_litvar_re = re.compile('{([^}]+)}')

def emph_literal_role(typ, rawtext, text, lineno, inliner,
                      options={}, content=[]):
    text = utils.unescape(text)
    pos = 0
    retnode = nodes.literal(role=typ.lower(), classes=[typ])
    for m in _litvar_re.finditer(text):
        if m.start() > pos:
            txt = text[pos:m.start()]
            retnode += nodes.Text(txt, txt)
        retnode += nodes.emphasis(m.group(1), m.group(1))
        pos = m.end()
    if pos < len(text):
        retnode += nodes.Text(text[pos:], text[pos:])
    return [retnode], []


_abbr_re = re.compile('\((.*)\)$', re.S)

def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
    text = utils.unescape(text)
    m = _abbr_re.search(text)
    if m is None:
        return [addnodes.abbreviation(text, text)], []
    abbr = text[:m.start()].strip()
    expl = m.group(1)
    return [addnodes.abbreviation(abbr, abbr, explanation=expl)], []


def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
    # create new reference target
    env = inliner.document.settings.env
    targetid = 'index-%s' % env.new_serialno('index')
    targetnode = nodes.target('', '', ids=[targetid])
    # split text and target in role content
    has_explicit_title, title, target = split_explicit_title(text)
    title = utils.unescape(title)
    target = utils.unescape(target)
    # if an explicit target is given, we can process it as a full entry
    if has_explicit_title:
        entries = process_index_entry(target, targetid)
    # otherwise we just create a "single" entry
    else:
        # but allow giving main entry
        main = ''
        if target.startswith('!'):
            target = target[1:]
            title = title[1:]
            main = 'main'
        entries = [('single', target, targetid, main)]
    indexnode = addnodes.index()
    indexnode['entries'] = entries
    textnode = nodes.Text(title, title)
    return [indexnode, targetnode, textnode], []


specific_docroles = {
    # links to download references
    'download': XRefRole(nodeclass=addnodes.download_reference),
    # links to documents
    'doc': XRefRole(warn_dangling=True),

    'pep': indexmarkup_role,
    'rfc': indexmarkup_role,
    'guilabel': menusel_role,
    'menuselection': menusel_role,
    'file': emph_literal_role,
    'samp': emph_literal_role,
    'abbr': abbr_role,
    'index': index_role,
}

for rolename, func in specific_docroles.iteritems():
    roles.register_local_role(rolename, func)


# backwards compatibility alias
def xfileref_role(*args, **kwds):
    warnings.warn('xfileref_role is deprecated, use XRefRole',
                  DeprecationWarning, stacklevel=2)
    return XRefRole()(*args, **kwds)