diff options
| author | Georg Brandl <georg@python.org> | 2009-09-04 00:17:41 +0200 |
|---|---|---|
| committer | Georg Brandl <georg@python.org> | 2009-09-04 00:17:41 +0200 |
| commit | 2524b3f01e98bb2b787fdfc44810d9b6441311c6 (patch) | |
| tree | ad5f103bf19d47a95911967612f6c30add7e31b4 /sphinx | |
| parent | df68eadcfd963e1e9e040f2341aa9c54858bd693 (diff) | |
| parent | c816d7defda99496824b8eabf66bc909e4b50f49 (diff) | |
| download | sphinx-2524b3f01e98bb2b787fdfc44810d9b6441311c6.tar.gz | |
merge with trunk
Diffstat (limited to 'sphinx')
50 files changed, 2896 insertions, 1130 deletions
diff --git a/sphinx/__init__.py b/sphinx/__init__.py index e6fb54b4..e3feebae 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,7 +12,7 @@ import sys from os import path -__version__ = '1.0' +__version__ = '1.0pre' __released__ = '1.0 (hg)' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) diff --git a/sphinx/application.py b/sphinx/application.py index 0c26b131..1296e575 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -14,18 +14,21 @@ import sys import types import posixpath +from os import path from cStringIO import StringIO from docutils import nodes from docutils.parsers.rst import directives, roles import sphinx -from sphinx.roles import xfileref_role, innernodetypes +from sphinx import package_dir, locale +from sphinx.roles import XRefRole from sphinx.config import Config from sphinx.errors import SphinxError, SphinxWarning, ExtensionError +from sphinx.domains import all_domains from sphinx.builders import BUILTIN_BUILDERS from sphinx.directives import GenericDesc, Target, additional_xref_types -from sphinx.environment import SphinxStandaloneReader +from sphinx.environment import BuildEnvironment, SphinxStandaloneReader from sphinx.util import pycompat # imported for side-effects from sphinx.util.tags import Tags from sphinx.util.compat import Directive, directive_dwim @@ -49,6 +52,7 @@ events = { } CONFIG_FILENAME = 'conf.py' +ENV_PICKLE_FILENAME = 'environment.pickle' class Sphinx(object): @@ -61,6 +65,7 @@ class Sphinx(object): self._listeners = {} self.builderclasses = BUILTIN_BUILDERS.copy() self.builder = None + self.env = None self.srcdir = srcdir self.confdir = confdir @@ -103,8 +108,62 @@ class Sphinx(object): # now that we know all config values, collect them from conf.py self.config.init_values() + # set up translation infrastructure + self._init_i18n() + # set up the build environment + self._init_env(freshenv) + # set up the builder + self._init_builder(buildername) + + def _init_i18n(self): + """ + Load translated strings from the configured localedirs if + enabled in the configuration. + """ + if self.config.language is not None: + self.info(bold('loading translations [%s]... ' % + self.config.language), nonl=True) + locale_dirs = [None, path.join(package_dir, 'locale')] + \ + [path.join(self.srcdir, x) for x in self.config.locale_dirs] + else: + locale_dirs = [] + self.translator, has_translation = locale.init(locale_dirs, + self.config.language) + if self.config.language is not None: + if has_translation: + self.info('done') + else: + self.info('locale not available') + + def _init_env(self, freshenv): + if freshenv: + self.env = BuildEnvironment(self.srcdir, self.doctreedir, + self.config) + self.env.find_files(self.config) + for domain in all_domains.keys(): + self.env.domains[domain] = all_domains[domain](self.env) + else: + try: + self.info(bold('loading pickled environment... '), nonl=True) + self.env = BuildEnvironment.frompickle(self.config, + path.join(self.doctreedir, ENV_PICKLE_FILENAME)) + self.env.domains = {} + for domain in all_domains.keys(): + # this can raise if the data version doesn't fit + self.env.domains[domain] = all_domains[domain](self.env) + self.info('done') + except Exception, err: + if type(err) is IOError and err.errno == 2: + self.info('not yet created') + else: + self.info('failed: %s' % err) + return self._init_env(freshenv=True) + + self.env.set_warnfunc(self.warn) + + def _init_builder(self, buildername): if buildername is None: - print >>status, 'No builder selected, using default: html' + print >>self._status, 'No builder selected, using default: html' buildername = 'html' if buildername not in self.builderclasses: raise SphinxError('Builder name %s not registered' % buildername) @@ -115,9 +174,7 @@ class Sphinx(object): mod, cls = builderclass builderclass = getattr( __import__('sphinx.builders.' + mod, None, None, [cls]), cls) - self.builder = builderclass(self, freshenv=freshenv) - self.builder.tags = self.tags - self.builder.tags.add(self.builder.format) + self.builder = builderclass(self) self.emit('builder-inited') def build(self, all_files, filenames): @@ -277,17 +334,21 @@ class Sphinx(object): if depart: setattr(translator, 'depart_'+node.__name__, depart) - def add_directive(self, name, obj, content=None, arguments=None, **options): + def _directive_helper(self, obj, content=None, arguments=None, **options): if isinstance(obj, clstypes) and issubclass(obj, Directive): if content or arguments or options: raise ExtensionError('when adding directive classes, no ' 'additional arguments may be given') - directives.register_directive(name, directive_dwim(obj)) + return directive_dwim(obj) else: obj.content = content obj.arguments = arguments obj.options = options - directives.register_directive(name, obj) + return obj + + def add_directive(self, name, obj, content=None, arguments=None, **options): + directives.register_directive( + name, self._directive_helper(obj, content, arguments, **options)) def add_role(self, name, role): roles.register_local_role(name, role) @@ -298,23 +359,41 @@ class Sphinx(object): role = roles.GenericRole(name, nodeclass) roles.register_local_role(name, role) + def add_domain(self, domain): + # XXX needs to be documented + if domain.name in all_domains: + raise ExtensionError('domain %s already registered' % domain.name) + all_domains[domain.name] = domain + + def add_directive_to_domain(self, domain, name, obj): + # XXX needs to be documented + if domain not in all_domains: + raise ExtensionError('domain %s not yet registered' % domain) + all_domains[domain].directives[name] = self._directive_helper(obj) + + def add_role_to_domain(self, domain, name, role): + # XXX needs to be documented + if domain not in all_domains: + raise ExtensionError('domain %s not yet registered' % domain) + all_domains[domain].roles[name] = role + def add_description_unit(self, directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None): additional_xref_types[directivename] = (rolename, indextemplate, parse_node) directives.register_directive(directivename, directive_dwim(GenericDesc)) - roles.register_local_role(rolename, xfileref_role) - if ref_nodeclass is not None: - innernodetypes[rolename] = 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)) - roles.register_local_role(rolename, xfileref_role) - if ref_nodeclass is not None: - innernodetypes[rolename] = ref_nodeclass + # XXX support more options + role_func = XRefRole(innernodeclass=ref_nodeclass) + roles.register_local_role(rolename, role_func) def add_transform(self, transform): SphinxStandaloneReader.transforms.append(transform) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index a8fc8871..08628c7b 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -15,9 +15,7 @@ from os import path from docutils import nodes -from sphinx import package_dir, locale from sphinx.util import SEP, relative_uri -from sphinx.environment import BuildEnvironment from sphinx.util.console import bold, purple, darkgreen, term_width_line # side effect: registers roles and directives @@ -25,9 +23,6 @@ from sphinx import roles from sphinx import directives -ENV_PICKLE_FILENAME = 'environment.pickle' - - class Builder(object): """ Builds target formats from the reST sources. @@ -38,7 +33,8 @@ class Builder(object): # builder's output format, or '' if no document output is produced format = '' - def __init__(self, app, env=None, freshenv=False): + def __init__(self, app): + self.env = app.env self.srcdir = app.srcdir self.confdir = app.confdir self.outdir = app.outdir @@ -50,21 +46,15 @@ class Builder(object): self.warn = app.warn self.info = app.info self.config = app.config - - self.load_i18n() + self.tags = app.tags + self.tags.add(self.format) # images that need to be copied over (source -> dest) self.images = {} - # if None, this is set in load_env() - self.env = env - self.freshenv = freshenv - self.init() - self.load_env() # helper methods - def init(self): """ Load necessary templates and perform initialization. The default @@ -167,62 +157,6 @@ class Builder(object): # build methods - def load_i18n(self): - """ - Load translated strings from the configured localedirs if - enabled in the configuration. - """ - self.translator = None - if self.config.language is not None: - self.info(bold('loading translations [%s]... ' % - self.config.language), nonl=True) - # the None entry is the system's default locale path - locale_dirs = [None, path.join(package_dir, 'locale')] + \ - [path.join(self.srcdir, x) for x in self.config.locale_dirs] - for dir_ in locale_dirs: - try: - trans = gettext.translation('sphinx', localedir=dir_, - languages=[self.config.language]) - if self.translator is None: - self.translator = trans - else: - self.translator._catalog.update(trans.catalog) - except Exception: - # Language couldn't be found in the specified path - pass - if self.translator is not None: - self.info('done') - else: - self.info('locale not available') - if self.translator is None: - self.translator = gettext.NullTranslations() - self.translator.install(unicode=True) - locale.init() # translate common labels - - def load_env(self): - """Set up the build environment.""" - if self.env: - return - if not self.freshenv: - try: - self.info(bold('loading pickled environment... '), nonl=True) - self.env = BuildEnvironment.frompickle(self.config, - path.join(self.doctreedir, ENV_PICKLE_FILENAME)) - self.info('done') - except Exception, err: - if type(err) is IOError and err.errno == 2: - self.info('not found') - else: - self.info('failed: %s' % err) - self.env = BuildEnvironment(self.srcdir, self.doctreedir, - self.config) - self.env.find_files(self.config) - else: - self.env = BuildEnvironment(self.srcdir, self.doctreedir, - self.config) - self.env.find_files(self.config) - self.env.set_warnfunc(self.warn) - def build_all(self): """Build all source files.""" self.build(None, summary='all source files', method='all') @@ -302,6 +236,7 @@ class Builder(object): if updated_docnames: # save the environment + from sphinx.application import ENV_PICKLE_FILENAME self.info(bold('pickling environment... '), nonl=True) self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME)) self.info('done') diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index ba117e62..e5a9a453 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -12,6 +12,7 @@ """ import os +import re import cgi import sys from os import path @@ -30,7 +31,7 @@ except ImportError: try: import elementtree.ElementTree as etree except ImportError: - import cElementTree.ElemenTree as etree + import cElementTree as etree try: import gzip @@ -114,11 +115,14 @@ class DevhelpBuilder(StandaloneHTMLBuilder): else: for i, ref in enumerate(refs): etree.SubElement(functions, 'function', - name="%s [%d]" % (title, i), link=ref) + name="[%d] %s" % (i, title), + link=ref) if subitems: + parent_title = re.sub(r'\s*\(.*\)\s*$', '', title) for subitem in subitems: - write_index(subitem[0], subitem[1], []) + write_index("%s %s" % (parent_title, subitem[0]), + subitem[1], []) for (key, group) in index: for title, (refs, subitems) in group: diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 54327fa1..02f62164 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -33,7 +33,8 @@ from sphinx.util import SEP, os_path, relative_uri, ensuredir, \ from sphinx.errors import SphinxError from sphinx.search import js_index from sphinx.theming import Theme -from sphinx.builders import Builder, ENV_PICKLE_FILENAME +from sphinx.builders import Builder +from sphinx.application import ENV_PICKLE_FILENAME from sphinx.highlighting import PygmentsBridge from sphinx.util.console import bold from sphinx.writers.html import HTMLWriter, HTMLTranslator, \ @@ -239,7 +240,9 @@ class StandaloneHTMLBuilder(Builder): rellinks = [] if self.config.html_use_index: rellinks.append(('genindex', _('General Index'), 'I', _('index'))) - if self.config.html_use_modindex and self.env.modules: + # XXX generalization of modindex? + if self.config.html_use_modindex and \ + self.env.domaindata['py']['modules']: rellinks.append(('modindex', _('Global Module Index'), 'M', _('modules'))) @@ -404,12 +407,13 @@ class StandaloneHTMLBuilder(Builder): # the global module index - if self.config.html_use_modindex and self.env.modules: + moduleindex = self.env.domaindata['py']['modules'] + if self.config.html_use_modindex and moduleindex: # the sorted list of all modules, for the global module index modules = sorted(((mn, (self.get_relative_uri('modindex', fn) + '#module-' + mn, sy, pl, dep)) for (mn, (fn, sy, pl, dep)) in - self.env.modules.iteritems()), + moduleindex.iteritems()), key=lambda x: x[0].lower()) # collect all platforms platforms = set() @@ -709,14 +713,15 @@ class StandaloneHTMLBuilder(Builder): self.info(bold('dumping object inventory... '), nonl=True) f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w') try: + # XXX inventory version 2 f.write('# Sphinx inventory version 1\n') f.write('# Project: %s\n' % self.config.project.encode('utf-8')) f.write('# Version: %s\n' % self.config.version) - for modname, info in self.env.modules.iteritems(): - f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0]))) - for refname, (docname, desctype) in self.env.descrefs.iteritems(): - f.write('%s %s %s\n' % (refname, desctype, - self.get_target_uri(docname))) + #for modname, info in self.env.modules.iteritems(): + # f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0]))) + #for refname, (docname, desctype) in self.env.descrefs.iteritems(): + # f.write('%s %s %s\n' % (refname, desctype, + # self.get_target_uri(docname))) finally: f.close() self.info('done') diff --git a/sphinx/config.py b/sphinx/config.py index b2ef29fb..dbe569fb 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -55,6 +55,7 @@ class Config(object): modindex_common_prefix = ([], 'html'), rst_epilog = (None, 'env'), trim_doctest_flags = (True, 'env'), + default_domain = ('py', 'env'), # HTML options html_theme = ('default', 'html'), @@ -112,6 +113,10 @@ class Config(object): latex_docclass = ({}, None), # now deprecated - use latex_elements latex_preamble = ('', None), + + # text options + text_sectionchars = ('*=-~"+`', 'text'), + text_windows_newlines = (False, 'text'), ) def __init__(self, dirname, filename, overrides, tags): diff --git a/sphinx/directives/desc.py b/sphinx/directives/desc.py index db261a87..6deb1f03 100644 --- a/sphinx/directives/desc.py +++ b/sphinx/directives/desc.py @@ -14,6 +14,7 @@ from docutils import nodes from docutils.parsers.rst import directives from sphinx import addnodes +from sphinx.locale import l_ from sphinx.util import ws_re from sphinx.util.compat import Directive, directive_dwim @@ -31,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'\\(?=[^\\])') @@ -83,8 +55,6 @@ class DescDirective(Directive): 'module': directives.unchanged, } - _ = lambda x: x # make gettext extraction in constants possible - doc_fields_with_arg = { 'param': '%param', 'parameter': '%param', @@ -94,23 +64,23 @@ class DescDirective(Directive): 'kwarg': '%param', 'kwparam': '%param', 'type': '%type', - 'raises': _('Raises'), - 'raise': 'Raises', - 'exception': 'Raises', - 'except': 'Raises', - 'var': _('Variable'), - 'ivar': 'Variable', - 'cvar': 'Variable', - 'returns': _('Returns'), - 'return': 'Returns', + 'raises': l_('Raises'), + 'raise': l_('Raises'), + 'exception': l_('Raises'), + 'except': l_('Raises'), + 'var': l_('Variable'), + 'ivar': l_('Variable'), + 'cvar': l_('Variable'), + 'returns': l_('Returns'), + 'return': l_('Returns'), } doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except') doc_fields_without_arg = { - 'returns': 'Returns', - 'return': 'Returns', - 'rtype': _('Return type'), + 'returns': l_('Returns'), + 'return': l_('Returns'), + 'rtype': l_('Return type'), } def handle_doc_fields(self, node): @@ -131,7 +101,7 @@ class DescDirective(Directive): fname, fbody = field try: typ, obj = fname.astext().split(None, 1) - typdesc = _(self.doc_fields_with_arg[typ]) + typdesc = self.doc_fields_with_arg[typ] if _is_only_paragraph(fbody): children = fbody.children[0].children else: @@ -175,7 +145,7 @@ class DescDirective(Directive): except (KeyError, ValueError): fnametext = fname.astext() try: - typ = _(self.doc_fields_without_arg[fnametext]) + typ = self.doc_fields_without_arg[fnametext] except KeyError: # at least capitalize the field name typ = fnametext.capitalize() @@ -234,7 +204,10 @@ class DescDirective(Directive): pass def run(self): - self.desctype = self.name + if ':' in self.name: + self.domain, self.desctype = self.name.split(':', 1) + else: + self.domain, self.desctype = '', self.name self.env = self.state.document.settings.env self.indexnode = addnodes.index(entries=[]) @@ -278,360 +251,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). @@ -681,7 +300,7 @@ class GenericDesc(DescDirective): else: signode.clear() signode += addnodes.desc_name(sig, sig) - # normalize whitespace like xfileref_role does + # normalize whitespace like XRefRole does name = ws_re.sub('', sig) return name @@ -691,7 +310,7 @@ class GenericDesc(DescDirective): signode['ids'].append(targetname) self.state.document.note_explicit_target(signode) if indextemplate: - indexentry = _(indextemplate) % (name,) + indexentry = indextemplate % (name,) indextype = 'single' colon = indexentry.find(':') if colon != -1: @@ -716,7 +335,7 @@ class Target(Directive): def run(self): env = self.state.document.settings.env rolename, indextemplate, foo = additional_xref_types[self.name] - # normalize whitespace in fullname like xfileref_role does + # normalize whitespace in fullname like XRefRole does fullname = ws_re.sub('', self.arguments[0].strip()) targetname = '%s-%s' % (rolename, fullname) node = nodes.target('', '', ids=[targetname]) @@ -735,37 +354,36 @@ class Target(Directive): env.note_reftarget(rolename, fullname, targetname) return ret + +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 = arguments[0] + env.default_domain = env.domains.get(domain_name) + + # Note: the target directive is not registered here, it is used by the # application when registering additional xref types. -_ = lambda x: x - # 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), + 'envvar': ('envvar', l_('environment variable; %s'), None), } -del _ - +directives.register_directive('default-domain', directive_dwim(DefaultDomain)) directives.register_directive('describe', directive_dwim(DescDirective)) - -directives.register_directive('function', directive_dwim(ModulelevelDesc)) -directives.register_directive('data', directive_dwim(ModulelevelDesc)) -directives.register_directive('class', directive_dwim(ClasslikeDesc)) -directives.register_directive('exception', directive_dwim(ClasslikeDesc)) -directives.register_directive('method', directive_dwim(ClassmemberDesc)) -directives.register_directive('classmethod', directive_dwim(ClassmemberDesc)) -directives.register_directive('staticmethod', directive_dwim(ClassmemberDesc)) -directives.register_directive('attribute', directive_dwim(ClassmemberDesc)) - -directives.register_directive('cfunction', directive_dwim(CDesc)) -directives.register_directive('cmember', directive_dwim(CDesc)) -directives.register_directive('cmacro', directive_dwim(CDesc)) -directives.register_directive('ctype', directive_dwim(CDesc)) -directives.register_directive('cvar', directive_dwim(CDesc)) - directives.register_directive('cmdoption', directive_dwim(CmdoptionDesc)) directives.register_directive('envvar', directive_dwim(GenericDesc)) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 50db49ce..225c1816 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -104,75 +104,6 @@ class TocTree(Directive): return ret -class Module(Directive): - """ - Directive to mark description of a new module. - """ - - has_content = False - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = { - 'platform': lambda x: x, - 'synopsis': lambda x: x, - 'noindex': directives.flag, - 'deprecated': directives.flag, - } - - def run(self): - env = self.state.document.settings.env - modname = self.arguments[0].strip() - noindex = 'noindex' in self.options - env.currmodule = modname - env.note_module(modname, self.options.get('synopsis', ''), - self.options.get('platform', ''), - 'deprecated' in self.options) - modulenode = addnodes.module() - modulenode['modname'] = modname - modulenode['synopsis'] = self.options.get('synopsis', '') - targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True) - self.state.document.note_explicit_target(targetnode) - ret = [modulenode, targetnode] - if 'platform' in self.options: - platform = self.options['platform'] - modulenode['platform'] = platform - node = nodes.paragraph() - node += nodes.emphasis('', _('Platforms: ')) - node += nodes.Text(platform, platform) - ret.append(node) - # the synopsis isn't printed; in fact, it is only used in the - # modindex currently - if not noindex: - indextext = _('%s (module)') % modname - inode = addnodes.index(entries=[('single', indextext, - 'module-' + modname, modname)]) - ret.insert(0, inode) - return ret - - -class CurrentModule(Directive): - """ - This directive is just to tell Sphinx that we're documenting - stuff in module foo, but links to module foo won't lead here. - """ - - has_content = False - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = {} - - def run(self): - env = self.state.document.settings.env - modname = self.arguments[0].strip() - if modname == 'None': - env.currmodule = None - else: - env.currmodule = modname - return [] - - class Author(Directive): """ Directive to give the name of the author of the current document @@ -330,7 +261,7 @@ class SeeAlso(Directive): return ret -token_re = re.compile('`([a-z_]+)`') +token_re = re.compile('`([a-z_][a-z0-9_]*)`') def token_xrefs(text, env): retnodes = [] @@ -561,8 +492,6 @@ class Only(Directive): directives.register_directive('toctree', directive_dwim(TocTree)) -directives.register_directive('module', directive_dwim(Module)) -directives.register_directive('currentmodule', directive_dwim(CurrentModule)) directives.register_directive('sectionauthor', directive_dwim(Author)) directives.register_directive('moduleauthor', directive_dwim(Author)) directives.register_directive('program', directive_dwim(Program)) diff --git a/sphinx/domains.py b/sphinx/domains.py new file mode 100644 index 00000000..6e00d540 --- /dev/null +++ b/sphinx/domains.py @@ -0,0 +1,779 @@ +# -*- coding: utf-8 -*- +""" + sphinx.domains + ~~~~~~~~~~~~~~ + + Support for domains, which are groupings of description directives + and roles describing e.g. constructs of one programming language. + + :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re +import string + +from docutils import nodes +from docutils.parsers.rst import directives + +from sphinx import addnodes +from sphinx.roles import XRefRole +from sphinx.directives import DescDirective +from sphinx.util import make_refnode +from sphinx.util.compat import Directive + + +class Domain(object): + """ + A Domain is meant to be a group of "object" description directives for + objects of a similar nature, and corresponding roles to create references to + them. Examples would be Python modules, classes, functions etc., elements + of a templating language, Sphinx roles and directives, etc. + + Each domain has a separate storage for information about existing objects + and how to reference them in `data`, which must be a dictionary. It also + must implement several functions that expose the object information in a + uniform way to parts of Sphinx that allow the user to reference or search + for objects in a domain-agnostic way. + + About `self.data`: since all object and cross-referencing information is + stored on a BuildEnvironment instance, the `domain.data` object is also + stored in the `env.domaindata` dict under the key `domain.name`. Before the + build process starts, every active domain is instantiated and given the + environment object; the `domaindata` dict must then either be nonexistent or + a dictionary whose 'version' key is equal to the domain class' + `data_version` attribute. Otherwise, `IOError` is raised and the pickled + environment is discarded. + """ + + name = '' + directives = {} + roles = {} + label = '' + + # data value for a fresh environment + initial_data = {} + # data version + data_version = 0 + + def __init__(self, env): + self.env = env + if self.name not in env.domaindata: + assert isinstance(self.initial_data, dict) + new_data = self.initial_data.copy() + new_data['version'] = self.data_version + self.data = env.domaindata[self.name] = new_data + else: + self.data = env.domaindata[self.name] + if self.data['version'] != self.data_version: + raise IOError('data of %r domain out of date' % self.label) + self._role_cache = {} + self._directive_cache = {} + + def clear_doc(self, docname): + """ + Remove traces of a document in the domain-specific inventories. + """ + pass + + def role(self, name): + """ + Return a role adapter function that always gives the registered + role its full name ('domain:name') as the first argument. + """ + if name in self._role_cache: + return self._role_cache[name] + if name not in self.roles: + return None + fullname = '%s:%s' % (self.name, name) + def role_adapter(typ, rawtext, text, lineno, inliner, + options={}, content=[]): + return self.roles[name](fullname, rawtext, text, lineno, + inliner, options, content) + self._role_cache[name] = role_adapter + return role_adapter + + def directive(self, name): + """ + Return a directive adapter class that always gives the registered + directive its full name ('domain:name') as ``self.name``. + """ + if name in self._directive_cache: + return self._directive_cache[name] + if name not in self.directives: + return None + fullname = '%s:%s' % (self.name, name) + # XXX what about function-style directives? + BaseDirective = self.directives[name] + class DirectiveAdapter(BaseDirective): + def run(self): + self.name = fullname + return BaseDirective.run(self) + self._directive_cache[name] = DirectiveAdapter + return DirectiveAdapter + + def resolve_xref(self, typ, target, node, contnode): + """ + Resolve the ``pending_xref`` *node* with the given *typ* and *target*. + + This method should return a new node, to replace the xref node, + containing the *contnode* which is the markup content of the + cross-reference. + + If no resolution can be found, None can be returned; the xref node will + then given to the 'missing-reference' event, and if that yields no + resolution, replaced by *contnode*. + + The method can also raise `sphinx.environment.NoUri` to suppress the + 'missing-reference' event being emitted. + """ + pass + + +# 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) + objects = self.env.domaindata['py']['objects'] + if fullname in objects: + self.env.warn( + self.env.docname, + 'duplicate object description of %s, ' % fullname + + 'other instance in ' + + self.env.doc2path(objects[fullname][0]), + self.lineno) + objects[fullname] = (self.env.docname, self.desctype) + + 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 PyModule(Directive): + """ + Directive to mark description of a new module. + """ + + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = { + 'platform': lambda x: x, + 'synopsis': lambda x: x, + 'noindex': directives.flag, + 'deprecated': directives.flag, + } + + def run(self): + env = self.state.document.settings.env + modname = self.arguments[0].strip() + noindex = 'noindex' in self.options + env.currmodule = modname + env.domaindata['py']['modules'][modname] = \ + (env.docname, self.options.get('synopsis', ''), + self.options.get('platform', ''), 'deprecated' in self.options) + modulenode = addnodes.module() + modulenode['modname'] = modname + modulenode['synopsis'] = self.options.get('synopsis', '') + targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True) + self.state.document.note_explicit_target(targetnode) + ret = [modulenode, targetnode] + if 'platform' in self.options: + platform = self.options['platform'] + modulenode['platform'] = platform + node = nodes.paragraph() + node += nodes.emphasis('', _('Platforms: ')) + node += nodes.Text(platform, platform) + ret.append(node) + # the synopsis isn't printed; in fact, it is only used in the + # modindex currently + if not noindex: + indextext = _('%s (module)') % modname + inode = addnodes.index(entries=[('single', indextext, + 'module-' + modname, modname)]) + ret.insert(0, inode) + return ret + + +class PyCurrentModule(Directive): + """ + This directive is just to tell Sphinx that we're documenting + stuff in module foo, but links to module foo won't lead here. + """ + + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + env = self.state.document.settings.env + modname = self.arguments[0].strip() + if modname == 'None': + env.currmodule = None + else: + env.currmodule = modname + return [] + + +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, + 'module': PyModule, + 'currentmodule': PyCurrentModule, + } + roles = { + 'data': PyXRefRole(), + 'exc': PyXRefRole(), + 'func': PyXRefRole(fix_parens=True), + 'class': PyXRefRole(), + 'const': PyXRefRole(), + 'attr': PyXRefRole(), + 'meth': PyXRefRole(fix_parens=True), + 'mod': PyXRefRole(), + 'obj': PyXRefRole(), + } + initial_data = { + 'objects': {}, # fullname -> docname, desctype + 'modules': {}, # modname -> docname, synopsis, platform, deprecated + } + + def clear_doc(self, docname): + for fullname, (fn, _) in self.data['objects'].items(): + if fn == docname: + del self.data['objects'][fullname] + for modname, (fn, _, _, _) in self.data['modules'].items(): + if fn == docname: + del self.data['modules'][modname] + + def find_desc(self, env, modname, classname, name, type, searchorder=0): + """ + Find a Python object description for "name", perhaps using the given + module and/or classname. + """ + # skip parens + if name[-2:] == '()': + name = name[:-2] + + if not name: + return None, None + + objects = self.data['objects'] + + newname = None + if searchorder == 1: + if modname and classname and \ + modname + '.' + classname + '.' + name in objects: + newname = modname + '.' + classname + '.' + name + elif modname and modname + '.' + name in objects: + newname = modname + '.' + name + elif name in objects: + newname = name + else: + if name in objects: + newname = name + elif modname and modname + '.' + name in objects: + newname = modname + '.' + name + elif modname and classname and \ + modname + '.' + classname + '.' + name in objects: + newname = modname + '.' + classname + '.' + name + # special case: builtin exceptions have module "exceptions" set + elif type == 'exc' and '.' not in name and \ + 'exceptions.' + name in objects: + newname = 'exceptions.' + name + # special case: object methods + elif type in ('func', 'meth') and '.' not in name and \ + 'object.' + name in objects: + newname = 'object.' + name + if newname is None: + return None, None + return newname, objects[newname] + + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + if (typ == 'mod' or + typ == 'obj' and target in self.data['modules']): + docname, synopsis, platform, deprecated = \ + self.data['modules'].get(target, ('','','', '')) + if not docname: + return None + elif docname == fromdocname: + # don't link to self + return contnode + else: + title = '%s%s%s' % ((platform and '(%s) ' % platform), + synopsis, + (deprecated and ' (deprecated)' or '')) + return make_refnode(builder, fromdocname, docname, + 'module-' + target, contnode, title) + else: + modname = node['modname'] + clsname = node['classname'] + searchorder = node.hasattr('refspecific') and 1 or 0 + name, desc = self.find_desc(env, modname, clsname, + target, typ, searchorder) + if not desc: + return None + else: + return make_refnode(builder, fromdocname, desc[0], name, + contnode, name) + + + +# 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( + '', refdomain='c', reftype='type', 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) + inv = self.env.domaindata['c']['objects'] + if name in inv: + self.env.warn( + self.env.docname, + 'duplicate C object description of %s, ' % name + + 'other instance in ' + self.env.doc2path(inv[name][0]), + self.lineno) + inv[name] = (self.env.docname, self.desctype) + + 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(), + 'macro': XRefRole(), + 'func' : XRefRole(fix_parens=True), + 'data': XRefRole(), + 'type': XRefRole(), + } + initial_data = { + 'objects': {}, # fullname -> docname, desctype + } + + def clear_doc(self, docname): + for fullname, (fn, _) in self.data['objects'].items(): + if fn == docname: + del self.data['objects'][fullname] + + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + # strip pointer asterisk + target = target.rstrip(' *') + if target not in self.data: + return None + desc = self.data[target] + return make_refnode(builder, fromdocname, desc[0], contnode, target) + + +# this contains all registered domains +all_domains = { + 'py': PythonDomain, + 'c': CDomain, +} diff --git a/sphinx/environment.py b/sphinx/environment.py index d04fcbf9..bd93c91c 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -28,7 +28,7 @@ from docutils.io import FileInput, NullOutput from docutils.core import Publisher from docutils.utils import Reporter, relative_path from docutils.readers import standalone -from docutils.parsers.rst import roles +from docutils.parsers.rst import roles, directives from docutils.parsers.rst.languages import en as english from docutils.parsers.rst.directives.html import MetaBody from docutils.writers import UnfilteredWriter @@ -37,10 +37,13 @@ from docutils.transforms.parts import ContentsFilter from sphinx import addnodes from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \ - docname_join, FilenameUniqDict, url_re -from sphinx.errors import SphinxError + docname_join, FilenameUniqDict, url_re, make_refnode +from sphinx.errors import SphinxError, ExtensionError from sphinx.directives import additional_xref_types +orig_role_function = roles.role +orig_directive_function = directives.directive + default_settings = { 'embed_stylesheet': False, 'cloak_email_addresses': True, @@ -53,7 +56,7 @@ default_settings = { # This is increased every time an environment attribute is added # or changed to properly invalidate pickle files. -ENV_VERSION = 30 +ENV_VERSION = 31 default_substitutions = set([ @@ -204,9 +207,9 @@ class BuildEnvironment: env = pickle.load(picklefile) finally: picklefile.close() - env.config.values = config.values if env.version != ENV_VERSION: raise IOError('env version not current') + env.config.values = config.values return env def topickle(self, filename): @@ -215,6 +218,8 @@ class BuildEnvironment: self.set_warnfunc(None) values = self.config.values del self.config.values + domains = self.domains + del self.domains # first write to a temporary file, so that if dumping fails, # the existing environment won't be overwritten picklefile = open(filename + '.tmp', 'wb') @@ -231,6 +236,7 @@ class BuildEnvironment: picklefile.close() movefile(filename + '.tmp', filename) # reset attributes + self.domains = domains self.config.values = values self.set_warnfunc(warnfunc) @@ -244,6 +250,9 @@ class BuildEnvironment: # the application object; only set while update() runs self.app = None + # all the registered domains, set by the application + self.domains = {} + # the docutils settings for building self.settings = default_settings.copy() self.settings['env'] = self @@ -282,11 +291,10 @@ class BuildEnvironment: self.glob_toctrees = set() # docnames that have :glob: toctrees self.numbered_toctrees = set() # docnames that have :numbered: toctrees + # domain-specific inventories, here to be pickled + self.domaindata = {} # domainname -> domain-specific object + # X-ref target inventory - self.descrefs = {} # fullname -> docname, desctype - self.filemodules = {} # docname -> [modules] - self.modules = {} # modname -> docname, synopsis, - # platform, deprecated self.labels = {} # labelname -> docname, labelid, sectionname self.anonlabels = {} # labelname -> docname, labelid self.progoptions = {} # (program, name) -> docname, labelid @@ -305,6 +313,7 @@ class BuildEnvironment: # These are set while parsing a file self.docname = None # current document name + # XXX remove currmodule and currclass from here self.currmodule = None # current module name self.currclass = None # current class name self.currdesc = None # current descref name @@ -344,7 +353,6 @@ class BuildEnvironment: self.toc_secnumbers.pop(docname, None) self.toc_num_entries.pop(docname, None) self.toctree_includes.pop(docname, None) - self.filemodules.pop(docname, None) self.indexentries.pop(docname, None) self.glob_toctrees.discard(docname) self.numbered_toctrees.discard(docname) @@ -355,12 +363,6 @@ class BuildEnvironment: fnset.discard(docname) if not fnset: del self.files_to_rebuild[subfn] - for fullname, (fn, _) in self.descrefs.items(): - if fn == docname: - del self.descrefs[fullname] - for modname, (fn, _, _, _) in self.modules.items(): - if fn == docname: - del self.modules[modname] for labelname, (fn, _, _) in self.labels.items(): if fn == docname: del self.labels[labelname] @@ -374,6 +376,10 @@ class BuildEnvironment: new = [change for change in changes if change[1] != docname] changes[:] = new + # XXX why does this not work inside the if? + for domain in self.domains.values(): + domain.clear_doc(docname) + def doc2path(self, docname, base=True, suffix=None): """ Return the filename for the document name. @@ -553,6 +559,7 @@ class BuildEnvironment: # remove all inventory entries for that file if app: app.emit('env-purge-doc', self, docname) + self.clear_doc(docname) if src_path is None: @@ -591,6 +598,44 @@ class BuildEnvironment: else: return data + # defaults to the global default, but can be re-set in a document + self.default_domain = self.domains.get(self.config.default_domain) + + # monkey-patch, so that domain directives take precedence + def directive(directive_name, language_module, document): + directive_name = directive_name.lower() + if ':' in directive_name: + domain_name, directive_name = directive_name.split(':', 1) + if domain_name in self.domains: + domain = self.domains[domain_name] + directive = domain.directive(directive_name) + if directive is not None: + return directive, [] + elif self.default_domain is not None: + directive = self.default_domain.directive(directive_name) + if directive is not None: + return directive, [] + return orig_directive_function(directive_name, language_module, + document) + directives.directive = directive + + def role(role_name, language_module, lineno, reporter): + role_name = role_name.lower() + if ':' in role_name: + domain_name, role_name = role_name.split(':', 1) + if domain_name in self.domains: + domain = self.domains[domain_name] + role = domain.role(role_name) + if role is not None: + return role, [] + elif self.default_domain is not None: + role = self.default_domain.role(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(), @@ -636,6 +681,7 @@ class BuildEnvironment: self.docname = None self.currmodule = None self.currclass = None + self.default_domain = None self.gloss_entries = set() if save_parsed: @@ -945,19 +991,6 @@ class BuildEnvironment: # ------- # these are called from docutils directives and therefore use self.docname # - def note_descref(self, fullname, desctype, line): - if fullname in self.descrefs: - self.warn(self.docname, - 'duplicate canonical description name %s, ' % fullname + - 'other instance in ' + - self.doc2path(self.descrefs[fullname][0]), - line) - self.descrefs[fullname] = (self.docname, desctype) - - def note_module(self, modname, synopsis, platform, deprecated): - self.modules[modname] = (self.docname, synopsis, platform, deprecated) - self.filemodules.setdefault(self.docname, []).append(modname) - def note_progoption(self, optname, labelid): self.progoptions[self.currprogram, optname] = (self.docname, labelid) @@ -973,6 +1006,14 @@ class BuildEnvironment: self.dependencies.setdefault(self.docname, set()).add(filename) # ------- + def get_domain(self, domainname): + """Return the domain instance with the specified name. + Raises an ExtensionError if the domain is not registered.""" + try: + return self.domains[domainname] + except KeyError: + raise ExtensionError('Domain %r is not registered' % domainname) + # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------ def get_doctree(self, docname): @@ -1155,11 +1196,8 @@ class BuildEnvironment: docname, refnode['refuri']) + refnode['anchorname'] return newnode - descroles = frozenset(('data', 'exc', 'func', 'class', 'const', - 'attr', 'obj', 'meth', 'cfunc', 'cmember', - 'cdata', 'ctype', 'cmacro')) - def resolve_references(self, doctree, fromdocname, builder): + # XXX remove this reftarget_roles = set(('token', 'term', 'citation')) # add all custom xref types too reftarget_roles.update(i[0] for i in additional_xref_types.values()) @@ -1172,7 +1210,15 @@ class BuildEnvironment: target = node['reftarget'] try: - if typ == 'ref': + if node.has_key('refdomain') and node['refdomain']: + # let the domain try to resolve the reference + try: + domain = self.domains[node['refdomain']] + except KeyError: + raise NoUri + newnode = domain.resolve_xref(self, fromdocname, builder, + typ, target, node, contnode) + elif typ == 'ref': if node['refcaption']: # reference to anonymous label; the reference uses # the supplied link caption @@ -1237,13 +1283,8 @@ class BuildEnvironment: #self.warn(fromdocname, 'unknown keyword: %s' % target) newnode = contnode else: - newnode = nodes.reference('', '') - if docname == fromdocname: - newnode['refid'] = labelid - else: - newnode['refuri'] = builder.get_relative_uri( - fromdocname, docname) + '#' + labelid - newnode.append(contnode) + newnode = make_refnode(builder, fromdocname, docname, + labelid, contnode) elif typ == 'option': progname = node['refprogram'] docname, labelid = self.progoptions.get((progname, target), @@ -1251,13 +1292,8 @@ class BuildEnvironment: if not docname: newnode = contnode else: - newnode = nodes.reference('', '') - if docname == fromdocname: - newnode['refid'] = labelid - else: - newnode['refuri'] = builder.get_relative_uri( - fromdocname, docname) + '#' + labelid - newnode.append(contnode) + newnode = make_refnode(builder, fromdocname, docname, + labelid, contnode) elif typ in reftarget_roles: docname, labelid = self.reftargets.get((typ, target), ('', '')) @@ -1272,62 +1308,19 @@ class BuildEnvironment: node.line) newnode = contnode else: - newnode = nodes.reference('', '') - if docname == fromdocname: - newnode['refid'] = labelid - else: - newnode['refuri'] = builder.get_relative_uri( - fromdocname, docname, typ) + '#' + labelid - newnode.append(contnode) - elif typ == 'mod' or \ - typ == 'obj' and target in self.modules: - docname, synopsis, platform, deprecated = \ - self.modules.get(target, ('','','', '')) - if not docname: - newnode = builder.app.emit_firstresult( - 'missing-reference', self, node, contnode) - if not newnode: - newnode = contnode - elif docname == fromdocname: - # don't link to self - newnode = contnode - else: - newnode = nodes.reference('', '') - newnode['refuri'] = builder.get_relative_uri( - fromdocname, docname) + '#module-' + target - newnode['reftitle'] = '%s%s%s' % ( - (platform and '(%s) ' % platform), - synopsis, (deprecated and ' (deprecated)' or '')) - newnode.append(contnode) - elif typ in self.descroles: - # "descrefs" - modname = node['modname'] - clsname = node['classname'] - searchorder = node.hasattr('refspecific') and 1 or 0 - name, desc = self.find_desc(modname, clsname, - target, typ, searchorder) - if not desc: - newnode = builder.app.emit_firstresult( - 'missing-reference', self, node, contnode) - if not newnode: - newnode = contnode - else: - newnode = nodes.reference('', '') - if desc[0] == fromdocname: - newnode['refid'] = name - else: - newnode['refuri'] = ( - builder.get_relative_uri(fromdocname, desc[0]) - + '#' + name) - newnode['reftitle'] = name - newnode.append(contnode) + newnode = make_refnode(builder, fromdocname, docname, + labelid, contnode) else: raise RuntimeError('unknown xfileref node encountered: %s' % node) + + # no new node found? try the missing-reference event + if newnode is None: + newnode = builder.app.emit_firstresult( + 'missing-reference', self, node, contnode) except NoUri: newnode = contnode - if newnode: - node.replace_self(newnode) + node.replace_self(newnode or contnode) for node in doctree.traverse(addnodes.only): try: @@ -1558,116 +1551,3 @@ class BuildEnvironment: # the master file is not included anywhere ;) continue self.warn(docname, 'document isn\'t included in any toctree') - - # --------- QUERYING ------------------------------------------------------- - - def find_desc(self, modname, classname, name, type, searchorder=0): - """Find a description node matching "name", perhaps using - the given module and/or classname.""" - # skip parens - if name[-2:] == '()': - name = name[:-2] - - if not name: - return None, None - - # don't add module and class names for C things - if type[0] == 'c' and type not in ('class', 'const'): - # skip trailing star and whitespace - name = name.rstrip(' *') - if name in self.descrefs and self.descrefs[name][1][0] == 'c': - return name, self.descrefs[name] - return None, None - - newname = None - if searchorder == 1: - if modname and classname and \ - modname + '.' + classname + '.' + name in self.descrefs: - newname = modname + '.' + classname + '.' + name - elif modname and modname + '.' + name in self.descrefs: - newname = modname + '.' + name - elif name in self.descrefs: - newname = name - else: - if name in self.descrefs: - newname = name - elif modname and modname + '.' + name in self.descrefs: - newname = modname + '.' + name - elif modname and classname and \ - modname + '.' + classname + '.' + name in self.descrefs: - newname = modname + '.' + classname + '.' + name - # special case: builtin exceptions have module "exceptions" set - elif type == 'exc' and '.' not in name and \ - 'exceptions.' + name in self.descrefs: - newname = 'exceptions.' + name - # special case: object methods - elif type in ('func', 'meth') and '.' not in name and \ - 'object.' + name in self.descrefs: - newname = 'object.' + name - if newname is None: - return None, None - return newname, self.descrefs[newname] - - 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) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index dc641674..09212eed 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -226,7 +226,7 @@ class Autosummary(Directive): ``[(name, signature, summary_string, real_name), ...]``. """ env = self.state.document.settings.env - + prefixes = [''] if env.currmodule: prefixes.insert(0, env.currmodule) @@ -443,8 +443,9 @@ def autolink_role(typ, rawtext, etext, lineno, inliner, Expands to ':obj:`text`' if `text` is an object that can be imported; otherwise expands to '*text*'. """ - r = roles.xfileref_role('obj', rawtext, etext, lineno, inliner, - options, content) + env = inliner.document.settings.env + r = env.get_domain('py').role('obj')( + 'obj', rawtext, etext, lineno, inliner, options, content) pnode = r[0][0] prefixes = [None] diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index f8447e94..568ee99f 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -233,9 +233,12 @@ def find_autosummary_in_lines(lines, module=None, filename=None): corresponding options set. """ autosummary_re = re.compile(r'^\s*\.\.\s+autosummary::\s*') - automodule_re = re.compile(r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$') - module_re = re.compile(r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$') - autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?') + automodule_re = re.compile( + r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$') + module_re = re.compile( + r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$') + autosummary_item_re = re.compile( + r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?') toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$') template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$') diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 964e58ee..ed5d92a4 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -79,6 +79,7 @@ class CoverageBuilder(Builder): def build_c_coverage(self): # Fetch all the info from the header files + c_objects = self.env.domaindata['c']['objects'] for filename in self.c_sourcefiles: undoc = [] f = open(filename, 'r') @@ -88,7 +89,7 @@ class CoverageBuilder(Builder): match = regex.match(line) if match: name = match.groups()[0] - if name not in self.env.descrefs: + if name not in c_objects: for exp in self.c_ignorexps.get(key, ()): if exp.match(name): break @@ -116,7 +117,10 @@ class CoverageBuilder(Builder): op.close() def build_py_coverage(self): - for mod_name in self.env.modules: + objects = self.env.domaindata['py']['objects'] + modules = self.env.domaindata['py']['modules'] + + for mod_name in modules: ignore = False for exp in self.mod_ignorexps: if exp.match(mod_name): @@ -151,7 +155,7 @@ class CoverageBuilder(Builder): full_name = '%s.%s' % (mod_name, name) if inspect.isfunction(obj): - if full_name not in self.env.descrefs: + if full_name not in objects: for exp in self.fun_ignorexps: if exp.match(name): break @@ -162,7 +166,7 @@ class CoverageBuilder(Builder): if exp.match(name): break else: - if full_name not in self.env.descrefs: + if full_name not in objects: # not documented at all classes[name] = [] continue @@ -176,7 +180,7 @@ class CoverageBuilder(Builder): continue full_attr_name = '%s.%s' % (full_name, attr_name) - if full_attr_name not in self.env.descrefs: + if full_attr_name not in objects: attrs.append(attr_name) if attrs: diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py index 90cd2b2c..1bc66af8 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -41,7 +41,8 @@ class IfConfig(Directive): node.document = self.state.document node.line = self.lineno node['expr'] = self.arguments[0] - self.state.nested_parse(self.content, self.content_offset, node) + self.state.nested_parse(self.content, self.content_offset, + node, match_titles=1) return [node] diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 35790731..e464adb5 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -47,7 +47,6 @@ except ImportError: from docutils import nodes from docutils.parsers.rst import directives -from sphinx.roles import xfileref_role from sphinx.ext.graphviz import render_dot_html, render_dot_latex from sphinx.util.compat import Directive @@ -280,6 +279,7 @@ class InheritanceDiagram(Directive): node.document = self.state.document env = self.state.document.settings.env class_names = self.arguments[0].split() + class_role = env.get_domain('py').role('class') # Create a graph starting with the list of classes try: @@ -293,7 +293,7 @@ class InheritanceDiagram(Directive): # references to real URLs later. These nodes will eventually be # removed from the doctree after we're done with them. for name in graph.get_all_class_names(): - refnodes, x = xfileref_role( + refnodes, x = class_role( 'class', ':class:`%s`' % name, name, 0, self.state) node.extend(refnodes) # Store the graph object so we can use it to generate the diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 91f7c101..e2c96a96 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -93,7 +93,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader): # make the paths into loaders self.loaders = map(SphinxFileSystemLoader, chain) - use_i18n = builder.translator is not None + use_i18n = builder.app.translator is not None extensions = use_i18n and ['jinja2.ext.i18n'] or [] self.environment = SandboxedEnvironment(loader=self, extensions=extensions) @@ -101,7 +101,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader): self.environment.globals['debug'] = contextfunction(pformat) self.environment.globals['accesskey'] = contextfunction(accesskey) if use_i18n: - self.environment.install_gettext_translations(builder.translator) + self.environment.install_gettext_translations(builder.app.translator) def render(self, template, context): return self.environment.get_template(template).render(context) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 36fabc61..63b5caf0 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -8,41 +8,179 @@ :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import gettext +import UserString + +from sphinx import package_dir + + +class _TranslationProxy(UserString.UserString, object): + """Class for proxy strings from gettext translations. This is a helper + for the lazy_* functions from this module. + + The proxy implementation attempts to be as complete as possible, so that + the lazy objects should mostly work as expected, for example for sorting. + + This inherits from UserString because some docutils versions use UserString + for their Text nodes, which then checks its argument for being either a + basestring or UserString, otherwise calls str() -- not unicode() -- on it. + This also inherits from object to make the __new__ method work. + """ + __slots__ = ('_func', '_args') + + def __new__(cls, func, *args): + if not args: + # not called with "function" and "arguments", but a plain string + return unicode(func) + return object.__new__(cls) + + def __init__(self, func, *args): + self._func = func + self._args = args + + data = property(lambda x: x._func(*x._args)) + + def __contains__(self, key): + return key in self.data + + def __nonzero__(self): + return bool(self.data) + + def __dir__(self): + return dir(unicode) + + def __iter__(self): + return iter(self.data) + + def __len__(self): + return len(self.data) + + def __str__(self): + return str(self.data) + + def __unicode__(self): + return unicode(self.data) + + def __add__(self, other): + return self.data + other + + def __radd__(self, other): + return other + self.data + + def __mod__(self, other): + return self.data % other + + def __rmod__(self, other): + return other % self.data + + def __mul__(self, other): + return self.data * other + + def __rmul__(self, other): + return other * self.data + + def __lt__(self, other): + return self.data < other + + def __le__(self, other): + return self.data <= other + + def __eq__(self, other): + return self.data == other + + def __ne__(self, other): + return self.data != other + + def __gt__(self, other): + return self.data > other + + def __ge__(self, other): + return self.data >= other + + def __getattr__(self, name): + if name == '__members__': + return self.__dir__() + return getattr(self.data, name) + + def __getstate__(self): + return self._func, self._args + + def __setstate__(self, tup): + self._func, self._args = tup + + def __getitem__(self, key): + return self.data[key] + + def __copy__(self): + return self + + def __repr__(self): + try: + return 'i' + repr(unicode(self.data)) + except: + return '<%s broken>' % self.__class__.__name__ + +def mygettext(string): + """Used instead of _ when creating TranslationProxies, because _ is + not bound yet at that time.""" + return _(string) + +def lazy_gettext(string): + """A lazy version of `gettext`.""" + #if isinstance(string, _TranslationProxy): + # return string + return _TranslationProxy(mygettext, string) + +l_ = lazy_gettext -_ = lambda x: x admonitionlabels = { - 'attention': _('Attention'), - 'caution': _('Caution'), - 'danger': _('Danger'), - 'error': _('Error'), - 'hint': _('Hint'), - 'important': _('Important'), - 'note': _('Note'), - 'seealso': _('See Also'), - 'tip': _('Tip'), - 'warning': _('Warning'), + 'attention': l_('Attention'), + 'caution': l_('Caution'), + 'danger': l_('Danger'), + 'error': l_('Error'), + 'hint': l_('Hint'), + 'important': l_('Important'), + 'note': l_('Note'), + 'seealso': l_('See Also'), + 'tip': l_('Tip'), + 'warning': l_('Warning'), } versionlabels = { - 'versionadded': _('New in version %s'), - 'versionchanged': _('Changed in version %s'), - 'deprecated': _('Deprecated since version %s'), + 'versionadded': l_('New in version %s'), + 'versionchanged': l_('Changed in version %s'), + 'deprecated': l_('Deprecated since version %s'), } pairindextypes = { - 'module': _('module'), - 'keyword': _('keyword'), - 'operator': _('operator'), - 'object': _('object'), - 'exception': _('exception'), - 'statement': _('statement'), - 'builtin': _('built-in function'), + 'module': l_('module'), + 'keyword': l_('keyword'), + 'operator': l_('operator'), + 'object': l_('object'), + 'exception': l_('exception'), + 'statement': l_('statement'), + 'builtin': l_('built-in function'), } -del _ -def init(): - for dct in (admonitionlabels, versionlabels, pairindextypes): - for key in dct: - dct[key] = _(dct[key]) +def init(locale_dirs, language): + # the None entry is the system's default locale path + translator = None + has_translation = True + for dir_ in locale_dirs: + try: + trans = gettext.translation('sphinx', localedir=dir_, + languages=[language]) + if translator is None: + translator = trans + else: + translator._catalog.update(trans.catalog) + except Exception: + # Language couldn't be found in the specified path + pass + if translator is None: + translator = gettext.NullTranslations() + has_translation = False + translator.install(unicode=True) + return translator, has_translation diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.js b/sphinx/locale/ca/LC_MESSAGES/sphinx.js new file mode 100644 index 00000000..8ad043b0 --- /dev/null +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.js @@ -0,0 +1 @@ +Documentation.addTranslations({"locale": "ca", "plural_expr": "(n != 1)", "messages": {"Search Results": "Resultats de la Cerca", "Preparing search...": "Preparant la cerca...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "La teva cerca no ha donat resultats. Assegura't que totes les paraules estan ben escrites i que has seleccionat prou categories.", "Search finished, found %s page(s) matching the search query.": "Cerca finalitzada, s'han trobat %s p\u00e0gin(a/es) de resultats.", ", in ": ", a ", "Permalink to this headline": "Link permanent a aquest t\u00edtol", "Searching": "Cercant", "Permalink to this definition": "Link permanent a aquesta definici\u00f3", "module, in ": "m\u00f2dule, a ", "Hide Search Matches": "Oculta Resultats de Cerca"}});
\ No newline at end of file diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.mo b/sphinx/locale/ca/LC_MESSAGES/sphinx.mo Binary files differnew file mode 100644 index 00000000..d9cc44ce --- /dev/null +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.po b/sphinx/locale/ca/LC_MESSAGES/sphinx.po new file mode 100644 index 00000000..440b0594 --- /dev/null +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.po @@ -0,0 +1,606 @@ +# Catalan translations for Sphinx. +# Copyright (C) 2009 ORGANIZATION +# This file is distributed under the same license as the Sphinx project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: Sphinx 1.0\n" +"Report-Msgid-Bugs-To: pau.fernandez@upc.edu\n" +"POT-Creation-Date: 2009-05-22 18:51+0200\n" +"PO-Revision-Date: 2009-06-07 14:20+0200\n" +"Last-Translator: Pau Fernández <pau.fernandez@upc.edu>\n" +"Language-Team: ca <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.4\n" + +#: sphinx/environment.py:104 sphinx/writers/latex.py:184 +#, python-format +msgid "%B %d, %Y" +msgstr "%d de %B de %Y" + +#: sphinx/environment.py:323 sphinx/themes/basic/genindex-single.html:2 +#: sphinx/themes/basic/genindex-split.html:2 +#: sphinx/themes/basic/genindex-split.html:5 +#: sphinx/themes/basic/genindex.html:2 sphinx/themes/basic/genindex.html:5 +#: sphinx/themes/basic/genindex.html:48 sphinx/themes/basic/layout.html:131 +#: sphinx/writers/latex.py:190 +msgid "Index" +msgstr "Índex" + +#: sphinx/environment.py:324 sphinx/writers/latex.py:189 +msgid "Module Index" +msgstr "Índex de Mòduls" + +#: sphinx/environment.py:325 sphinx/themes/basic/defindex.html:16 +msgid "Search Page" +msgstr "Pàgina de Cerca" + +#: sphinx/roles.py:55 sphinx/directives/desc.py:747 +#, python-format +msgid "environment variable; %s" +msgstr "variable d'entorn; %s" + +#: sphinx/roles.py:62 +#, python-format +msgid "Python Enhancement Proposals!PEP %s" +msgstr "Python Enhancement Proposals!PEP %s" + +#: sphinx/builders/changes.py:71 +msgid "Builtins" +msgstr "Mòduls Interns" + +#: sphinx/builders/changes.py:73 +msgid "Module level" +msgstr "Nivell de mòdul" + +#: sphinx/builders/html.py:219 +#, python-format +msgid "%b %d, %Y" +msgstr "%d %b, %Y" + +#: sphinx/builders/html.py:238 sphinx/themes/basic/defindex.html:21 +msgid "General Index" +msgstr "Índex General" + +#: sphinx/builders/html.py:238 +msgid "index" +msgstr "índex" + +#: sphinx/builders/html.py:240 sphinx/builders/htmlhelp.py:184 +#: sphinx/builders/qthelp.py:132 sphinx/themes/basic/defindex.html:19 +#: sphinx/themes/basic/modindex.html:2 sphinx/themes/basic/modindex.html:13 +msgid "Global Module Index" +msgstr "Índex Global de Mòduls" + +#: sphinx/builders/html.py:241 +msgid "modules" +msgstr "mòduls" + +#: sphinx/builders/html.py:296 +msgid "next" +msgstr "següent" + +#: sphinx/builders/html.py:305 +msgid "previous" +msgstr "anterior" + +#: sphinx/builders/latex.py:162 +msgid " (in " +msgstr " (a " + +#: sphinx/directives/desc.py:97 +msgid "Raises" +msgstr "Llença" + +#: sphinx/directives/desc.py:101 +msgid "Variable" +msgstr "Variable" + +#: sphinx/directives/desc.py:104 +msgid "Returns" +msgstr "Retorna" + +#: sphinx/directives/desc.py:113 +msgid "Return type" +msgstr "Tipus de retorn" + +#: sphinx/directives/desc.py:186 +msgid "Parameter" +msgstr "Paràmetre" + +#: sphinx/directives/desc.py:190 +msgid "Parameters" +msgstr "Paràmetres" + +#: sphinx/directives/desc.py:418 +#, python-format +msgid "%s() (built-in function)" +msgstr "%s() (funció interna)" + +#: sphinx/directives/desc.py:419 sphinx/directives/desc.py:476 +#: sphinx/directives/desc.py:488 +#, python-format +msgid "%s() (in module %s)" +msgstr "%s() (al mòdul %s)" + +#: sphinx/directives/desc.py:422 +#, python-format +msgid "%s (built-in variable)" +msgstr "%s (variable interna)" + +#: sphinx/directives/desc.py:423 sphinx/directives/desc.py:514 +#, python-format +msgid "%s (in module %s)" +msgstr "%s (al mòdul %s)" + +#: sphinx/directives/desc.py:439 +#, python-format +msgid "%s (built-in class)" +msgstr "%s (classe interna)" + +#: sphinx/directives/desc.py:440 +#, python-format +msgid "%s (class in %s)" +msgstr "%s (class a %s)" + +#: sphinx/directives/desc.py:480 +#, python-format +msgid "%s() (%s.%s method)" +msgstr "%s() (mètode %s.%s)" + +#: sphinx/directives/desc.py:482 +#, python-format +msgid "%s() (%s method)" +msgstr "%s() (mètode %s)" + +#: sphinx/directives/desc.py:492 +#, python-format +msgid "%s() (%s.%s static method)" +msgstr "%s() (mètode estàtic %s.%s)" + +#: sphinx/directives/desc.py:495 +#, python-format +msgid "%s() (%s static method)" +msgstr "%s() (mètode estàtic %s)" + +#: sphinx/directives/desc.py:518 +#, python-format +msgid "%s (%s.%s attribute)" +msgstr "%s (atribut %s.%s)" + +#: sphinx/directives/desc.py:520 +#, python-format +msgid "%s (%s attribute)" +msgstr "%s (atribut %s)" + +#: sphinx/directives/desc.py:609 +#, python-format +msgid "%s (C function)" +msgstr "%s (funció de C)" + +#: sphinx/directives/desc.py:611 +#, python-format +msgid "%s (C member)" +msgstr "%s (membre de C)" + +#: sphinx/directives/desc.py:613 +#, python-format +msgid "%s (C macro)" +msgstr "%s (macro de C)" + +#: sphinx/directives/desc.py:615 +#, python-format +msgid "%s (C type)" +msgstr "%s (tipus de C)" + +#: sphinx/directives/desc.py:617 +#, python-format +msgid "%s (C variable)" +msgstr "%s (variable de C)" + +#: sphinx/directives/desc.py:665 +#, python-format +msgid "%scommand line option; %s" +msgstr "opció de línia de comandes %s; %s" + +#: sphinx/directives/other.py:138 +msgid "Platforms: " +msgstr "Plataformes: " + +#: sphinx/directives/other.py:144 +#, python-format +msgid "%s (module)" +msgstr "%s (mòdul)" + +#: sphinx/directives/other.py:193 +msgid "Section author: " +msgstr "Autor de la secció:" + +#: sphinx/directives/other.py:195 +msgid "Module author: " +msgstr "Autor del mòdul: " + +#: sphinx/directives/other.py:197 +msgid "Author: " +msgstr "Autor: " + +#: sphinx/directives/other.py:317 +msgid "See also" +msgstr "Vegeu també" + +#: sphinx/ext/autodoc.py:888 +#, python-format +msgid " Bases: %s" +msgstr " Bases: %s" + +#: sphinx/ext/autodoc.py:919 +#, python-format +msgid "alias of :class:`%s`" +msgstr "àlies de :class:`%s`" + +#: sphinx/ext/todo.py:41 +msgid "Todo" +msgstr "Pendent" + +#: sphinx/ext/todo.py:99 +#, python-format +msgid "(The original entry is located in %s, line %d and can be found " +msgstr "(La entrada original està a %s, línia %d i es pot trobar " + +#: sphinx/ext/todo.py:105 +msgid "here" +msgstr "aquí" + +#: sphinx/locale/__init__.py:15 +msgid "Attention" +msgstr "Atenció" + +#: sphinx/locale/__init__.py:16 +msgid "Caution" +msgstr "Compte" + +#: sphinx/locale/__init__.py:17 +msgid "Danger" +msgstr "Perill" + +#: sphinx/locale/__init__.py:18 +msgid "Error" +msgstr "Error" + +#: sphinx/locale/__init__.py:19 +msgid "Hint" +msgstr "Suggerència" + +#: sphinx/locale/__init__.py:20 +msgid "Important" +msgstr "Important" + +#: sphinx/locale/__init__.py:21 +msgid "Note" +msgstr "Nota" + +#: sphinx/locale/__init__.py:22 +msgid "See Also" +msgstr "Vegeu També" + +#: sphinx/locale/__init__.py:23 +msgid "Tip" +msgstr "Truc" + +#: sphinx/locale/__init__.py:24 +msgid "Warning" +msgstr "Avís" + +#: sphinx/locale/__init__.py:28 +#, python-format +msgid "New in version %s" +msgstr "Novetat de la versió %s" + +#: sphinx/locale/__init__.py:29 +#, python-format +msgid "Changed in version %s" +msgstr "Canviat a la versió %s" + +#: sphinx/locale/__init__.py:30 +#, python-format +msgid "Deprecated since version %s" +msgstr "Obsolet desde la versió %s" + +#: sphinx/locale/__init__.py:34 +msgid "module" +msgstr "mòdul" + +#: sphinx/locale/__init__.py:35 +msgid "keyword" +msgstr "paraula clau" + +#: sphinx/locale/__init__.py:36 +msgid "operator" +msgstr "operador" + +#: sphinx/locale/__init__.py:37 +msgid "object" +msgstr "objecte" + +#: sphinx/locale/__init__.py:38 +msgid "exception" +msgstr "excepció" + +#: sphinx/locale/__init__.py:39 +msgid "statement" +msgstr "sentència" + +#: sphinx/locale/__init__.py:40 +msgid "built-in function" +msgstr "funció interna" + +#: sphinx/themes/basic/defindex.html:2 +msgid "Overview" +msgstr "Resum" + +#: sphinx/themes/basic/defindex.html:11 +msgid "Indices and tables:" +msgstr "Índexs i taules:" + +#: sphinx/themes/basic/defindex.html:14 +msgid "Complete Table of Contents" +msgstr "Taula de Contingut Completa" + +#: sphinx/themes/basic/defindex.html:15 +msgid "lists all sections and subsections" +msgstr "llista totes les seccions i subseccions" + +#: sphinx/themes/basic/defindex.html:17 +msgid "search this documentation" +msgstr "cerca aquesta documentació" + +#: sphinx/themes/basic/defindex.html:20 +msgid "quick access to all modules" +msgstr "accés ràpid a tots els mòduls" + +#: sphinx/themes/basic/defindex.html:22 +msgid "all functions, classes, terms" +msgstr "totes les funcions, classes, termes" + +#: sphinx/themes/basic/genindex-single.html:5 +#, python-format +msgid "Index – %(key)s" +msgstr "Índes – %(key)s" + +#: sphinx/themes/basic/genindex-single.html:44 +#: sphinx/themes/basic/genindex-split.html:14 +#: sphinx/themes/basic/genindex-split.html:27 +#: sphinx/themes/basic/genindex.html:54 +msgid "Full index on one page" +msgstr "Índex complet en una pàgina" + +#: sphinx/themes/basic/genindex-split.html:7 +msgid "Index pages by letter" +msgstr "Pàgines d'índex per lletra" + +#: sphinx/themes/basic/genindex-split.html:15 +msgid "can be huge" +msgstr "pot ser gegant" + +#: sphinx/themes/basic/layout.html:10 +msgid "Navigation" +msgstr "Navegació" + +#: sphinx/themes/basic/layout.html:42 +msgid "Table Of Contents" +msgstr "Taula de Contingut" + +#: sphinx/themes/basic/layout.html:48 +msgid "Previous topic" +msgstr "Tema anterior" + +#: sphinx/themes/basic/layout.html:50 +msgid "previous chapter" +msgstr "capítol anterior" + +#: sphinx/themes/basic/layout.html:53 +msgid "Next topic" +msgstr "Tema següent" + +#: sphinx/themes/basic/layout.html:55 +msgid "next chapter" +msgstr "capítol següent" + +#: sphinx/themes/basic/layout.html:60 +msgid "This Page" +msgstr "Aquesta Pàgina" + +#: sphinx/themes/basic/layout.html:63 +msgid "Show Source" +msgstr "Mostra Codi Font" + +#: sphinx/themes/basic/layout.html:73 +msgid "Quick search" +msgstr "Cerca ràpida" + +#: sphinx/themes/basic/layout.html:76 +msgid "Go" +msgstr "Ves a" + +#: sphinx/themes/basic/layout.html:81 +msgid "Enter search terms or a module, class or function name." +msgstr "Entra paraules de cerca o el nom d'un mòdul, classe o funció." + +#: sphinx/themes/basic/layout.html:119 +#, python-format +msgid "Search within %(docstitle)s" +msgstr "Cerca dins de %(docstitle)s" + +#: sphinx/themes/basic/layout.html:128 +msgid "About these documents" +msgstr "Quant a aquests documents" + +#: sphinx/themes/basic/layout.html:134 sphinx/themes/basic/search.html:2 +#: sphinx/themes/basic/search.html:5 +msgid "Search" +msgstr "Cerca" + +#: sphinx/themes/basic/layout.html:137 +msgid "Copyright" +msgstr "Copyright" + +#: sphinx/themes/basic/layout.html:184 +#, python-format +msgid "© <a href=\"%(path)s\">Copyright</a> %(copyright)s." +msgstr "© <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s." + +#: sphinx/themes/basic/layout.html:186 +#, python-format +msgid "© Copyright %(copyright)s." +msgstr "© Copyright %(copyright)s." + +#: sphinx/themes/basic/layout.html:190 +#, python-format +msgid "Last updated on %(last_updated)s." +msgstr "Última actualització el %(last_updated)s." + +#: sphinx/themes/basic/layout.html:193 +#, python-format +msgid "" +"Created using <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> " +"%(sphinx_version)s." +msgstr "" +"Creat amb <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> " +"%(sphinx_version)s." + +#: sphinx/themes/basic/modindex.html:36 +msgid "Deprecated" +msgstr "Obsolet" + +#: sphinx/themes/basic/opensearch.xml:4 +#, python-format +msgid "Search %(docstitle)s" +msgstr "Cercar a %(docstitle)s" + +#: sphinx/themes/basic/search.html:9 +msgid "" +"Please activate JavaScript to enable the search\n" +" functionality." +msgstr "" +"Activa JavaScript per utilitzar la funcionalitat\n" +"de cerca." + +#: sphinx/themes/basic/search.html:14 +msgid "" +"From here you can search these documents. Enter your search\n" +" words into the box below and click \"search\". Note that the search\n" +" function will automatically search for all of the words. Pages\n" +" containing fewer words won't appear in the result list." +msgstr "" +"Des d'aquí pots fer cerques en aquests documents. Entra les \n" +"paraules de la teva cerca i clica el botó \"cerca\". Tingues en compte\n" +"que la cerca inclourà totes les paraules que posis. Les pàgines que no\n" +"tenen totes les paraules no sortiràn." + +#: sphinx/themes/basic/search.html:21 +msgid "search" +msgstr "cerca" + +#: sphinx/themes/basic/search.html:25 +#: sphinx/themes/basic/static/searchtools.js:462 +msgid "Search Results" +msgstr "Resultats de la Cerca" + +#: sphinx/themes/basic/search.html:27 +msgid "Your search did not match any results." +msgstr "La teva cerca no té resultats." + +#: sphinx/themes/basic/changes/frameset.html:5 +#: sphinx/themes/basic/changes/versionchanges.html:12 +#, python-format +msgid "Changes in Version %(version)s — %(docstitle)s" +msgstr "Canvis a la Versió %(version)s — %(docstitle)s" + +#: sphinx/themes/basic/changes/rstsource.html:5 +#, python-format +msgid "%(filename)s — %(docstitle)s" +msgstr "%(filename)s — %(docstitle)s" + +#: sphinx/themes/basic/changes/versionchanges.html:17 +#, python-format +msgid "Automatically generated list of changes in version %(version)s" +msgstr "Llista de canvis de la versió %(version)s generada automàticament" + +#: sphinx/themes/basic/changes/versionchanges.html:18 +msgid "Library changes" +msgstr "Canvis a la llibreria" + +#: sphinx/themes/basic/changes/versionchanges.html:23 +msgid "C API changes" +msgstr "Canvis a la API de C" + +#: sphinx/themes/basic/changes/versionchanges.html:25 +msgid "Other changes" +msgstr "Altres canvis" + +#: sphinx/themes/basic/static/doctools.js:139 sphinx/writers/html.py:473 +#: sphinx/writers/html.py:478 +msgid "Permalink to this headline" +msgstr "Link permanent a aquest títol" + +#: sphinx/themes/basic/static/doctools.js:145 sphinx/writers/html.py:80 +msgid "Permalink to this definition" +msgstr "Link permanent a aquesta definició" + +#: sphinx/themes/basic/static/doctools.js:174 +msgid "Hide Search Matches" +msgstr "Oculta Resultats de Cerca" + +#: sphinx/themes/basic/static/searchtools.js:274 +msgid "Searching" +msgstr "Cercant" + +#: sphinx/themes/basic/static/searchtools.js:279 +msgid "Preparing search..." +msgstr "Preparant la cerca..." + +#: sphinx/themes/basic/static/searchtools.js:347 +msgid "module, in " +msgstr "mòdule, a " + +#: sphinx/themes/basic/static/searchtools.js:356 +msgid ", in " +msgstr ", a " + +#: sphinx/themes/basic/static/searchtools.js:464 +msgid "" +"Your search did not match any documents. Please make sure that all words " +"are spelled correctly and that you've selected enough categories." +msgstr "" +"La teva cerca no ha donat resultats. Assegura't que totes les paraules " +"estan ben escrites i que has seleccionat prou categories." + +#: sphinx/themes/basic/static/searchtools.js:466 +#, python-format +msgid "Search finished, found %s page(s) matching the search query." +msgstr "Cerca finalitzada, s'han trobat %s pàgin(a/es) de resultats." + +#: sphinx/writers/latex.py:187 +msgid "Release" +msgstr "Versió" + +#: sphinx/writers/latex.py:639 +msgid "continued from previous page" +msgstr "ve de la pàgina anterior" + +#: sphinx/writers/latex.py:643 +msgid "Continued on next page" +msgstr "Continua a la pàgina següent" + +#: sphinx/writers/text.py:166 +#, python-format +msgid "Platform: %s" +msgstr "Plataforma: %s" + +#: sphinx/writers/text.py:428 +msgid "[image]" +msgstr "[imatge]" + diff --git a/sphinx/locale/de/LC_MESSAGES/sphinx.mo b/sphinx/locale/de/LC_MESSAGES/sphinx.mo Binary files differindex a8905259..681091ce 100644 --- a/sphinx/locale/de/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/de/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/de/LC_MESSAGES/sphinx.po b/sphinx/locale/de/LC_MESSAGES/sphinx.po index e1d61a20..9483de79 100644 --- a/sphinx/locale/de/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/de/LC_MESSAGES/sphinx.po @@ -248,7 +248,7 @@ msgstr "Zu tun" #: sphinx/ext/todo.py:99 #, python-format msgid "(The original entry is located in %s, line %d and can be found " -msgstr "(Der ursprüngliche Eintrag steht in %s, Zeile %s, siehe " +msgstr "(Der ursprüngliche Eintrag steht in %s, Zeile %d, siehe " #: sphinx/ext/todo.py:105 msgid "here" diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.js b/sphinx/locale/fi/LC_MESSAGES/sphinx.js index f654e7e1..82f02c29 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.js @@ -1 +1 @@ -Documentation.addTranslations({"locale": "fi", "plural_expr": "(n != 1)", "messages": {"module, in ": "", "Preparing search...": "Valmistellaan etsint\u00e4\u00e4...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Ei l\u00f6ytynyt yht\u00e4\u00e4n. Tarkista hakuehdot, sanahaku, ei sen osia", "Search finished, found %s page(s) matching the search query.": "Etsint\u00e4 tehty, l\u00f6ydetty %s sivu(a).", ", in ": "", "Permalink to this headline": "", "Searching": "Etsit\u00e4\u00e4n", "Permalink to this definition": "", "Hide Search Matches": "Piilota l\u00f6ydetyt", "Search Results": "Etsinn\u00e4n tulos"}});
\ No newline at end of file +Documentation.addTranslations({"locale": "fi", "plural_expr": "(n != 1)", "messages": {"Search Results": "Etsinn\u00e4n tulos", "Preparing search...": "Valmistellaan etsint\u00e4\u00e4...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Ei l\u00f6ytynyt yht\u00e4\u00e4n. Tarkista hakuehdot, sanahaku, ei sen osia", "Search finished, found %s page(s) matching the search query.": "Etsint\u00e4 tehty, l\u00f6ydetty %s sivu(a).", ", in ": "", "Permalink to this headline": "", "Searching": "Etsit\u00e4\u00e4n", "Permalink to this definition": "", "module, in ": "", "Hide Search Matches": "Piilota l\u00f6ydetyt"}});
\ No newline at end of file diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.mo b/sphinx/locale/fi/LC_MESSAGES/sphinx.mo Binary files differindex 44d19f8c..54b25dc8 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.po b/sphinx/locale/fi/LC_MESSAGES/sphinx.po index 3794a648..97cdace1 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.po @@ -594,7 +594,7 @@ msgstr "Hakemisto yhtenä luettelona" #: sphinx/writers/text.py:166 #, fuzzy, python-format msgid "Platform: %s" -msgstr "Ympäristö" +msgstr "Ympäristö: %s" #: sphinx/writers/text.py:428 msgid "[image]" diff --git a/sphinx/locale/sphinx.pot b/sphinx/locale/sphinx.pot index d6337cf7..438d247d 100644 --- a/sphinx/locale/sphinx.pot +++ b/sphinx/locale/sphinx.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Sphinx 1.0\n" +"Project-Id-Version: Sphinx 1.0pre/4bacd76a2cdc+a18846601c6e+\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2009-08-06 23:04+0200\n" +"POT-Creation-Date: 2009-08-09 22:45+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,218 +17,232 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.4\n" -#: sphinx/environment.py:103 sphinx/writers/latex.py:184 +#: sphinx/domains.py:290 #, python-format -msgid "%B %d, %Y" +msgid "%s() (built-in function)" msgstr "" -#: sphinx/environment.py:324 sphinx/themes/basic/genindex-single.html:2 -#: sphinx/themes/basic/genindex-split.html:2 -#: sphinx/themes/basic/genindex-split.html:5 -#: sphinx/themes/basic/genindex.html:2 sphinx/themes/basic/genindex.html:5 -#: sphinx/themes/basic/genindex.html:48 sphinx/themes/basic/layout.html:134 -#: sphinx/writers/latex.py:190 -msgid "Index" +#: sphinx/domains.py:291 sphinx/domains.py:348 sphinx/domains.py:360 +#: sphinx/domains.py:373 +#, python-format +msgid "%s() (in module %s)" msgstr "" -#: sphinx/environment.py:325 sphinx/writers/latex.py:189 -msgid "Module Index" +#: sphinx/domains.py:294 +#, python-format +msgid "%s (built-in variable)" msgstr "" -#: sphinx/environment.py:326 sphinx/themes/basic/defindex.html:16 -msgid "Search Page" +#: sphinx/domains.py:295 sphinx/domains.py:386 +#, python-format +msgid "%s (in module %s)" msgstr "" -#: sphinx/roles.py:55 sphinx/directives/desc.py:747 +#: sphinx/domains.py:311 #, python-format -msgid "environment variable; %s" +msgid "%s (built-in class)" msgstr "" -#: sphinx/roles.py:62 +#: sphinx/domains.py:312 #, python-format -msgid "Python Enhancement Proposals!PEP %s" +msgid "%s (class in %s)" msgstr "" -#: sphinx/builders/changes.py:71 -msgid "Builtins" +#: sphinx/domains.py:352 +#, python-format +msgid "%s() (%s.%s method)" msgstr "" -#: sphinx/builders/changes.py:73 -msgid "Module level" +#: sphinx/domains.py:354 +#, python-format +msgid "%s() (%s method)" msgstr "" -#: sphinx/builders/html.py:222 +#: sphinx/domains.py:364 #, python-format -msgid "%b %d, %Y" +msgid "%s() (%s.%s static method)" msgstr "" -#: sphinx/builders/html.py:241 sphinx/themes/basic/defindex.html:21 -msgid "General Index" +#: sphinx/domains.py:367 +#, python-format +msgid "%s() (%s static method)" msgstr "" -#: sphinx/builders/html.py:241 -msgid "index" +#: sphinx/domains.py:377 +#, python-format +msgid "%s() (%s.%s class method)" msgstr "" -#: sphinx/builders/html.py:243 sphinx/builders/htmlhelp.py:219 -#: sphinx/builders/qthelp.py:133 sphinx/themes/basic/defindex.html:19 -#: sphinx/themes/basic/modindex.html:2 sphinx/themes/basic/modindex.html:13 -msgid "Global Module Index" +#: sphinx/domains.py:380 +#, python-format +msgid "%s() (%s class method)" msgstr "" -#: sphinx/builders/html.py:244 -msgid "modules" +#: sphinx/domains.py:390 +#, python-format +msgid "%s (%s.%s attribute)" msgstr "" -#: sphinx/builders/html.py:300 -msgid "next" +#: sphinx/domains.py:392 +#, python-format +msgid "%s (%s attribute)" msgstr "" -#: sphinx/builders/html.py:309 -msgid "previous" +#: sphinx/domains.py:437 +msgid "Platforms: " msgstr "" -#: sphinx/builders/latex.py:162 -msgid " (in " +#: sphinx/domains.py:443 +#, python-format +msgid "%s (module)" msgstr "" -#: sphinx/directives/desc.py:97 -msgid "Raises" +#: sphinx/domains.py:705 +#, python-format +msgid "%s (C function)" msgstr "" -#: sphinx/directives/desc.py:101 -msgid "Variable" +#: sphinx/domains.py:707 +#, python-format +msgid "%s (C member)" msgstr "" -#: sphinx/directives/desc.py:104 -msgid "Returns" +#: sphinx/domains.py:709 +#, python-format +msgid "%s (C macro)" msgstr "" -#: sphinx/directives/desc.py:113 -msgid "Return type" +#: sphinx/domains.py:711 +#, python-format +msgid "%s (C type)" msgstr "" -#: sphinx/directives/desc.py:186 -msgid "Parameter" +#: sphinx/domains.py:713 +#, python-format +msgid "%s (C variable)" msgstr "" -#: sphinx/directives/desc.py:190 -msgid "Parameters" +#: sphinx/environment.py:106 sphinx/writers/latex.py:184 +#, python-format +msgid "%B %d, %Y" msgstr "" -#: sphinx/directives/desc.py:418 -#, python-format -msgid "%s() (built-in function)" +#: sphinx/environment.py:333 sphinx/themes/basic/genindex-single.html:2 +#: sphinx/themes/basic/genindex-split.html:2 +#: sphinx/themes/basic/genindex-split.html:5 +#: sphinx/themes/basic/genindex.html:2 sphinx/themes/basic/genindex.html:5 +#: sphinx/themes/basic/genindex.html:48 sphinx/themes/basic/layout.html:134 +#: sphinx/writers/latex.py:190 +msgid "Index" msgstr "" -#: sphinx/directives/desc.py:419 sphinx/directives/desc.py:476 -#: sphinx/directives/desc.py:488 -#, python-format -msgid "%s() (in module %s)" +#: sphinx/environment.py:334 sphinx/writers/latex.py:189 +msgid "Module Index" msgstr "" -#: sphinx/directives/desc.py:422 -#, python-format -msgid "%s (built-in variable)" +#: sphinx/environment.py:335 sphinx/themes/basic/defindex.html:16 +msgid "Search Page" msgstr "" -#: sphinx/directives/desc.py:423 sphinx/directives/desc.py:514 +#: sphinx/roles.py:139 sphinx/directives/desc.py:382 #, python-format -msgid "%s (in module %s)" +msgid "environment variable; %s" msgstr "" -#: sphinx/directives/desc.py:439 +#: sphinx/roles.py:146 #, python-format -msgid "%s (built-in class)" +msgid "Python Enhancement Proposals!PEP %s" msgstr "" -#: sphinx/directives/desc.py:440 -#, python-format -msgid "%s (class in %s)" +#: sphinx/builders/changes.py:71 +msgid "Builtins" msgstr "" -#: sphinx/directives/desc.py:480 -#, python-format -msgid "%s() (%s.%s method)" +#: sphinx/builders/changes.py:73 +msgid "Module level" msgstr "" -#: sphinx/directives/desc.py:482 +#: sphinx/builders/html.py:223 #, python-format -msgid "%s() (%s method)" +msgid "%b %d, %Y" msgstr "" -#: sphinx/directives/desc.py:492 -#, python-format -msgid "%s() (%s.%s static method)" +#: sphinx/builders/html.py:242 sphinx/themes/basic/defindex.html:21 +msgid "General Index" msgstr "" -#: sphinx/directives/desc.py:495 -#, python-format -msgid "%s() (%s static method)" +#: sphinx/builders/html.py:242 +msgid "index" msgstr "" -#: sphinx/directives/desc.py:518 -#, python-format -msgid "%s (%s.%s attribute)" +#: sphinx/builders/html.py:246 sphinx/builders/htmlhelp.py:219 +#: sphinx/builders/qthelp.py:133 sphinx/themes/basic/defindex.html:19 +#: sphinx/themes/basic/modindex.html:2 sphinx/themes/basic/modindex.html:13 +#: sphinx/themes/scrolls/modindex.html:2 sphinx/themes/scrolls/modindex.html:13 +msgid "Global Module Index" msgstr "" -#: sphinx/directives/desc.py:520 -#, python-format -msgid "%s (%s attribute)" +#: sphinx/builders/html.py:247 +msgid "modules" msgstr "" -#: sphinx/directives/desc.py:609 -#, python-format -msgid "%s (C function)" +#: sphinx/builders/html.py:303 +msgid "next" msgstr "" -#: sphinx/directives/desc.py:611 -#, python-format -msgid "%s (C member)" +#: sphinx/builders/html.py:312 +msgid "previous" msgstr "" -#: sphinx/directives/desc.py:613 -#, python-format -msgid "%s (C macro)" +#: sphinx/builders/latex.py:162 +msgid " (in " msgstr "" -#: sphinx/directives/desc.py:615 -#, python-format -msgid "%s (C type)" +#: sphinx/directives/desc.py:67 sphinx/directives/desc.py:68 +#: sphinx/directives/desc.py:69 sphinx/directives/desc.py:70 +msgid "Raises" msgstr "" -#: sphinx/directives/desc.py:617 -#, python-format -msgid "%s (C variable)" +#: sphinx/directives/desc.py:71 sphinx/directives/desc.py:72 +#: sphinx/directives/desc.py:73 +msgid "Variable" msgstr "" -#: sphinx/directives/desc.py:665 -#, python-format -msgid "%scommand line option; %s" +#: sphinx/directives/desc.py:74 sphinx/directives/desc.py:75 +#: sphinx/directives/desc.py:81 sphinx/directives/desc.py:82 +msgid "Returns" msgstr "" -#: sphinx/directives/other.py:140 -msgid "Platforms: " +#: sphinx/directives/desc.py:83 +msgid "Return type" msgstr "" -#: sphinx/directives/other.py:146 +#: sphinx/directives/desc.py:156 +msgid "Parameter" +msgstr "" + +#: sphinx/directives/desc.py:160 +msgid "Parameters" +msgstr "" + +#: sphinx/directives/desc.py:284 #, python-format -msgid "%s (module)" +msgid "%scommand line option; %s" msgstr "" -#: sphinx/directives/other.py:195 +#: sphinx/directives/other.py:126 msgid "Section author: " msgstr "" -#: sphinx/directives/other.py:197 +#: sphinx/directives/other.py:128 msgid "Module author: " msgstr "" -#: sphinx/directives/other.py:199 +#: sphinx/directives/other.py:130 msgid "Author: " msgstr "" -#: sphinx/directives/other.py:319 +#: sphinx/directives/other.py:250 msgid "See also" msgstr "" @@ -255,86 +269,86 @@ msgstr "" msgid "here" msgstr "" -#: sphinx/locale/__init__.py:15 +#: sphinx/locale/__init__.py:138 msgid "Attention" msgstr "" -#: sphinx/locale/__init__.py:16 +#: sphinx/locale/__init__.py:139 msgid "Caution" msgstr "" -#: sphinx/locale/__init__.py:17 +#: sphinx/locale/__init__.py:140 msgid "Danger" msgstr "" -#: sphinx/locale/__init__.py:18 +#: sphinx/locale/__init__.py:141 msgid "Error" msgstr "" -#: sphinx/locale/__init__.py:19 +#: sphinx/locale/__init__.py:142 msgid "Hint" msgstr "" -#: sphinx/locale/__init__.py:20 +#: sphinx/locale/__init__.py:143 msgid "Important" msgstr "" -#: sphinx/locale/__init__.py:21 +#: sphinx/locale/__init__.py:144 msgid "Note" msgstr "" -#: sphinx/locale/__init__.py:22 +#: sphinx/locale/__init__.py:145 msgid "See Also" msgstr "" -#: sphinx/locale/__init__.py:23 +#: sphinx/locale/__init__.py:146 msgid "Tip" msgstr "" -#: sphinx/locale/__init__.py:24 +#: sphinx/locale/__init__.py:147 msgid "Warning" msgstr "" -#: sphinx/locale/__init__.py:28 +#: sphinx/locale/__init__.py:151 #, python-format msgid "New in version %s" msgstr "" -#: sphinx/locale/__init__.py:29 +#: sphinx/locale/__init__.py:152 #, python-format msgid "Changed in version %s" msgstr "" -#: sphinx/locale/__init__.py:30 +#: sphinx/locale/__init__.py:153 #, python-format msgid "Deprecated since version %s" msgstr "" -#: sphinx/locale/__init__.py:34 +#: sphinx/locale/__init__.py:157 msgid "module" msgstr "" -#: sphinx/locale/__init__.py:35 +#: sphinx/locale/__init__.py:158 msgid "keyword" msgstr "" -#: sphinx/locale/__init__.py:36 +#: sphinx/locale/__init__.py:159 msgid "operator" msgstr "" -#: sphinx/locale/__init__.py:37 +#: sphinx/locale/__init__.py:160 msgid "object" msgstr "" -#: sphinx/locale/__init__.py:38 +#: sphinx/locale/__init__.py:161 msgid "exception" msgstr "" -#: sphinx/locale/__init__.py:39 +#: sphinx/locale/__init__.py:162 msgid "statement" msgstr "" -#: sphinx/locale/__init__.py:40 +#: sphinx/locale/__init__.py:163 msgid "built-in function" msgstr "" @@ -448,29 +462,29 @@ msgstr "" msgid "Copyright" msgstr "" -#: sphinx/themes/basic/layout.html:187 +#: sphinx/themes/basic/layout.html:187 sphinx/themes/scrolls/layout.html:83 #, python-format msgid "© <a href=\"%(path)s\">Copyright</a> %(copyright)s." msgstr "" -#: sphinx/themes/basic/layout.html:189 +#: sphinx/themes/basic/layout.html:189 sphinx/themes/scrolls/layout.html:85 #, python-format msgid "© Copyright %(copyright)s." msgstr "" -#: sphinx/themes/basic/layout.html:193 +#: sphinx/themes/basic/layout.html:193 sphinx/themes/scrolls/layout.html:89 #, python-format msgid "Last updated on %(last_updated)s." msgstr "" -#: sphinx/themes/basic/layout.html:196 +#: sphinx/themes/basic/layout.html:196 sphinx/themes/scrolls/layout.html:92 #, python-format msgid "" "Created using <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> " "%(sphinx_version)s." msgstr "" -#: sphinx/themes/basic/modindex.html:36 +#: sphinx/themes/basic/modindex.html:36 sphinx/themes/scrolls/modindex.html:37 msgid "Deprecated" msgstr "" diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 914d9567..c2446924 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -333,7 +333,8 @@ devhelp: \t@echo "Build finished." \t@echo "To view the help file:" \t@echo "# mkdir -p $$HOME/.local/share/devhelp/%(project_fn)s" -\t@echo "# ln -s %(rbuilddir)s/devhelp $$HOME/.local/share/devhelp/%(project_fn)s" +\t@echo "# ln -s %(rbuilddir)s/devhelp \ +$$HOME/.local/share/devhelp/%(project_fn)s" \t@echo "# devhelp" latex: diff --git a/sphinx/roles.py b/sphinx/roles.py index af574b98..db231463 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -10,6 +10,7 @@ """ import re +import warnings from docutils import nodes, utils from docutils.parsers.rst import roles @@ -28,7 +29,7 @@ generic_docroles = { 'manpage' : addnodes.literal_emphasis, 'mimetype' : addnodes.literal_emphasis, 'newsgroup' : addnodes.literal_emphasis, - 'program' : nodes.strong, + 'program' : nodes.strong, # XXX should be an x-ref 'regexp' : nodes.literal, } @@ -37,6 +38,89 @@ for rolename, nodeclass in generic_docroles.iteritems(): roles.register_local_role(rolename, role) +# -- generic cross-reference roles --------------------------------------------- + +class XRefRole(object): + """XXX add docstring""" + + nodeclass = addnodes.pending_xref + innernodeclass = nodes.literal + + def __init__(self, fix_parens=False, lowercase=False, + nodeclass=None, innernodeclass=None): + 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 ':' not in typ: + domain, role = '', typ + else: + domain, role = typ.split(':', 1) + 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], [] + + +class OptionXRefRole(XRefRole): + innernodeclass = addnodes.literal_emphasis + + 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) + pnode['refprogram'] = program + return title, target + + +_EnvvarXrefRole = XRefRole() + def indexmarkup_role(typ, rawtext, etext, lineno, inliner, options={}, content=[]): env = inliner.document.settings.env @@ -54,8 +138,8 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, indexnode['entries'] = [('single', text, targetid, text), ('single', _('environment variable; %s') % text, targetid, text)] - xref_nodes = xfileref_role(typ, rawtext, etext, lineno, inliner, - options, content)[0] + xref_nodes = _EnvvarXrefRole(typ, rawtext, etext, lineno, inliner, + options, content)[0] return [indexnode, targetnode] + xref_nodes, [] elif typ == 'pep': indexnode['entries'] = [ @@ -89,117 +173,12 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, rn += sn return [indexnode, targetnode, rn], [] -roles.register_local_role('envvar', indexmarkup_role) -roles.register_local_role('pep', indexmarkup_role) -roles.register_local_role('rfc', indexmarkup_role) - - -# default is `literal` -innernodetypes = { - 'ref': nodes.emphasis, - 'term': nodes.emphasis, - 'token': nodes.strong, - 'envvar': nodes.strong, - 'download': nodes.strong, - 'option': addnodes.literal_emphasis, -} - -def _fix_parens(typ, text, env): - if typ in ('func', 'meth', 'cfunc'): - if text.endswith('()'): - # remove parentheses - text = text[:-2] - if env.config.add_function_parentheses: - # add them back to all occurrences if configured - text += '()' - return text - -def xfileref_role(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 [innernodetypes.get(typ, nodes.literal)( - rawtext, text, classes=['xref'])], [] - # we want a cross-reference, create the reference node - nodeclass = (typ == 'download') and addnodes.download_reference or \ - addnodes.pending_xref - pnode = nodeclass(rawtext, reftype=typ, refcaption=False, - modname=env.currmodule, classname=env.currclass) - # we may need the line number for warnings - pnode.line = lineno - # look if explicit title and target are given with `foo <bar>` syntax - has_explicit_title, title, target = split_explicit_title(text) - if has_explicit_title: - pnode['refcaption'] = True - # special target for Python object cross-references - if typ in ('data', 'exc', 'func', 'class', 'const', 'attr', - 'meth', 'mod', 'obj'): - # fix-up parentheses in link title - 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 - title = _fix_parens(typ, title, env) - # 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:] - # remove parentheses from the target too - if target.endswith('()'): - target = target[:-2] - # 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 - # some other special cases for the target - elif typ == 'option': - 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) - pnode['refprogram'] = program - elif typ == 'term': - # normalize whitespace in definition terms (if the term reference is - # broken over a line, a newline will be in target) - target = ws_re.sub(' ', target).lower() - elif typ == 'ref': - # reST label names are always lowercased - target = ws_re.sub('', target).lower() - elif typ == 'cfunc': - # fix-up parens for C functions too - if not has_explicit_title: - title = _fix_parens(typ, title, env) - # remove parentheses from the target too - if target.endswith('()'): - target = target[:-2] - else: - # remove all whitespace to avoid referencing problems - target = ws_re.sub('', target) - pnode['reftarget'] = target - pnode += innernodetypes.get(typ, nodes.literal)(rawtext, title, - classes=['xref']) - return [pnode], [] - def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): return [nodes.emphasis( rawtext, utils.unescape(text).replace('-->', u'\N{TRIANGULAR BULLET}'))], [] + return role _litvar_re = re.compile('{([^}]+)}') @@ -233,30 +212,17 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): specific_docroles = { - 'data': xfileref_role, - 'exc': xfileref_role, - 'func': xfileref_role, - 'class': xfileref_role, - 'const': xfileref_role, - 'attr': xfileref_role, - 'meth': xfileref_role, - 'obj': xfileref_role, - 'cfunc' : xfileref_role, - 'cmember': xfileref_role, - 'cdata': xfileref_role, - 'ctype': xfileref_role, - 'cmacro': xfileref_role, - - 'mod': xfileref_role, - - 'keyword': xfileref_role, - 'ref': xfileref_role, - 'token': xfileref_role, - 'term': xfileref_role, - 'option': xfileref_role, - 'doc': xfileref_role, - 'download': xfileref_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), + + 'envvar': indexmarkup_role, + 'pep': indexmarkup_role, + 'rfc': indexmarkup_role, 'menuselection': menusel_role, 'file': emph_literal_role, 'samp': emph_literal_role, @@ -265,3 +231,10 @@ specific_docroles = { for rolename, func in specific_docroles.iteritems(): roles.register_local_role(rolename, func) + + +# compatibility alias +def xfileref_role(*args, **kwds): + warnings.warn('xfileref_role is deprecated, use XRefRole', + DeprecationWarning, stacklevel=2) + return XRefRole()(*args, **kwds) diff --git a/sphinx/search.py b/sphinx/search.py index 9bfa9d92..7f1a87a9 100644 --- a/sphinx/search.py +++ b/sphinx/search.py @@ -148,6 +148,8 @@ class IndexBuilder(object): def get_modules(self, fn2index): rv = {} + # XXX implement search capability + return rv for name, (doc, _, _, _) in self.env.modules.iteritems(): if doc in fn2index: rv[name] = fn2index[doc] @@ -156,6 +158,8 @@ class IndexBuilder(object): def get_descrefs(self, fn2index): rv = {} dt = self._desctypes + # XXX implement search capability + return rv for fullname, (doc, desctype) in self.env.descrefs.iteritems(): if doc not in fn2index: continue diff --git a/sphinx/themes/scrolls/artwork/logo.svg b/sphinx/themes/scrolls/artwork/logo.svg new file mode 100644 index 00000000..0907a4ea --- /dev/null +++ b/sphinx/themes/scrolls/artwork/logo.svg @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="200" + height="80" + id="svg2766" + sodipodi:version="0.32" + inkscape:version="0.46" + version="1.0" + sodipodi:docname="logo.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs2768"> + <linearGradient + id="linearGradient6558"> + <stop + style="stop-color:#575757;stop-opacity:1;" + offset="0" + id="stop6560" /> + <stop + style="stop-color:#2f2f2f;stop-opacity:1;" + offset="1" + id="stop6562" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective2774" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient6558" + id="radialGradient2797" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.7160081,0,0,0.6767021,-34.98413,-3.3035294e-2)" + cx="61.297766" + cy="60.910986" + fx="61.297766" + fy="60.910986" + r="44.688254" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="6.1848684" + inkscape:cx="95.923838" + inkscape:cy="34.518668" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1440" + inkscape:window-height="852" + inkscape:window-x="0" + inkscape:window-y="0" /> + <metadata + id="metadata2771"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + style="opacity:1;fill:url(#radialGradient2797);fill-opacity:1;fill-rule:evenodd;stroke:#323232;stroke-width:0.71600807000000000;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + d="M 72.4375 8.6875 L 3.0625 18.71875 L 20.84375 29.0625 L 20.6875 44.09375 L 7.75 36.1875 L 8.40625 71.75 L 17.125 65.625 L 29.09375 67.5625 L 33.15625 39.90625 L 25.875 43.78125 L 26.1875 33.59375 L 46.875 31.34375 L 47.21875 42.96875 L 39.28125 40.5625 L 42.6875 67.71875 L 52.375 66.75 L 60.3125 71.75 L 62.90625 33.4375 L 53.03125 43.625 L 53.03125 28.25 L 72.4375 8.6875 z M 48.03125 22.125 L 47.0625 26.46875 L 28.46875 28.09375 L 28.46875 25.1875 L 48.03125 22.125 z M 58.375 45.0625 L 57.40625 62.875 L 51.40625 60.59375 L 45.90625 61.71875 L 43 46.21875 L 53.84375 49.9375 L 58.375 45.0625 z M 12.125 46.53125 L 22 49.75 L 26.53125 47.03125 L 25.21875 62.0625 L 16.96875 60.4375 L 12.125 63.65625 L 12.125 46.53125 z " + id="path2783" /> + <path + style="opacity:1;fill:#e7eef6;fill-opacity:1;fill-rule:nonzero;stroke:#e1e8f3;stroke-width:0.52748101999999997;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + d="M 75.632462,22.265877 L 64.489624,64.880679 L 92.7889,40.941187 L 91.373937,61.872575 L 128.87048,23.519253 L 116.84328,58.36312 L 144.25821,44.450641 L 145.49631,65.632704 L 169.02007,38.183758 L 170.78877,60.493861 L 193.07447,18.631085 L 176.09491,36.554369 L 176.44864,19.633786 L 152.0405,44.701316 L 156.81601,27.655396 L 128.87048,44.325304 L 137.00652,14.494942 L 99.863721,44.325304 L 100.74807,27.028707 L 76.163076,45.829355 L 75.632462,22.265877 z" + id="path2804" /> + <text + xml:space="preserve" + style="font-size:12px;font-style:normal;font-weight:normal;opacity:1;fill:#1752b4;fill-opacity:1;fill-rule:nonzero;stroke:#28437f;stroke-width:0.71600807000000000;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans" + x="68.40242" + y="54.03759" + id="text2800"><tspan + sodipodi:role="line" + id="tspan2802" + x="68.40242" + y="54.03759" + style="font-size:36px;fill:#1752b4;fill-opacity:1;fill-rule:nonzero;stroke:#28437f;stroke-width:0.71600807000000000;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate">Project</tspan></text> + </g> +</svg> diff --git a/sphinx/themes/scrolls/genindex.html b/sphinx/themes/scrolls/genindex.html new file mode 100644 index 00000000..9add6e95 --- /dev/null +++ b/sphinx/themes/scrolls/genindex.html @@ -0,0 +1,36 @@ +{% extends "layout.html" %} +{% set title = 'Index' %} +{% block body %} + + <h1 id="index">Index</h1> + + {% for key, dummy in genindexentries -%} + <a href="#{{ key }}"><strong>{{ key }}</strong></a> {% if not loop.last %}| {% endif %} + {%- endfor %} + <hr> + + {% for key, entries in genindexentries %} + <h2 id="{{ key }}">{{ key }}</h2> + <table class="indextable"><tr> + {%- for column in entries|slice(2) if column %} + <td><dl> + {%- for entryname, (links, subitems) in column %} + <dt>{% if links %}<a href="{{ links[0] }}">{{ entryname|e }}</a> + {% for link in links[1:] %}, <a href="{{ link }}">[Link]</a>{% endfor %} + {%- else %}{{ entryname|e }}{% endif %}</dt> + {%- if subitems %} + <dd><dl> + {%- for subentryname, subentrylinks in subitems %} + <dt><a href="{{ subentrylinks[0] }}">{{ subentryname|e }}</a> + {%- for link in subentrylinks[1:] %}, <a href="{{ link }}">[Link]</a>{% endfor -%} + </dt> + {%- endfor %} + </dl></dd> + {%- endif -%} + {%- endfor %} + </dl></td> + {%- endfor %} + </tr></table> + {% endfor %} + +{% endblock %} diff --git a/sphinx/themes/scrolls/layout.html b/sphinx/themes/scrolls/layout.html new file mode 100644 index 00000000..d1c66ae2 --- /dev/null +++ b/sphinx/themes/scrolls/layout.html @@ -0,0 +1,96 @@ +<!doctype html> +<html> + <head> + {%- if not embedded %} + {%- set titlesuffix = " — "|safe + docstitle|e %} + {%- else %} + {%- set titlesuffix = "" %} + {%- endif %} + <title>{{ title|striptags }}{{ titlesuffix }}</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rel="stylesheet" href="{{ pathto('_static/style.css', 1) }}" type="text/css"> + <link rel="stylesheet" href="{{ pathto('_static/print.css', 1) }}" type="text/css" media="print"> + <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css"> + {%- if builder != 'htmlhelp' %} + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '{{ pathto("", 1) }}', + VERSION: '{{ release|e }}', + COLLAPSE_MODINDEX: false, + FILE_SUFFIX: '{{ file_suffix }}', + HAS_SOURCE: {{ has_source|lower }} + }; + </script> + <script type="text/javascript" src="{{ pathto('_static/jquery.js', 1) }}"></script> + <script type="text/javascript" src="{{ pathto('_static/interface.js', 1) }}"></script> + <script type="text/javascript" src="{{ pathto('_static/doctools.js', 1) }}"></script> + <script type="text/javascript" src="{{ pathto('_static/theme_extras.js', 1) }}"></script> + {%- endif %} + {%- if use_opensearch and builder != 'htmlhelp' %} + <link rel="search" type="application/opensearchdescription+xml" + title="Search within {{ docstitle }}" + href="{{ pathto('_static/opensearch.xml', 1) }}"> + {%- endif %} + {%- if hasdoc('about') %} + <link rel="author" title="About these documents" href="{{ pathto('about') }}"> + {%- endif %} + <link rel="contents" title="Global table of contents" href="{{ pathto('contents') }}"> + <link rel="index" title="Global index" href="{{ pathto('genindex') }}"> + <link rel="search" title="Search" href="{{ pathto('search') }}"> + {%- if hasdoc('copyright') %} + <link rel="copyright" title="Copyright" href="{{ pathto('copyright') }}"> + {%- endif %} + <link rel="top" title="{{ docstitle }}" href="{{ pathto('index') }}"> + {%- if parents %} + <link rel="up" title="{{ parents[-1].title|striptags }}" href="{{ parents[-1].link|e }}"> + {%- endif %} + {%- if next %} + <link rel="next" title="{{ next.title|striptags }}" href="{{ next.link|e }}"> + {%- endif %} + {%- if prev %} + <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}"> + {%- endif %} + {% block extrahead %}{% endblock %} + </head> + <body> + <div id="content"> + <div class="header"> + <h1 class="heading"><a href="{{ pathto('index') }}" + title="back to the documentation overview"><span>{{ title|striptags }}</span></a></h1> + </div> + <div class="relnav"> + {%- if prev %} + <a href="{{ prev.link|e }}">« {{ prev.title }}</a> | + {%- endif %} + <a href="{{ pathto(current_page_name) if current_page_name else '#' }}">{{ title }}</a> + {%- if next %} + | <a href="{{ next.link|e }}">{{ next.title }} »</a> + {%- endif %} + </div> + <div id="contentwrapper"> + {%- if display_toc %} + <div id="toc"> + <h3>Table Of Contents</h3> + {{ toc }} + </div> + {%- endif %} + {% block body %}{% endblock %} + </div> + </div> + <div class="footer"> + {%- if show_copyright %} + {%- if hasdoc('copyright') %} + {% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %} + {%- else %} + {% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {%- endif %} + {%- endif %} + {%- if last_updated %} + {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} + {%- endif %} + {%- if show_sphinx %} + {% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %} + {%- endif %} + </div> + </body> +</html> diff --git a/sphinx/themes/scrolls/modindex.html b/sphinx/themes/scrolls/modindex.html new file mode 100644 index 00000000..314ebdd9 --- /dev/null +++ b/sphinx/themes/scrolls/modindex.html @@ -0,0 +1,43 @@ +{% extends "layout.html" %} +{% set title = _('Global Module Index') %} +{% block extrahead %} +{{ super() }} +{% if not embedded and collapse_modindex %} + <script type="text/javascript"> + DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX = true; + </script> +{% endif %} +{% endblock %} +{% block body %} + + <h1 id="global-module-index">{{ _('Global Module Index') }}</h1> + + <div class="modindex-jumpbox"> + {%- for letter in letters %} + <a href="#cap-{{ letter }}"><strong>{{ letter }}</strong></a> {% if not loop.last %}| {% endif %} + {%- endfor %} + </div> + + <table class="modindextable"> + {%- for modname, collapse, cgroup, indent, fname, synops, pform, dep, stripped in modindexentries %} + {%- if not modname -%} + <tr class="pcap"><td></td><td> </td><td></td></tr> + <tr class="cap"><td></td><td><a name="cap-{{ fname }}"><strong>{{ fname }}</strong></a></td><td></td></tr> + {%- else -%} + <tr{% if indent %} class="cg-{{ cgroup }}"{% endif %}> + <td>{% if collapse -%} + <img src="{{ pathto('_static/minus.png', 1) }}" id="toggle-{{ cgroup }}" + class="toggler" style="display: none" alt="-" /> + {%- endif %}</td> + <td>{% if indent %} {% endif %} + {% if fname %}<a href="{{ fname }}">{% endif -%} + <tt class="xref">{{ stripped|e }}{{ modname|e }}</tt> + {%- if fname %}</a>{% endif %} + {%- if pform and pform[0] %} <em>({{ pform|join(', ') }})</em>{% endif -%} + </td><td>{% if dep %}<strong>{{ _('Deprecated')}}:</strong>{% endif %} + <em>{{ synops|e }}</em></td></tr> + {%- endif -%} + {% endfor %} + </table> + +{% endblock %} diff --git a/sphinx/themes/scrolls/opensearch.xml b/sphinx/themes/scrolls/opensearch.xml new file mode 100644 index 00000000..9f2fa427 --- /dev/null +++ b/sphinx/themes/scrolls/opensearch.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> + <ShortName>{{ project }}</ShortName> + <Description>Search {{ docstitle }}</Description> + <InputEncoding>utf-8</InputEncoding> + <Url type="text/html" method="get" + template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}&check_keywords=yes&area=default"/> + <LongName>{{ docstitle }}</LongName> +</OpenSearchDescription> diff --git a/sphinx/themes/scrolls/page.html b/sphinx/themes/scrolls/page.html new file mode 100644 index 00000000..ee6cad3d --- /dev/null +++ b/sphinx/themes/scrolls/page.html @@ -0,0 +1,4 @@ +{% extends 'layout.html' %} +{% block body %} + {{ body }} +{% endblock %} diff --git a/sphinx/themes/scrolls/search.html b/sphinx/themes/scrolls/search.html new file mode 100644 index 00000000..0c942b70 --- /dev/null +++ b/sphinx/themes/scrolls/search.html @@ -0,0 +1,35 @@ +{% extends "layout.html" %} +{% set title = 'Search' %} +{% block extrahead %} + <script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script> +{% endblock %} +{% block body %} + <h1 id="search-documentation">Search</h1> + <p> + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing less words won't appear in the result list. + </p> + <form action="" method="get"><p> + <input type="text" name="q" value=""> + <input type="submit" value="search"> + </p></form> + {% if search_performed %} + <h2>Search Results</h2> + {% if not search_results %} + <p>Your search did not match any results.</p> + {% endif %} + {% endif %} + <div id="search-results"> + {% if search_results %} + <ul> + {% for href, caption, context in search_results %} + <li><a href="{{ pathto(item.href) }}">{{ caption }}</a> + <div class="context">{{ context|e }}</div> + </li> + {% endfor %} + </ul> + {% endif %} + </div> +{% endblock %} diff --git a/sphinx/themes/scrolls/static/darkmetal.png b/sphinx/themes/scrolls/static/darkmetal.png Binary files differnew file mode 100644 index 00000000..e8c9ff62 --- /dev/null +++ b/sphinx/themes/scrolls/static/darkmetal.png diff --git a/sphinx/themes/scrolls/static/headerbg.png b/sphinx/themes/scrolls/static/headerbg.png Binary files differnew file mode 100644 index 00000000..0c5b3657 --- /dev/null +++ b/sphinx/themes/scrolls/static/headerbg.png diff --git a/sphinx/themes/scrolls/static/logo.png b/sphinx/themes/scrolls/static/logo.png Binary files differnew file mode 100644 index 00000000..d1961cf0 --- /dev/null +++ b/sphinx/themes/scrolls/static/logo.png diff --git a/sphinx/themes/scrolls/static/metal.png b/sphinx/themes/scrolls/static/metal.png Binary files differnew file mode 100644 index 00000000..97166f13 --- /dev/null +++ b/sphinx/themes/scrolls/static/metal.png diff --git a/sphinx/themes/scrolls/static/navigation.png b/sphinx/themes/scrolls/static/navigation.png Binary files differnew file mode 100644 index 00000000..1e248d4d --- /dev/null +++ b/sphinx/themes/scrolls/static/navigation.png diff --git a/sphinx/themes/scrolls/static/print.css b/sphinx/themes/scrolls/static/print.css new file mode 100644 index 00000000..fb633d87 --- /dev/null +++ b/sphinx/themes/scrolls/static/print.css @@ -0,0 +1,5 @@ +div.header, div.relnav, #toc { display: none; } +#contentwrapper { padding: 0; margin: 0; border: none; } +body { color: black; background-color: white; } +div.footer { border-top: 1px solid #888; color: #888; margin-top: 1cm; } +div.footer a { text-decoration: none; } diff --git a/sphinx/themes/scrolls/static/style.css_t b/sphinx/themes/scrolls/static/style.css_t new file mode 100644 index 00000000..0c346d04 --- /dev/null +++ b/sphinx/themes/scrolls/static/style.css_t @@ -0,0 +1,398 @@ +body { + background-color: #222; + margin: 0; + padding: 0; + font-family: 'Georgia', serif; + font-size: 15px; + color: #eee; +} + +div.footer { + border-top: 1px solid #111; + padding: 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.5px; +} + +div.footer a { + color: #eee; +} + +div.header { + margin: 0 -15px 0 -15px; + background: url(headerbg.png) repeat-x; + border-top: 6px solid {{ theme_headerbordercolor }}; +} + +div.relnav { + border-bottom: 1px solid #111; + background: url(navigation.png); + margin: 0 -15px 0 -15px; + padding: 2px 20px 0 28px; + line-height: 25px; + color: #aaa; + font-size: 12px; + text-align: center; +} + +div.relnav a { + color: #eee; + font-weight: bold; + text-decoration: none; +} + +div.relnav a:hover { + text-decoration: underline; +} + +#content { + background-color: white; + color: #111; + border-bottom: 1px solid black; + background: url(watermark.png) center 0; + padding: 0 15px 0 15px; + margin: 0; +} + +h1 { + margin: 0; + padding: 15px 0 0 0; +} + +h1.heading { + margin: 0; + padding: 0; + height: 80px; +} + +h1.heading:hover { + background: #222; +} + +h1.heading a { + background: url({{ logo if logo else 'logo.png' }}) no-repeat center 0; + display: block; + width: 100%; + height: 80px; +} + +h1.heading a:focus { + -moz-outline: none; + outline: none; +} + +h1.heading span { + display: none; +} + +#jinjalogo { + background-image: url(jinjalogo.png); + background-repeat: no-repeat; + width: 400px; + height: 160px; +} + +#contentwrapper { + max-width: 680px; + padding: 0 18px 20px 18px; + margin: 0 auto 0 auto; + border-right: 1px solid #eee; + border-left: 1px solid #eee; + background: url(watermark_blur.png) center -114px; +} + +#contentwrapper h2, +#contentwrapper h2 a { + color: #222; + font-size: 24px; + margin: 20px 0 0 0; +} + +#contentwrapper h3, +#contentwrapper h3 a { + color: {{ theme_subheadlinecolor }}; + font-size: 20px; + margin: 20px 0 0 0; +} + +table.docutils { + border-collapse: collapse; + border: 2px solid #aaa; + margin: 0.5em 1.5em 0.5em 1.5em; +} + +table.docutils td { + padding: 2px; + border: 1px solid #ddd; +} + +p, li, dd, dt, blockquote { + color: #333; +} + +blockquote { + margin: 10px 0 10px 20px; +} + +p { + line-height: 20px; + margin-bottom: 0; + margin-top: 10px; +} + +hr { + border-top: 1px solid #ccc; + border-bottom: 0; + border-right: 0; + border-left: 0; + margin-bottom: 10px; + margin-top: 20px; +} + +dl { + margin-left: 10px; +} + +li, dt { + margin-top: 5px; +} + +dt { + font-weight: bold; + color: #000; +} + +dd { + margin-top: 10px; + line-height: 20px; +} + +th { + text-align: left; + padding: 3px; + background-color: #f2f2f2; +} + +a { + color: {{ theme_linkcolor }}; +} + +a:hover { + color: {{ theme_visitedlinkcolor }}; +} + +pre { + background: #ededed url(metal.png); + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + padding: 5px; + font-size: 13px; + font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace; +} + +tt { + font-size: 13px; + font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace; + color: black; + padding: 1px 2px 1px 2px; + background-color: #fafafa; + border-bottom: 1px solid #eee; +} + +a.reference:hover tt { + border-bottom-color: #aaa; +} + +cite { + /* abusing <cite>, it's generated by ReST for `x` */ + font-size: 13px; + font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace; + font-weight: bold; + font-style: normal; +} + +div.admonition { + margin: 10px 0 10px 0; + padding: 10px; + border: 1px solid #ccc; +} + +div.admonition p.admonition-title { + background-color: {{ theme_admonitioncolor }}; + color: white; + margin: -10px -10px 10px -10px; + padding: 4px 10px 4px 10px; + font-weight: bold; + font-size: 15px; +} + +div.admonition p.admonition-title a { + color: white!important; +} + +a.headerlink { + color: #B4B4B4!important; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none!important; + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +a.headerlink:hover { + background-color: #B4B4B4; + color: #F0F0F0!important; +} + +table.indextable { + width: 100%; +} + +table.indextable td { + vertical-align: top; + width: 50%; +} + +table.indextable dl dd { + font-size: 11px; +} + +table.indextable dl dd a { + color: #000; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +table.modindextable { + width: 100%; + border: none; +} + +table.modindextable img.toggler { + margin-right: 10px; +} + +dl.function dt, +dl.class dt, +dl.exception dt, +dl.method dt, +dl.attribute dt { + font-weight: normal; +} + +dt .descname { + font-weight: bold; + margin-right: 4px; +} + +dt .descname, dt .descclassname { + padding: 0; + background: transparent; + border-bottom: 1px solid #111; +} + +dt .descclassname { + margin-left: 2px; +} + +dl dt big { + font-size: 100%; +} + +ul.search { + margin: 10px 0 0 30px; + padding: 0; +} + +ul.search li { + margin: 10px 0 0 0; + padding: 0; +} + +ul.search div.context { + font-size: 12px; + padding: 4px 0 0 20px; + color: #888; +} + +span.highlight { + background-color: #eee; + border: 1px solid #ccc; +} + +#toc { + margin: 0 -17px 0 -17px; + display: none; +} + +#toc h3 { + float: right; + margin: 5px 5px 0 0; + padding: 0; + font-size: 12px; + color: #777; +} + +#toc h3:hover { + color: #333; + cursor: pointer; +} + +.expandedtoc { + background: #222 url(darkmetal.png); + border-bottom: 1px solid #111; + outline-bottom: 1px solid #000; + padding: 5px; +} + +.expandedtoc h3 { + color: #aaa; + margin: 0!important; +} + +.expandedtoc h3:hover { + color: white!important; +} + +#tod h3:hover { + color: white; +} + +#toc a { + color: #ddd; + text-decoration: none; +} + +#toc a:hover { + color: white; + text-decoration: underline; +} + +#toc ul { + margin: 5px 0 12px 17px; + padding: 0 7px 0 7px; +} + +#toc ul ul { + margin-bottom: 0; +} + +#toc ul li { + margin: 2px 0 0 0; +} diff --git a/sphinx/themes/scrolls/static/theme_extras.js b/sphinx/themes/scrolls/static/theme_extras.js new file mode 100644 index 00000000..1c042187 --- /dev/null +++ b/sphinx/themes/scrolls/static/theme_extras.js @@ -0,0 +1,26 @@ +$(function() { + + var + toc = $('#toc').show(), + items = $('#toc > ul').hide(); + + $('#toc h3') + .click(function() { + if (items.is(':visible')) { + items.animate({ + height: 'hide', + opacity: 'hide' + }, 300, function() { + toc.removeClass('expandedtoc'); + }); + } + else { + items.animate({ + height: 'show', + opacity: 'show' + }, 400); + toc.addClass('expandedtoc'); + } + }); + +}); diff --git a/sphinx/themes/scrolls/static/watermark.png b/sphinx/themes/scrolls/static/watermark.png Binary files differnew file mode 100644 index 00000000..eb1b6be9 --- /dev/null +++ b/sphinx/themes/scrolls/static/watermark.png diff --git a/sphinx/themes/scrolls/static/watermark_blur.png b/sphinx/themes/scrolls/static/watermark_blur.png Binary files differnew file mode 100644 index 00000000..563f6cde --- /dev/null +++ b/sphinx/themes/scrolls/static/watermark_blur.png diff --git a/sphinx/themes/scrolls/theme.conf b/sphinx/themes/scrolls/theme.conf new file mode 100644 index 00000000..b4205046 --- /dev/null +++ b/sphinx/themes/scrolls/theme.conf @@ -0,0 +1,11 @@ +[theme] +inherit = default +stylesheet = scrolls.css +pygments_style = tango + +[options] +headerbordercolor = #1752b4 +subheadlinecolor = #0d306b +linkcolor = #1752b4 +visitedlinkcolor = #444 +admonitioncolor = #28437f diff --git a/sphinx/theming.py b/sphinx/theming.py index e5807029..217dd81c 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -78,7 +78,7 @@ class Theme(object): dirname = path.dirname(name) if not path.isdir(path.join(self.themedir, dirname)): os.makedirs(path.join(self.themedir, dirname)) - fp = open(path.join(self.themedir, name), 'w') + fp = open(path.join(self.themedir, name), 'wb') fp.write(tinfo.read(name)) fp.close() diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 50c5bd3f..87b08095 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -446,6 +446,23 @@ def split_explicit_title(text): return True, match.group(1), match.group(2) return False, text, text + +from docutils import nodes + +def make_refnode(builder, fromdocname, todocname, targetid, child, title=None): + """Shortcut to create a reference node.""" + node = nodes.reference('', '') + if fromdocname == todocname: + node['refid'] = targetid + else: + node['refuri'] = (builder.get_relative_uri(fromdocname, todocname) + + '#' + targetid) + if title: + node['reftitle'] = title + node.append(child) + return node + + # monkey-patch Node.traverse to get more speed # traverse() is called so many times during a build that it saves # on average 20-25% overall build time! @@ -475,8 +492,7 @@ def _new_traverse(self, condition=None, return self._old_traverse(condition, include_self, descend, siblings, ascend) -import docutils.nodes -docutils.nodes.Node._old_traverse = docutils.nodes.Node.traverse -docutils.nodes.Node._all_traverse = _all_traverse -docutils.nodes.Node._fast_traverse = _fast_traverse -docutils.nodes.Node.traverse = _new_traverse +nodes.Node._old_traverse = nodes.Node.traverse +nodes.Node._all_traverse = _all_traverse +nodes.Node._fast_traverse = _fast_traverse +nodes.Node.traverse = _new_traverse diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index ceca5c8a..9e7bb63d 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -47,7 +47,7 @@ STDINDENT = 3 class TextTranslator(nodes.NodeVisitor): - sectionchars = '*=-~"+' + sectionchars = '*=-~"+`' def __init__(self, document, builder): nodes.NodeVisitor.__init__(self, document) |
