sphinx-i18n / sphinx / directives /

Full commit
# -*- coding: utf-8 -*-

    Handlers for additional ReST directives.

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

import re

from docutils.parsers.rst import Directive, directives
from docutils.parsers.rst.directives import images

from sphinx import addnodes
from sphinx.util.docfields import DocFieldTransformer

# import and register directives
from sphinx.directives.code import *
from sphinx.directives.other import *

# allow units for the figure's "figwidth"
    images.Figure.option_spec['figwidth'] = \
except AttributeError:
    images.figure.options['figwidth'] = \

# RE to strip backslash escapes
nl_escape_re = re.compile(r'\\\n')
strip_backslash_re = re.compile(r'\\(?=[^\\])')

class ObjectDescription(Directive):
    Directive to describe a class, function or similar object.  Not used
    directly, but subclassed (in domain-specific directives) to add custom

    has_content = True
    required_arguments = 1
    optional_arguments = 0
    final_argument_whitespace = True
    option_spec = {
        'noindex': directives.flag,

    # types of doc fields that this directive handles, see sphinx.util.docfields
    doc_field_types = []

    def get_signatures(self):
        Retrieve the signatures to document from the directive arguments.  By
        default, signatures are given as arguments, one per line.

        Backslash-escaping of newlines is supported.
        lines = nl_escape_re.sub('', self.arguments[0]).split('\n')
        # remove backslashes to support (dummy) escapes; helps Vim highlighting
        return [strip_backslash_re.sub('', line.strip()) for line in lines]

    def handle_signature(self, sig, signode):
        Parse the signature *sig* into individual nodes and append them to
        *signode*. If ValueError is raised, parsing is aborted and the whole
        *sig* is put into a single desc_name node.

        The return value should be a value that identifies the object.  It is
        passed to :meth:`add_target_and_index()` unchanged, and otherwise only
        used to skip duplicates.
        raise ValueError

    def add_target_and_index(self, name, sig, signode):
        Add cross-reference IDs and entries to self.indexnode, if applicable.

        *name* is whatever :meth:`handle_signature()` returned.
        return  # do nothing by default

    def before_content(self):
        Called before parsing content. Used to set information about the current
        directive context on the build environment.

    def after_content(self):
        Called after parsing content. Used to reset information about the
        current directive context on the build environment.

    def run(self):
        Main directive entry function, called by docutils upon encountering the

        This directive is meant to be quite easily subclassable, so it delegates
        to several additional methods.  What it does:

        * find out if called as a domain-specific directive, set self.domain
        * create a `desc` node to fit all description inside
        * parse standard options, currently `noindex`
        * create an index node if needed as self.indexnode
        * parse all given signatures (as returned by self.get_signatures())
          using self.handle_signature(), which should either return a name
          or raise ValueError
        * add index entries using self.add_target_and_index()
        * parse the content and handle doc fields in it
        if ':' in
            self.domain, self.objtype =':', 1)
            self.domain, self.objtype = '',
        self.env = self.state.document.settings.env
        self.indexnode = addnodes.index(entries=[])

        node = addnodes.desc()
        node.document = self.state.document
        node['domain'] = self.domain
        # 'desctype' is a backwards compatible attribute
        node['objtype'] = node['desctype'] = self.objtype
        node['noindex'] = noindex = ('noindex' in self.options)

        self.names = []
        signatures = self.get_signatures()
        for i, sig in enumerate(signatures):
            # add a signature node for each signature in the current unit
            # and add a reference target for it
            signode = addnodes.desc_signature(sig, '')
            signode['first'] = False
                # name can also be a tuple, e.g. (classname, objname);
                # this is strictly domain-specific (i.e. no assumptions may
                # be made in this base class)
                name = self.handle_signature(sig, signode)
            except ValueError:
                # signature parsing failed
                signode += addnodes.desc_name(sig, sig)
                continue  # we don't want an index entry here
            if not noindex and name not in self.names:
                # only add target and index entry if this is the first
                # description of the object with this name in this desc block
                self.add_target_and_index(name, sig, signode)

        contentnode = addnodes.desc_content()
        if self.names:
            # needed for association of version{added,changed} directives
            self.env.temp_data['object'] = self.names[0]
        self.state.nested_parse(self.content, self.content_offset, contentnode)
        self.env.temp_data['object'] = None
        return [self.indexnode, node]

# backwards compatible old name
DescDirective = ObjectDescription

class DefaultDomain(Directive):
    Directive to (re-)set the default domain for this source file.

    has_content = False
    required_arguments = 1
    optional_arguments = 0
    final_argument_whitespace = False
    option_spec = {}

    def run(self):
        env = self.state.document.settings.env
        domain_name = self.arguments[0].lower()
        # if domain_name not in
        #     # try searching by label
        #     for domain in
        #         if domain.label.lower() == domain_name:
        #             domain_name =
        #             break
        env.temp_data['default_domain'] =
        return []

directives.register_directive('default-domain', DefaultDomain)
directives.register_directive('describe', ObjectDescription)
# new, more consistent, name
directives.register_directive('object', ObjectDescription)