[Python-checkins] r62708 - in doctools/trunk/sphinx: directives directives.py directives/__init__.py directives/code.py directives/desc.py directives/other.py
georg.brandl
python-checkins at python.org
Sun May 4 19:22:32 CEST 2008
Author: georg.brandl
Date: Sun May 4 19:22:31 2008
New Revision: 62708
Log:
Split directives into a subpackage.
Added:
doctools/trunk/sphinx/directives/
doctools/trunk/sphinx/directives/__init__.py
doctools/trunk/sphinx/directives/code.py
doctools/trunk/sphinx/directives/desc.py
doctools/trunk/sphinx/directives/other.py
Removed:
doctools/trunk/sphinx/directives.py
Deleted: doctools/trunk/sphinx/directives.py
==============================================================================
--- doctools/trunk/sphinx/directives.py Sun May 4 19:22:31 2008
+++ (empty file)
@@ -1,856 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.directives
- ~~~~~~~~~~~~~~~~~
-
- Handlers for additional ReST directives.
-
- :copyright: 2007-2008 by Georg Brandl.
- :license: BSD.
-"""
-
-import re
-import sys
-import string
-import posixpath
-from os import path
-
-from docutils import nodes
-from docutils.parsers.rst import directives
-
-from sphinx import addnodes
-from sphinx.util import patfilter
-from sphinx.roles import caption_ref_re
-from sphinx.util.compat import make_admonition
-
-ws_re = re.compile(r'\s+')
-
-# ------ index markup --------------------------------------------------------------
-
-entrytypes = [
- 'single', 'pair', 'triple', 'module', 'keyword', 'operator',
- 'object', 'exception', 'statement', 'builtin',
-]
-
-def index_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- arguments = arguments[0].split('\n')
- env = state.document.settings.env
- targetid = 'index-%s' % env.index_num
- env.index_num += 1
- targetnode = nodes.target('', '', ids=[targetid])
- state.document.note_explicit_target(targetnode)
- indexnode = addnodes.index()
- indexnode['entries'] = ne = []
- for entry in arguments:
- entry = entry.strip()
- for type in entrytypes:
- if entry.startswith(type+':'):
- value = entry[len(type)+1:].strip()
- env.note_index_entry(type, value, targetid, value)
- ne.append((type, value, targetid, value))
- break
- # shorthand notation for single entries
- else:
- for value in entry.split(','):
- env.note_index_entry('single', value.strip(), targetid, value.strip())
- ne.append(('single', value.strip(), targetid, value.strip()))
- return [indexnode, targetnode]
-
-index_directive.arguments = (1, 0, 1)
-directives.register_directive('index', index_directive)
-
-# ------ information units ---------------------------------------------------------
-
-def desc_index_text(desctype, currmodule, name):
- if desctype == 'function':
- if not currmodule:
- return '%s() (built-in function)' % name
- return '%s() (in module %s)' % (name, currmodule)
- elif desctype == 'data':
- if not currmodule:
- return '%s (built-in variable)' % name
- return '%s (in module %s)' % (name, currmodule)
- elif desctype == 'class':
- return '%s (class in %s)' % (name, currmodule)
- elif desctype == 'exception':
- return name
- elif desctype == 'method':
- try:
- clsname, methname = name.rsplit('.', 1)
- except ValueError:
- if currmodule:
- return '%s() (in module %s)' % (name, currmodule)
- else:
- return '%s()' % name
- if currmodule:
- return '%s() (%s.%s method)' % (methname, currmodule, clsname)
- else:
- return '%s() (%s method)' % (methname, clsname)
- elif desctype == 'attribute':
- try:
- clsname, attrname = name.rsplit('.', 1)
- except ValueError:
- if currmodule:
- return '%s (in module %s)' % (name, currmodule)
- else:
- return name
- if currmodule:
- return '%s (%s.%s attribute)' % (attrname, currmodule, clsname)
- else:
- return '%s (%s attribute)' % (attrname, clsname)
- elif desctype == 'opcode':
- return '%s (opcode)' % name
- elif desctype == 'cfunction':
- return '%s (C function)' % name
- elif desctype == 'cmember':
- return '%s (C member)' % name
- elif desctype == 'cmacro':
- return '%s (C macro)' % name
- elif desctype == 'ctype':
- return '%s (C type)' % name
- elif desctype == 'cvar':
- return '%s (C variable)' % name
- else:
- raise ValueError("unhandled descenv: %s" % desctype)
-
-
-# ------ functions to parse a Python or C signature and create desc_* nodes.
-
-py_sig_re = re.compile(r'''^([\w.]*\.)? # class names
- (\w+) \s* # thing name
- (?: \((.*)\) )? $ # optionally arguments
- ''', re.VERBOSE)
-
-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 (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 = m.groups()
-
- add_module = True
- if env.currclass:
- if classname and classname.startswith(env.currclass):
- fullname = classname + name
- # class name is given again in the signature
- classname = classname[len(env.currclass):].lstrip('.')
- add_module = False
- elif classname:
- # class name is given in the signature, but different
- fullname = env.currclass + '.' + classname + name
- else:
- # class name is not given in the signature
- fullname = env.currclass + '.' + name
- add_module = False
- else:
- fullname = classname and classname + name or name
-
- if classname:
- signode += addnodes.desc_classname(classname, classname)
- # exceptions are a special case, since they are documented in the
- # 'exceptions' module.
- elif add_module and env.config.add_module_names and \
- env.currmodule and env.currmodule != 'exceptions':
- nodetext = env.currmodule + '.'
- signode += addnodes.desc_classname(nodetext, nodetext)
-
- signode += addnodes.desc_name(name, name)
- if not arglist:
- if desctype in ('function', 'method'):
- # for callables, add an empty parameter list
- signode += addnodes.desc_parameterlist()
- 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
- return fullname, classname
-
-
-c_sig_re = re.compile(
- r'''^([^(]*?) # return type
- ([\w:]+) \s* # thing name (colon allowed for C++ class names)
- (?: \((.*)\) )? $ # optionally arguments
- ''', re.VERBOSE)
-c_funcptr_sig_re = re.compile(
- r'''^([^(]+?) # return type
- (\( [^()]+ \)) \s* # name in parentheses
- \( (.*) \) $ # arguments
- ''', re.VERBOSE)
-c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
-
-# RE to split at word boundaries
-wsplit_re = re.compile(r'(\W+)')
-
-# These C types aren't described in the reference, so don't try to create
-# a cross-reference to them
-stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
-
-def parse_c_type(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.letters+'_' and part not in stopwords:
- pnode = addnodes.pending_xref(
- '', reftype='ctype', reftarget=part, modname=None, classname=None)
- pnode += tnode
- node += pnode
- else:
- node += tnode
-
-def parse_c_signature(signode, sig, desctype):
- """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 = m.groups()
-
- signode += addnodes.desc_type("", "")
- parse_c_type(signode[-1], rettype)
- 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 desctype == 'cfunction':
- # for functions, add an empty parameter list
- signode += addnodes.desc_parameterlist()
- 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
- parse_c_type(param, arg)
- else:
- parse_c_type(param, ctype)
- param += nodes.emphasis(' '+argname, ' '+argname)
- paramlist += param
- signode += paramlist
- return name
-
-
-opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)\s*\((.*)\)')
-
-def parse_opcode_signature(signode, sig):
- """Transform an opcode signature into RST nodes."""
- m = opcode_sig_re.match(sig)
- if m is None:
- raise ValueError
- opname, arglist = m.groups()
- signode += addnodes.desc_name(opname, opname)
- paramlist = addnodes.desc_parameterlist()
- signode += paramlist
- paramlist += addnodes.desc_parameter(arglist, arglist)
- return opname.strip()
-
-
-option_desc_re = re.compile(
- r'(/|-|--)([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
-
-def parse_option_desc(signode, sig):
- """Transform an option description into RST nodes."""
- count = 0
- firstname = ''
- for m in option_desc_re.finditer(sig):
- prefix, optname, args = m.groups()
- if count:
- signode += addnodes.desc_classname(', ', ', ')
- signode += addnodes.desc_name(prefix+optname, prefix+optname)
- signode += addnodes.desc_classname(args, args)
- if not count:
- firstname = optname
- count += 1
- if not firstname:
- raise ValueError
- return firstname
-
-
-def desc_directive(desctype, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- env = state.document.settings.env
- node = addnodes.desc()
- node['desctype'] = desctype
-
- noindex = ('noindex' in options)
- node['noindex'] = noindex
- # remove backslashes to support (dummy) escapes; helps Vim's highlighting
- signatures = map(lambda s: s.strip().replace('\\', ''), 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
- sig = sig.strip()
- signode = addnodes.desc_signature(sig, '')
- signode['first'] = False
- node.append(signode)
- try:
- if desctype in ('function', 'data', 'class', 'exception',
- 'method', 'attribute'):
- 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':
- name = parse_opcode_signature(signode, sig)
- elif desctype == 'cmdoption':
- optname = parse_option_desc(signode, sig)
- if not noindex:
- targetname = 'cmdoption-' + optname
- signode['ids'].append(targetname)
- state.document.note_explicit_target(signode)
- env.note_index_entry('pair', 'command line option; %s' % sig,
- targetname, targetname)
- env.note_reftarget('option', optname, targetname)
- continue
- elif desctype == 'describe':
- signode.clear()
- signode += addnodes.desc_name(sig, sig)
- continue
- else:
- # another registered generic x-ref directive
- rolename, indextemplate, parse_node = additional_xref_types[desctype]
- if parse_node:
- fullname = parse_node(env, sig, signode)
- else:
- signode.clear()
- signode += addnodes.desc_name(sig, sig)
- # normalize whitespace like xfileref_role does
- fullname = ws_re.sub('', sig)
- if not noindex:
- targetname = '%s-%s' % (rolename, fullname)
- signode['ids'].append(targetname)
- state.document.note_explicit_target(signode)
- if indextemplate:
- indexentry = indextemplate % (fullname,)
- indextype = 'single'
- colon = indexentry.find(':')
- if colon != -1:
- indextype = indexentry[:colon].strip()
- indexentry = indexentry[colon+1:].strip()
- env.note_index_entry(indextype, indexentry,
- targetname, targetname)
- env.note_reftarget(rolename, fullname, targetname)
- # don't use object indexing below
- continue
- except ValueError, err:
- # signature parsing failed
- signode.clear()
- signode += addnodes.desc_name(sig, sig)
- continue # we don't want an index entry here
- # only add target and index entry if this is the first description of the
- # function name in this desc block
- if not noindex and name not in names:
- fullname = (env.currmodule and env.currmodule + '.' or '') + name
- # note target
- if fullname not in state.document.ids:
- signode['names'].append(fullname)
- signode['ids'].append(fullname)
- signode['first'] = (not names)
- state.document.note_explicit_target(signode)
- env.note_descref(fullname, desctype, lineno)
- names.append(name)
-
- env.note_index_entry('single',
- desc_index_text(desctype, env.currmodule, name),
- fullname, fullname)
-
- subnode = addnodes.desc_content()
- # needed for automatic qualification of members
- clsname_set = False
- if desctype in ('class', 'exception') 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 clsname_set:
- env.currclass = None
- env.currdesc = None
- node.append(subnode)
- return [node]
-
-desc_directive.content = 1
-desc_directive.arguments = (1, 0, 1)
-desc_directive.options = {'noindex': directives.flag}
-
-desctypes = [
- # the Python ones
- 'function',
- 'data',
- 'class',
- 'method',
- 'attribute',
- 'exception',
- # the C ones
- 'cfunction',
- 'cmember',
- 'cmacro',
- 'ctype',
- 'cvar',
- # the odd one
- 'opcode',
- # for command line options
- 'cmdoption',
- # the generic one
- 'describe',
- 'envvar',
-]
-
-for _name in desctypes:
- directives.register_directive(_name, desc_directive)
-
-# Generic cross-reference types; they can be registered in the application;
-# the directives are either desc_directive or target_directive
-additional_xref_types = {
- # directive name: (role name, index text, function to parse the desc node)
- 'envvar': ('envvar', 'environment variable; %s', None),
-}
-
-
-# ------ target --------------------------------------------------------------------
-
-def target_directive(targettype, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- """Generic target for user-defined cross-reference types."""
- env = state.document.settings.env
- rolename, indextemplate, _ = additional_xref_types[targettype]
- # normalize whitespace in fullname like xfileref_role does
- fullname = ws_re.sub('', arguments[0].strip())
- targetname = '%s-%s' % (rolename, fullname)
- node = nodes.target('', '', ids=[targetname])
- state.document.note_explicit_target(node)
- if indextemplate:
- indexentry = indextemplate % (fullname,)
- indextype = 'single'
- colon = indexentry.find(':')
- if colon != -1:
- indextype = indexentry[:colon].strip()
- indexentry = indexentry[colon+1:].strip()
- env.note_index_entry(indextype, indexentry, targetname, targetname)
- env.note_reftarget(rolename, fullname, targetname)
- return [node]
-
-target_directive.content = 0
-target_directive.arguments = (1, 0, 1)
-
-
-# ------ versionadded/versionchanged -----------------------------------------------
-
-def version_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- node = addnodes.versionmodified()
- node['type'] = name
- node['version'] = arguments[0]
- if len(arguments) == 2:
- inodes, messages = state.inline_text(arguments[1], lineno+1)
- node.extend(inodes)
- if content:
- state.nested_parse(content, content_offset, node)
- ret = [node] + messages
- else:
- ret = [node]
- env = state.document.settings.env
- env.note_versionchange(node['type'], node['version'], node, lineno)
- return ret
-
-version_directive.arguments = (1, 1, 1)
-version_directive.content = 1
-
-directives.register_directive('deprecated', version_directive)
-directives.register_directive('versionadded', version_directive)
-directives.register_directive('versionchanged', version_directive)
-
-
-# ------ see also ------------------------------------------------------------------
-
-def seealso_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- rv = make_admonition(
- addnodes.seealso, name, ['See also'], options, content,
- lineno, content_offset, block_text, state, state_machine)
- return rv
-
-seealso_directive.content = 1
-seealso_directive.arguments = (0, 0, 0)
-directives.register_directive('seealso', seealso_directive)
-
-
-# ------ production list (for the reference) ---------------------------------------
-
-token_re = re.compile('`([a-z_]+)`')
-
-def token_xrefs(text, env):
- retnodes = []
- pos = 0
- for m in token_re.finditer(text):
- if m.start() > pos:
- txt = text[pos:m.start()]
- retnodes.append(nodes.Text(txt, txt))
- refnode = addnodes.pending_xref(m.group(1))
- refnode['reftype'] = 'token'
- refnode['reftarget'] = m.group(1)
- refnode['modname'] = env.currmodule
- refnode['classname'] = env.currclass
- refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
- retnodes.append(refnode)
- pos = m.end()
- if pos < len(text):
- retnodes.append(nodes.Text(text[pos:], text[pos:]))
- return retnodes
-
-def productionlist_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- env = state.document.settings.env
- node = addnodes.productionlist()
- messages = []
- i = 0
-
- for rule in arguments[0].split('\n'):
- if i == 0 and ':' not in rule:
- # production group
- continue
- i += 1
- try:
- name, tokens = rule.split(':', 1)
- except ValueError:
- break
- subnode = addnodes.production()
- subnode['tokenname'] = name.strip()
- if subnode['tokenname']:
- idname = 'grammar-token-%s' % subnode['tokenname']
- if idname not in state.document.ids:
- subnode['ids'].append(idname)
- state.document.note_implicit_target(subnode, subnode)
- env.note_reftarget('token', subnode['tokenname'], idname)
- subnode.extend(token_xrefs(tokens, env))
- node.append(subnode)
- return [node] + messages
-
-productionlist_directive.content = 0
-productionlist_directive.arguments = (1, 0, 1)
-directives.register_directive('productionlist', productionlist_directive)
-
-# ------ section metadata ----------------------------------------------------------
-
-def module_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- env = state.document.settings.env
- modname = arguments[0].strip()
- env.currmodule = modname
- env.note_module(modname, options.get('synopsis', ''),
- options.get('platform', ''),
- 'deprecated' in options)
- modulenode = addnodes.module()
- modulenode['modname'] = modname
- modulenode['synopsis'] = options.get('synopsis', '')
- targetnode = nodes.target('', '', ids=['module-' + modname])
- state.document.note_explicit_target(targetnode)
- ret = [modulenode, targetnode]
- if 'platform' in options:
- modulenode['platform'] = options['platform']
- node = nodes.paragraph()
- node += nodes.emphasis('Platforms: ', 'Platforms: ')
- node += nodes.Text(options['platform'], options['platform'])
- ret.append(node)
- # the synopsis isn't printed; in fact, it is only used in the modindex currently
- env.note_index_entry('single', '%s (module)' % modname, 'module-' + modname,
- modname)
- return ret
-
-module_directive.arguments = (1, 0, 0)
-module_directive.options = {'platform': lambda x: x,
- 'synopsis': lambda x: x,
- 'deprecated': directives.flag}
-directives.register_directive('module', module_directive)
-
-
-def currentmodule_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- # This directive is just to tell people that we're documenting
- # stuff in module foo, but links to module foo won't lead here.
- env = state.document.settings.env
- modname = arguments[0].strip()
- env.currmodule = modname
- return []
-
-currentmodule_directive.arguments = (1, 0, 0)
-directives.register_directive('currentmodule', currentmodule_directive)
-
-
-def author_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- # Show authors only if the show_authors option is on
- env = state.document.settings.env
- if not env.config.show_authors:
- return []
- para = nodes.paragraph()
- emph = nodes.emphasis()
- para += emph
- if name == 'sectionauthor':
- text = 'Section author: '
- elif name == 'moduleauthor':
- text = 'Module author: '
- else:
- text = 'Author: '
- emph += nodes.Text(text, text)
- inodes, messages = state.inline_text(arguments[0], lineno)
- emph.extend(inodes)
- return [para] + messages
-
-author_directive.arguments = (1, 0, 1)
-directives.register_directive('sectionauthor', author_directive)
-directives.register_directive('moduleauthor', author_directive)
-
-
-# ------ toctree directive ---------------------------------------------------------
-
-def toctree_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- env = state.document.settings.env
- suffix = env.config.source_suffix
- dirname = posixpath.dirname(env.docname)
- glob = 'glob' in options
-
- ret = []
- subnode = addnodes.toctree()
- includefiles = []
- includetitles = {}
- all_docnames = env.found_docs.copy()
- # don't add the currently visited file in catch-all patterns
- all_docnames.remove(env.docname)
- for entry in content:
- if not entry:
- continue
- if not glob:
- # look for explicit titles and documents ("Some Title <document>").
- m = caption_ref_re.match(entry)
- if m:
- docname = m.group(2)
- includetitles[docname] = m.group(1)
- else:
- docname = entry
- # remove suffixes (backwards compatibility)
- if docname.endswith(suffix):
- docname = docname[:-len(suffix)]
- # absolutize filenames
- docname = posixpath.normpath(posixpath.join(dirname, docname))
- if docname not in env.found_docs:
- ret.append(state.document.reporter.warning(
- 'toctree references unknown document %r' % docname, line=lineno))
- else:
- includefiles.append(docname)
- else:
- patname = posixpath.normpath(posixpath.join(dirname, entry))
- docnames = sorted(patfilter(all_docnames, patname))
- for docname in docnames:
- all_docnames.remove(docname) # don't include it again
- includefiles.append(docname)
- if not docnames:
- ret.append(state.document.reporter.warning(
- 'toctree glob pattern %r didn\'t match any documents' % entry,
- line=lineno))
- subnode['includefiles'] = includefiles
- subnode['includetitles'] = includetitles
- subnode['maxdepth'] = options.get('maxdepth', -1)
- ret.append(subnode)
- return ret
-
-toctree_directive.content = 1
-toctree_directive.options = {'maxdepth': int, 'glob': directives.flag}
-directives.register_directive('toctree', toctree_directive)
-
-
-# ------ centered directive ---------------------------------------------------------
-
-def centered_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- if not arguments:
- return []
- subnode = addnodes.centered()
- inodes, messages = state.inline_text(arguments[0], lineno)
- subnode.extend(inodes)
- return [subnode] + messages
-
-centered_directive.arguments = (1, 0, 1)
-directives.register_directive('centered', centered_directive)
-
-
-# ------ highlight directive --------------------------------------------------------
-
-def highlightlang_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- if 'linenothreshold' in options:
- try:
- linenothreshold = int(options['linenothreshold'])
- except Exception:
- linenothreshold = 10
- else:
- linenothreshold = sys.maxint
- return [addnodes.highlightlang(lang=arguments[0].strip(),
- linenothreshold=linenothreshold)]
-
-highlightlang_directive.content = 0
-highlightlang_directive.arguments = (1, 0, 0)
-highlightlang_directive.options = {'linenothreshold': directives.unchanged}
-directives.register_directive('highlight', highlightlang_directive)
-directives.register_directive('highlightlang', highlightlang_directive) # old name
-
-
-# ------ code-block directive -------------------------------------------------------
-
-def codeblock_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- code = u'\n'.join(content)
- literal = nodes.literal_block(code, code)
- literal['language'] = arguments[0]
- literal['linenos'] = 'linenos' in options
- return [literal]
-
-codeblock_directive.content = 1
-codeblock_directive.arguments = (1, 0, 0)
-codeblock_directive.options = {'linenos': directives.flag}
-directives.register_directive('code-block', codeblock_directive)
-directives.register_directive('sourcecode', codeblock_directive)
-
-
-# ------ literalinclude directive ---------------------------------------------------
-
-def literalinclude_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- """Like .. include:: :literal:, but only warns if the include file is not found."""
- if not state.document.settings.file_insertion_enabled:
- return [state.document.reporter.warning('File insertion disabled', line=lineno)]
- env = state.document.settings.env
- rel_fn = arguments[0]
- source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
- lineno - state_machine.input_offset - 1)))
- fn = path.normpath(path.join(source_dir, rel_fn))
-
- try:
- f = open(fn)
- text = f.read()
- f.close()
- except (IOError, OSError):
- retnode = state.document.reporter.warning(
- 'Include file %r not found or reading it failed' % arguments[0], line=lineno)
- else:
- retnode = nodes.literal_block(text, text, source=fn)
- retnode.line = 1
- if options.get('language', ''):
- retnode['language'] = options['language']
- if 'linenos' in options:
- retnode['linenos'] = True
- state.document.settings.env.note_dependency(rel_fn)
- return [retnode]
-
-literalinclude_directive.options = {'linenos': directives.flag,
- 'language': directives.unchanged}
-literalinclude_directive.content = 0
-literalinclude_directive.arguments = (1, 0, 0)
-directives.register_directive('literalinclude', literalinclude_directive)
-
-
-# ------ glossary directive ---------------------------------------------------------
-
-def glossary_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- """Glossary with cross-reference targets for :dfn: roles."""
- env = state.document.settings.env
- node = addnodes.glossary()
- state.nested_parse(content, content_offset, node)
-
- # the content should be definition lists
- dls = [child for child in node if isinstance(child, nodes.definition_list)]
- # now, extract definition terms to enable cross-reference creation
- for dl in dls:
- dl['classes'].append('glossary')
- for li in dl.children:
- if not li.children or not isinstance(li[0], nodes.term):
- continue
- termtext = li.children[0].astext()
- new_id = 'term-' + nodes.make_id(termtext)
- if new_id in env.gloss_entries:
- new_id = 'term-' + str(len(env.gloss_entries))
- env.gloss_entries.add(new_id)
- li[0]['names'].append(new_id)
- li[0]['ids'].append(new_id)
- state.document.settings.env.note_reftarget('term', termtext.lower(),
- new_id)
- return [node]
-
-glossary_directive.content = 1
-glossary_directive.arguments = (0, 0, 0)
-directives.register_directive('glossary', glossary_directive)
-
-
-# ------ acks directive -------------------------------------------------------------
-
-def acks_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- node = addnodes.acks()
- state.nested_parse(content, content_offset, node)
- if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list):
- return [state.document.reporter.warning('.. acks content is not a list',
- line=lineno)]
- return [node]
-
-acks_directive.content = 1
-acks_directive.arguments = (0, 0, 0)
-directives.register_directive('acks', acks_directive)
-
-
-# ------ tabularcolumns directive ---------------------------------------------------
-
-def tabularcolumns_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- # support giving explicit tabulary column definition to latex
- node = addnodes.tabular_col_spec()
- node['spec'] = arguments[0]
- return [node]
-
-tabularcolumns_directive.content = 0
-tabularcolumns_directive.arguments = (1, 0, 1)
-directives.register_directive('tabularcolumns', tabularcolumns_directive)
-
Added: doctools/trunk/sphinx/directives/__init__.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/directives/__init__.py Sun May 4 19:22:31 2008
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives
+ ~~~~~~~~~~~~~~~~~
+
+ Handlers for additional ReST directives.
+
+ :copyright: 2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+from sphinx.directives.desc import *
+from sphinx.directives.code import *
+from sphinx.directives.other import *
Added: doctools/trunk/sphinx/directives/code.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/directives/code.py Sun May 4 19:22:31 2008
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives.code
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: 2007-2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+import sys
+from os import path
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+
+
+# ------ highlight directive --------------------------------------------------------
+
+def highlightlang_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ if 'linenothreshold' in options:
+ try:
+ linenothreshold = int(options['linenothreshold'])
+ except Exception:
+ linenothreshold = 10
+ else:
+ linenothreshold = sys.maxint
+ return [addnodes.highlightlang(lang=arguments[0].strip(),
+ linenothreshold=linenothreshold)]
+
+highlightlang_directive.content = 0
+highlightlang_directive.arguments = (1, 0, 0)
+highlightlang_directive.options = {'linenothreshold': directives.unchanged}
+directives.register_directive('highlight', highlightlang_directive)
+directives.register_directive('highlightlang', highlightlang_directive) # old name
+
+
+# ------ code-block directive -------------------------------------------------------
+
+def codeblock_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ code = u'\n'.join(content)
+ literal = nodes.literal_block(code, code)
+ literal['language'] = arguments[0]
+ literal['linenos'] = 'linenos' in options
+ return [literal]
+
+codeblock_directive.content = 1
+codeblock_directive.arguments = (1, 0, 0)
+codeblock_directive.options = {'linenos': directives.flag}
+directives.register_directive('code-block', codeblock_directive)
+directives.register_directive('sourcecode', codeblock_directive)
+
+
+# ------ literalinclude directive ---------------------------------------------------
+
+def literalinclude_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Like .. include:: :literal:, but only warns if the include file is not found."""
+ if not state.document.settings.file_insertion_enabled:
+ return [state.document.reporter.warning('File insertion disabled', line=lineno)]
+ env = state.document.settings.env
+ rel_fn = arguments[0]
+ source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
+ lineno - state_machine.input_offset - 1)))
+ fn = path.normpath(path.join(source_dir, rel_fn))
+
+ try:
+ f = open(fn)
+ text = f.read()
+ f.close()
+ except (IOError, OSError):
+ retnode = state.document.reporter.warning(
+ 'Include file %r not found or reading it failed' % arguments[0], line=lineno)
+ else:
+ retnode = nodes.literal_block(text, text, source=fn)
+ retnode.line = 1
+ if options.get('language', ''):
+ retnode['language'] = options['language']
+ if 'linenos' in options:
+ retnode['linenos'] = True
+ state.document.settings.env.note_dependency(rel_fn)
+ return [retnode]
+
+literalinclude_directive.options = {'linenos': directives.flag,
+ 'language': directives.unchanged}
+literalinclude_directive.content = 0
+literalinclude_directive.arguments = (1, 0, 0)
+directives.register_directive('literalinclude', literalinclude_directive)
Added: doctools/trunk/sphinx/directives/desc.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/directives/desc.py Sun May 4 19:22:31 2008
@@ -0,0 +1,434 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives.desc
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: 2007-2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+import re
+import string
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+
+
+ws_re = re.compile(r'\s+')
+
+# ------ information units ---------------------------------------------------------
+
+def desc_index_text(desctype, currmodule, name):
+ if desctype == 'function':
+ if not currmodule:
+ return '%s() (built-in function)' % name
+ return '%s() (in module %s)' % (name, currmodule)
+ elif desctype == 'data':
+ if not currmodule:
+ return '%s (built-in variable)' % name
+ return '%s (in module %s)' % (name, currmodule)
+ elif desctype == 'class':
+ return '%s (class in %s)' % (name, currmodule)
+ elif desctype == 'exception':
+ return name
+ elif desctype == 'method':
+ try:
+ clsname, methname = name.rsplit('.', 1)
+ except ValueError:
+ if currmodule:
+ return '%s() (in module %s)' % (name, currmodule)
+ else:
+ return '%s()' % name
+ if currmodule:
+ return '%s() (%s.%s method)' % (methname, currmodule, clsname)
+ else:
+ return '%s() (%s method)' % (methname, clsname)
+ elif desctype == 'attribute':
+ try:
+ clsname, attrname = name.rsplit('.', 1)
+ except ValueError:
+ if currmodule:
+ return '%s (in module %s)' % (name, currmodule)
+ else:
+ return name
+ if currmodule:
+ return '%s (%s.%s attribute)' % (attrname, currmodule, clsname)
+ else:
+ return '%s (%s attribute)' % (attrname, clsname)
+ elif desctype == 'opcode':
+ return '%s (opcode)' % name
+ elif desctype == 'cfunction':
+ return '%s (C function)' % name
+ elif desctype == 'cmember':
+ return '%s (C member)' % name
+ elif desctype == 'cmacro':
+ return '%s (C macro)' % name
+ elif desctype == 'ctype':
+ return '%s (C type)' % name
+ elif desctype == 'cvar':
+ return '%s (C variable)' % name
+ else:
+ raise ValueError("unhandled descenv: %s" % desctype)
+
+
+# ------ functions to parse a Python or C signature and create desc_* nodes.
+
+py_sig_re = re.compile(r'''^([\w.]*\.)? # class names
+ (\w+) \s* # thing name
+ (?: \((.*)\) )? $ # optionally arguments
+ ''', re.VERBOSE)
+
+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 (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 = m.groups()
+
+ add_module = True
+ if env.currclass:
+ if classname and classname.startswith(env.currclass):
+ fullname = classname + name
+ # class name is given again in the signature
+ classname = classname[len(env.currclass):].lstrip('.')
+ add_module = False
+ elif classname:
+ # class name is given in the signature, but different
+ fullname = env.currclass + '.' + classname + name
+ else:
+ # class name is not given in the signature
+ fullname = env.currclass + '.' + name
+ add_module = False
+ else:
+ fullname = classname and classname + name or name
+
+ if classname:
+ signode += addnodes.desc_classname(classname, classname)
+ # exceptions are a special case, since they are documented in the
+ # 'exceptions' module.
+ elif add_module and env.config.add_module_names and \
+ env.currmodule and env.currmodule != 'exceptions':
+ nodetext = env.currmodule + '.'
+ signode += addnodes.desc_classname(nodetext, nodetext)
+
+ signode += addnodes.desc_name(name, name)
+ if not arglist:
+ if desctype in ('function', 'method'):
+ # for callables, add an empty parameter list
+ signode += addnodes.desc_parameterlist()
+ 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
+ return fullname, classname
+
+
+c_sig_re = re.compile(
+ r'''^([^(]*?) # return type
+ ([\w:]+) \s* # thing name (colon allowed for C++ class names)
+ (?: \((.*)\) )? $ # optionally arguments
+ ''', re.VERBOSE)
+c_funcptr_sig_re = re.compile(
+ r'''^([^(]+?) # return type
+ (\( [^()]+ \)) \s* # name in parentheses
+ \( (.*) \) $ # arguments
+ ''', re.VERBOSE)
+c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
+
+# RE to split at word boundaries
+wsplit_re = re.compile(r'(\W+)')
+
+# These C types aren't described in the reference, so don't try to create
+# a cross-reference to them
+stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
+
+def parse_c_type(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.letters+'_' and part not in stopwords:
+ pnode = addnodes.pending_xref(
+ '', reftype='ctype', reftarget=part, modname=None, classname=None)
+ pnode += tnode
+ node += pnode
+ else:
+ node += tnode
+
+def parse_c_signature(signode, sig, desctype):
+ """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 = m.groups()
+
+ signode += addnodes.desc_type("", "")
+ parse_c_type(signode[-1], rettype)
+ 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 desctype == 'cfunction':
+ # for functions, add an empty parameter list
+ signode += addnodes.desc_parameterlist()
+ 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
+ parse_c_type(param, arg)
+ else:
+ parse_c_type(param, ctype)
+ param += nodes.emphasis(' '+argname, ' '+argname)
+ paramlist += param
+ signode += paramlist
+ return name
+
+
+opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)\s*\((.*)\)')
+
+def parse_opcode_signature(signode, sig):
+ """Transform an opcode signature into RST nodes."""
+ m = opcode_sig_re.match(sig)
+ if m is None:
+ raise ValueError
+ opname, arglist = m.groups()
+ signode += addnodes.desc_name(opname, opname)
+ paramlist = addnodes.desc_parameterlist()
+ signode += paramlist
+ paramlist += addnodes.desc_parameter(arglist, arglist)
+ return opname.strip()
+
+
+option_desc_re = re.compile(
+ r'(/|-|--)([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
+
+def parse_option_desc(signode, sig):
+ """Transform an option description into RST nodes."""
+ count = 0
+ firstname = ''
+ for m in option_desc_re.finditer(sig):
+ prefix, optname, args = m.groups()
+ if count:
+ signode += addnodes.desc_classname(', ', ', ')
+ signode += addnodes.desc_name(prefix+optname, prefix+optname)
+ signode += addnodes.desc_classname(args, args)
+ if not count:
+ firstname = optname
+ count += 1
+ if not firstname:
+ raise ValueError
+ return firstname
+
+
+def desc_directive(desctype, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ env = state.document.settings.env
+ node = addnodes.desc()
+ node['desctype'] = desctype
+
+ noindex = ('noindex' in options)
+ node['noindex'] = noindex
+ # remove backslashes to support (dummy) escapes; helps Vim's highlighting
+ signatures = map(lambda s: s.strip().replace('\\', ''), 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
+ sig = sig.strip()
+ signode = addnodes.desc_signature(sig, '')
+ signode['first'] = False
+ node.append(signode)
+ try:
+ if desctype in ('function', 'data', 'class', 'exception',
+ 'method', 'attribute'):
+ 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':
+ name = parse_opcode_signature(signode, sig)
+ elif desctype == 'cmdoption':
+ optname = parse_option_desc(signode, sig)
+ if not noindex:
+ targetname = 'cmdoption-' + optname
+ signode['ids'].append(targetname)
+ state.document.note_explicit_target(signode)
+ env.note_index_entry('pair', 'command line option; %s' % sig,
+ targetname, targetname)
+ env.note_reftarget('option', optname, targetname)
+ continue
+ elif desctype == 'describe':
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ continue
+ else:
+ # another registered generic x-ref directive
+ rolename, indextemplate, parse_node = additional_xref_types[desctype]
+ if parse_node:
+ fullname = parse_node(env, sig, signode)
+ else:
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ # normalize whitespace like xfileref_role does
+ fullname = ws_re.sub('', sig)
+ if not noindex:
+ targetname = '%s-%s' % (rolename, fullname)
+ signode['ids'].append(targetname)
+ state.document.note_explicit_target(signode)
+ if indextemplate:
+ indexentry = indextemplate % (fullname,)
+ indextype = 'single'
+ colon = indexentry.find(':')
+ if colon != -1:
+ indextype = indexentry[:colon].strip()
+ indexentry = indexentry[colon+1:].strip()
+ env.note_index_entry(indextype, indexentry,
+ targetname, targetname)
+ env.note_reftarget(rolename, fullname, targetname)
+ # don't use object indexing below
+ continue
+ except ValueError, err:
+ # signature parsing failed
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ continue # we don't want an index entry here
+ # only add target and index entry if this is the first description of the
+ # function name in this desc block
+ if not noindex and name not in names:
+ fullname = (env.currmodule and env.currmodule + '.' or '') + name
+ # note target
+ if fullname not in state.document.ids:
+ signode['names'].append(fullname)
+ signode['ids'].append(fullname)
+ signode['first'] = (not names)
+ state.document.note_explicit_target(signode)
+ env.note_descref(fullname, desctype, lineno)
+ names.append(name)
+
+ env.note_index_entry('single',
+ desc_index_text(desctype, env.currmodule, name),
+ fullname, fullname)
+
+ subnode = addnodes.desc_content()
+ # needed for automatic qualification of members
+ clsname_set = False
+ if desctype in ('class', 'exception') 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 clsname_set:
+ env.currclass = None
+ env.currdesc = None
+ node.append(subnode)
+ return [node]
+
+desc_directive.content = 1
+desc_directive.arguments = (1, 0, 1)
+desc_directive.options = {'noindex': directives.flag}
+
+desctypes = [
+ # the Python ones
+ 'function',
+ 'data',
+ 'class',
+ 'method',
+ 'attribute',
+ 'exception',
+ # the C ones
+ 'cfunction',
+ 'cmember',
+ 'cmacro',
+ 'ctype',
+ 'cvar',
+ # the odd one
+ 'opcode',
+ # for command line options
+ 'cmdoption',
+ # the generic one
+ 'describe',
+ 'envvar',
+]
+
+for _name in desctypes:
+ directives.register_directive(_name, desc_directive)
+
+# Generic cross-reference types; they can be registered in the application;
+# the directives are either desc_directive or target_directive
+additional_xref_types = {
+ # directive name: (role name, index text, function to parse the desc node)
+ 'envvar': ('envvar', 'environment variable; %s', None),
+}
+
+
+# ------ target --------------------------------------------------------------------
+
+def target_directive(targettype, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Generic target for user-defined cross-reference types."""
+ env = state.document.settings.env
+ rolename, indextemplate, _ = additional_xref_types[targettype]
+ # normalize whitespace in fullname like xfileref_role does
+ fullname = ws_re.sub('', arguments[0].strip())
+ targetname = '%s-%s' % (rolename, fullname)
+ node = nodes.target('', '', ids=[targetname])
+ state.document.note_explicit_target(node)
+ if indextemplate:
+ indexentry = indextemplate % (fullname,)
+ indextype = 'single'
+ colon = indexentry.find(':')
+ if colon != -1:
+ indextype = indexentry[:colon].strip()
+ indexentry = indexentry[colon+1:].strip()
+ env.note_index_entry(indextype, indexentry, targetname, targetname)
+ env.note_reftarget(rolename, fullname, targetname)
+ return [node]
+
+target_directive.content = 0
+target_directive.arguments = (1, 0, 1)
Added: doctools/trunk/sphinx/directives/other.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/directives/other.py Sun May 4 19:22:31 2008
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives.other
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: 2007-2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+import re
+import posixpath
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+from sphinx.util import patfilter
+from sphinx.roles import caption_ref_re
+from sphinx.util.compat import make_admonition
+
+
+# ------ the TOC tree ---------------------------------------------------------------
+
+def toctree_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ env = state.document.settings.env
+ suffix = env.config.source_suffix
+ dirname = posixpath.dirname(env.docname)
+ glob = 'glob' in options
+
+ ret = []
+ subnode = addnodes.toctree()
+ includefiles = []
+ includetitles = {}
+ all_docnames = env.found_docs.copy()
+ # don't add the currently visited file in catch-all patterns
+ all_docnames.remove(env.docname)
+ for entry in content:
+ if not entry:
+ continue
+ if not glob:
+ # look for explicit titles and documents ("Some Title <document>").
+ m = caption_ref_re.match(entry)
+ if m:
+ docname = m.group(2)
+ includetitles[docname] = m.group(1)
+ else:
+ docname = entry
+ # remove suffixes (backwards compatibility)
+ if docname.endswith(suffix):
+ docname = docname[:-len(suffix)]
+ # absolutize filenames
+ docname = posixpath.normpath(posixpath.join(dirname, docname))
+ if docname not in env.found_docs:
+ ret.append(state.document.reporter.warning(
+ 'toctree references unknown document %r' % docname, line=lineno))
+ else:
+ includefiles.append(docname)
+ else:
+ patname = posixpath.normpath(posixpath.join(dirname, entry))
+ docnames = sorted(patfilter(all_docnames, patname))
+ for docname in docnames:
+ all_docnames.remove(docname) # don't include it again
+ includefiles.append(docname)
+ if not docnames:
+ ret.append(state.document.reporter.warning(
+ 'toctree glob pattern %r didn\'t match any documents' % entry,
+ line=lineno))
+ subnode['includefiles'] = includefiles
+ subnode['includetitles'] = includetitles
+ subnode['maxdepth'] = options.get('maxdepth', -1)
+ ret.append(subnode)
+ return ret
+
+toctree_directive.content = 1
+toctree_directive.options = {'maxdepth': int, 'glob': directives.flag}
+directives.register_directive('toctree', toctree_directive)
+
+
+# ------ section metadata ----------------------------------------------------------
+
+def module_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ env = state.document.settings.env
+ modname = arguments[0].strip()
+ env.currmodule = modname
+ env.note_module(modname, options.get('synopsis', ''),
+ options.get('platform', ''),
+ 'deprecated' in options)
+ modulenode = addnodes.module()
+ modulenode['modname'] = modname
+ modulenode['synopsis'] = options.get('synopsis', '')
+ targetnode = nodes.target('', '', ids=['module-' + modname])
+ state.document.note_explicit_target(targetnode)
+ ret = [modulenode, targetnode]
+ if 'platform' in options:
+ modulenode['platform'] = options['platform']
+ node = nodes.paragraph()
+ node += nodes.emphasis('Platforms: ', 'Platforms: ')
+ node += nodes.Text(options['platform'], options['platform'])
+ ret.append(node)
+ # the synopsis isn't printed; in fact, it is only used in the modindex currently
+ env.note_index_entry('single', '%s (module)' % modname, 'module-' + modname,
+ modname)
+ return ret
+
+module_directive.arguments = (1, 0, 0)
+module_directive.options = {'platform': lambda x: x,
+ 'synopsis': lambda x: x,
+ 'deprecated': directives.flag}
+directives.register_directive('module', module_directive)
+
+
+def currentmodule_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ # This directive is just to tell people that we're documenting
+ # stuff in module foo, but links to module foo won't lead here.
+ env = state.document.settings.env
+ modname = arguments[0].strip()
+ env.currmodule = modname
+ return []
+
+currentmodule_directive.arguments = (1, 0, 0)
+directives.register_directive('currentmodule', currentmodule_directive)
+
+
+def author_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ # Show authors only if the show_authors option is on
+ env = state.document.settings.env
+ if not env.config.show_authors:
+ return []
+ para = nodes.paragraph()
+ emph = nodes.emphasis()
+ para += emph
+ if name == 'sectionauthor':
+ text = 'Section author: '
+ elif name == 'moduleauthor':
+ text = 'Module author: '
+ else:
+ text = 'Author: '
+ emph += nodes.Text(text, text)
+ inodes, messages = state.inline_text(arguments[0], lineno)
+ emph.extend(inodes)
+ return [para] + messages
+
+author_directive.arguments = (1, 0, 1)
+directives.register_directive('sectionauthor', author_directive)
+directives.register_directive('moduleauthor', author_directive)
+
+
+# ------ index markup --------------------------------------------------------------
+
+entrytypes = [
+ 'single', 'pair', 'triple', 'module', 'keyword', 'operator',
+ 'object', 'exception', 'statement', 'builtin',
+]
+
+def index_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ arguments = arguments[0].split('\n')
+ env = state.document.settings.env
+ targetid = 'index-%s' % env.index_num
+ env.index_num += 1
+ targetnode = nodes.target('', '', ids=[targetid])
+ state.document.note_explicit_target(targetnode)
+ indexnode = addnodes.index()
+ indexnode['entries'] = ne = []
+ for entry in arguments:
+ entry = entry.strip()
+ for type in entrytypes:
+ if entry.startswith(type+':'):
+ value = entry[len(type)+1:].strip()
+ env.note_index_entry(type, value, targetid, value)
+ ne.append((type, value, targetid, value))
+ break
+ # shorthand notation for single entries
+ else:
+ for value in entry.split(','):
+ env.note_index_entry('single', value.strip(), targetid, value.strip())
+ ne.append(('single', value.strip(), targetid, value.strip()))
+ return [indexnode, targetnode]
+
+index_directive.arguments = (1, 0, 1)
+directives.register_directive('index', index_directive)
+
+# ------ versionadded/versionchanged -----------------------------------------------
+
+def version_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ node = addnodes.versionmodified()
+ node['type'] = name
+ node['version'] = arguments[0]
+ if len(arguments) == 2:
+ inodes, messages = state.inline_text(arguments[1], lineno+1)
+ node.extend(inodes)
+ if content:
+ state.nested_parse(content, content_offset, node)
+ ret = [node] + messages
+ else:
+ ret = [node]
+ env = state.document.settings.env
+ env.note_versionchange(node['type'], node['version'], node, lineno)
+ return ret
+
+version_directive.arguments = (1, 1, 1)
+version_directive.content = 1
+
+directives.register_directive('deprecated', version_directive)
+directives.register_directive('versionadded', version_directive)
+directives.register_directive('versionchanged', version_directive)
+
+
+# ------ see also ------------------------------------------------------------------
+
+def seealso_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ rv = make_admonition(
+ addnodes.seealso, name, ['See also'], options, content,
+ lineno, content_offset, block_text, state, state_machine)
+ return rv
+
+seealso_directive.content = 1
+seealso_directive.arguments = (0, 0, 0)
+directives.register_directive('seealso', seealso_directive)
+
+
+# ------ production list (for the reference) ---------------------------------------
+
+token_re = re.compile('`([a-z_]+)`')
+
+def token_xrefs(text, env):
+ retnodes = []
+ pos = 0
+ for m in token_re.finditer(text):
+ if m.start() > pos:
+ txt = text[pos:m.start()]
+ retnodes.append(nodes.Text(txt, txt))
+ refnode = addnodes.pending_xref(m.group(1))
+ refnode['reftype'] = 'token'
+ refnode['reftarget'] = m.group(1)
+ refnode['modname'] = env.currmodule
+ refnode['classname'] = env.currclass
+ refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
+ retnodes.append(refnode)
+ pos = m.end()
+ if pos < len(text):
+ retnodes.append(nodes.Text(text[pos:], text[pos:]))
+ return retnodes
+
+def productionlist_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ env = state.document.settings.env
+ node = addnodes.productionlist()
+ messages = []
+ i = 0
+
+ for rule in arguments[0].split('\n'):
+ if i == 0 and ':' not in rule:
+ # production group
+ continue
+ i += 1
+ try:
+ name, tokens = rule.split(':', 1)
+ except ValueError:
+ break
+ subnode = addnodes.production()
+ subnode['tokenname'] = name.strip()
+ if subnode['tokenname']:
+ idname = 'grammar-token-%s' % subnode['tokenname']
+ if idname not in state.document.ids:
+ subnode['ids'].append(idname)
+ state.document.note_implicit_target(subnode, subnode)
+ env.note_reftarget('token', subnode['tokenname'], idname)
+ subnode.extend(token_xrefs(tokens, env))
+ node.append(subnode)
+ return [node] + messages
+
+productionlist_directive.content = 0
+productionlist_directive.arguments = (1, 0, 1)
+directives.register_directive('productionlist', productionlist_directive)
+
+
+# ------ glossary directive ---------------------------------------------------------
+
+def glossary_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Glossary with cross-reference targets for :dfn: roles."""
+ env = state.document.settings.env
+ node = addnodes.glossary()
+ state.nested_parse(content, content_offset, node)
+
+ # the content should be definition lists
+ dls = [child for child in node if isinstance(child, nodes.definition_list)]
+ # now, extract definition terms to enable cross-reference creation
+ for dl in dls:
+ dl['classes'].append('glossary')
+ for li in dl.children:
+ if not li.children or not isinstance(li[0], nodes.term):
+ continue
+ termtext = li.children[0].astext()
+ new_id = 'term-' + nodes.make_id(termtext)
+ if new_id in env.gloss_entries:
+ new_id = 'term-' + str(len(env.gloss_entries))
+ env.gloss_entries.add(new_id)
+ li[0]['names'].append(new_id)
+ li[0]['ids'].append(new_id)
+ state.document.settings.env.note_reftarget('term', termtext.lower(),
+ new_id)
+ return [node]
+
+glossary_directive.content = 1
+glossary_directive.arguments = (0, 0, 0)
+directives.register_directive('glossary', glossary_directive)
+
+
+# ------ miscellaneous markup -------------------------------------------------------
+
+def centered_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ if not arguments:
+ return []
+ subnode = addnodes.centered()
+ inodes, messages = state.inline_text(arguments[0], lineno)
+ subnode.extend(inodes)
+ return [subnode] + messages
+
+centered_directive.arguments = (1, 0, 1)
+directives.register_directive('centered', centered_directive)
+
+
+def acks_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ node = addnodes.acks()
+ state.nested_parse(content, content_offset, node)
+ if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list):
+ return [state.document.reporter.warning('.. acks content is not a list',
+ line=lineno)]
+ return [node]
+
+acks_directive.content = 1
+acks_directive.arguments = (0, 0, 0)
+directives.register_directive('acks', acks_directive)
+
+
+def tabularcolumns_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ # support giving explicit tabulary column definition to latex
+ node = addnodes.tabular_col_spec()
+ node['spec'] = arguments[0]
+ return [node]
+
+tabularcolumns_directive.content = 0
+tabularcolumns_directive.arguments = (1, 0, 1)
+directives.register_directive('tabularcolumns', tabularcolumns_directive)
More information about the Python-checkins
mailing list